Commit graph

27 commits

Author SHA1 Message Date
f39e7ccf39
test(intent): /trekplan must stop without an approved intent — RED
Veikart steg 1, økt 1 av 2. 18 tests, all failing today:
(a) a brief without an approval marker → the gate line in
commands/trekplan.md exits non-zero (today: no gate, planning proceeds);
(b) marker + ## Intent or ## Goal edited after approval → stale, stops;
(c) a valid marker passes (known negative), and edits outside the two
sections or whitespace-only reflow keep it valid;
(d) the stamp runs before the Phase 5 manual/auto fork and emits
brief-approved, so the manual (default) path records it too.

The gate and stamp lines are extracted from the command prose and
executed, so removing the line or stubbing the module fells the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 07:47:17 +02:00
21a96b9e31 fix(validators): hard-block the token formats the run-length patterns missed
Review finding 91e21c1f (MAJOR emitted, catalogue tier BLOCKER). Live in every
session regardless of the STORM flag.

The hard-block tier is the one thing no operator flag unlocks - not `strict`,
not `--soft`, not VOYAGE_QUERY_PRIVACY_ALLOW=1 - so a format it misses is a
secret leaving the machine in an outbound query with no second gate behind it.
Two patterns keyed on a run of consecutive alphanumerics, which a `-` or `_`
inside the token body breaks:

- /\bsk-[A-Za-z0-9]{20,}\b/ was commented "OpenAI/Anthropic-style" but the run
  ends after `api03` (3 chars) in an Anthropic Console key, so
  sk-ant-api03-<~95> passed through. Measured by execution, not read.
- /\bghp_[A-Za-z0-9]{36,}\b/ covered only the classic prefix: github_pat_<...>
  and gho_<36> passed through; ghp_<36> was blocked.

Widened with one pattern per real-world format rather than one loose pattern,
so each stays readable and its length floor stays honest:

- sk-ant-<scheme>-<20+ base64url>  (covers api03 and oat01)
- gh[pousr]_<36+>                  (classic PAT, OAuth, user, server, refresh)
- github_pat_<20+ incl. underscore> (fine-grained, real format is <22>_<59>)

Patterns whose body class includes `-`/`_` carry no trailing \b - it would not
fire on a non-word final character. The existing sk-/AKIA/xox/PEM patterns are
unchanged; the AWS comment is accurate as written, so it was left alone.

Formats verified against GitHub's token-format documentation and Anthropic key
anatomy before the patterns were written, not from memory:
- github.blog/engineering/platform-security/behind-githubs-new-authentication-token-formats/
- gh[pousr]_ + 36 chars; github_pat_ + <22>_<59> = 93 total
- sk-ant-api03- + ~95 base64url chars (base64url includes _ and -)

6 new tests: three table rows for the missed formats, and three that pin each
one blocked with `strict: false` AND the opt-in env var set at once - the
property that makes this tier meaningful.

Suite 952 (950/0/2, baseline 937 + 15 across both Track A fixes).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013zNqxP8qTWgJhn3wMYUFEh
2026-08-12 22:03:43 +02:00
0a569eec55 feat(validators): add outbound query privacy gate for research egress 2026-08-09 14:26:17 +02:00
84fbee2313 feat(profiles): add built-in fable profile (all six phases on fable) 2026-07-02 16:59:26 +02:00
8b7a849a76 test(validators): cover fable accept + unknown-model reject in both gate layers 2026-07-02 16:56:26 +02:00
357e17b176 feat(validators): add fable to BASE_ALLOWED_MODELS with accept/reject coverage 2026-07-02 16:54:08 +02:00
926b768543 fix(validators): brief-validator CLI no-flag invocation bailed to Usage
The documented `brief-validator.mjs <brief.md>` invocation (no flags) always
bailed to Usage/exit 2. Root cause: when --min-version is absent, minIdx is -1,
so the skip index minIdx+1 was 0 — excluding argv index 0, exactly where the
file positional sits in the no-flag case. Any leading flag (--soft, --json)
pushed the file to index >=1 and masked the bug, so the function-level tests
never caught it.

Guard the skip index to -1 when --min-version is absent. Add two CLI regression
tests (execFileSync, matching the next-session-prompt-validator pattern):
no-flag invocation reaches validation, and --min-version still skips its value
token to find the file. Suite 822 -> 824 (822/0/2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1krHamUehZh6JqVqs85t
2026-06-30 09:48:28 +02:00
844492fbcf test(eval): two-sided gate coverage for BRIEF_* BLOCKERs 2026-06-26 11:57:10 +02:00
e986b10431 feat(voyage): validate iterations_remaining in progress-validator
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:26:22 +02:00
213cf388de chore(voyage): S34 — V30 economy-profile self-declares experimental (uncalibrated Jaccard floor)
The economy profile's cross-tier Jaccard floor (0.55) rests on parked-synthetic
fixtures; empirical Step-17 calibration is v4.2-budget-gated ($60–120,
unauthorized). Fork resolved as label-not-calibrate: the experimental status,
previously prose-only in docs/profiles.md, now lives in the profile data and is
machine-checked. No new user-facing capability — honest labeling + a guard.

- lib/profiles/economy.yaml: add `experimental: true` (with rationale comment).
- lib/validators/profile-validator.mjs: recognize `experimental` as an OPTIONAL
  boolean; non-boolean → PROFILE_INVALID_ENUM. Absent ⇒ tier is stable
  (premium/balanced unaffected, profile_version stays 1.0 — additive).
- README.md + docs/operations.md + docs/profiles.md: flag the `economy` table
  row "⚠ Experimental (uncalibrated Jaccard floor)".
- tests/synthetic/profile-jaccard-calibration.md + analysis §6/§10 + backlog
  plan §S34: cross-reference the marker; mark V30/S34 done.

+5 tests (739 → 744, 742/2/0): economy declares experimental:true; premium and
balanced do not; validator rejects non-boolean experimental; every profile-doc
economy row is flagged; the flag tracks the calibration's parked-synthetic
status (must drop in the same change that lands real calibration).

Closes the balance backlog (4/4, S31–S34). claude plugin validate green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-20 10:18:38 +02:00
7cfce2b996 fix(voyage): S26 — parse plan_version prose form (S22 defect #2/#3)
The plan template (templates/plan-template.md:21) emits plan_version ONLY in
the prose blockquote metadata line:

  > Generated by trekplan v{version} on {YYYY-MM-DD} — `plan_version: 1.7`

It carries no frontmatter plan_version (the frontmatter block is trekreview-only
and holds source_findings). But PLAN_VERSION_REGEX in lib/parsers/plan-schema.mjs
was `^`-anchored (/m), matching ONLY line-start (frontmatter). The backtick-
wrapped prose form never matched → extractPlanVersion returned null → every real
generated plan got a spurious PLAN_NO_VERSION warning from plan-validator.

Not caught earlier because no test ran the parser against the actual template;
the synthetic fixtures all carry frontmatter plan_version and parse fine.

Internal source contradiction surfaced: the parser comment documents intent
"frontmatter OR doc body", planning-orchestrator.md:228 + the template place it
in the prose line, while HANDOVER-CONTRACTS.md calls it a frontmatter field.

Operator-chosen fix (parser, not template): relax the regex to
`/(?:^|`)plan_version:.../m` so it matches line-start (frontmatter) OR the
backtick-prefixed prose form. Honors the parser's own documented contract,
fixes all existing + future plans, changes no plan output, touches one code
file — vs the template-fix which would alter every plan's shape, contradict
planning-orchestrator.md, and force a 3-file doc reconciliation (scope creep).

TDD (red first): added prose-form + canonical-template regression pins in
plan-schema.test.mjs and a no-PLAN_NO_VERSION pin in plan-validator.test.mjs;
all 3 red on the `^`-anchored regex, green after the relax. The template pin
ties the parser directly to the real generated artifact.

S22 defect closed in docs/S22-happy-path-dogfood.md (§Pipeline defects + log).

Tests: 728 (726 pass / 2 skip / 0 fail; live `node --test`, = 725 baseline +3).
plugin validate passes (1 accepted CLAUDE.md-at-root warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 21:59:31 +02:00
987e847ea1 feat(voyage): S18 — framing-hardening (min-version gate + memory status + pre-2.2 doc + flagship hedge)
Closes devils-advocate audit #4–#6 (MAJOR×MED). Four additive, non-breaking
changes to the v5.5 framing-alignment machinery:

1. --min-brief-version <ver> gate (audit #4). Opt-in version floor on
   /trekplan + /trekresearch, forwarded to brief-validator as --min-version.
   New opts.minBriefVersion warns BRIEF_VERSION_BELOW_MINIMUM (never blocks)
   when a brief declares a version below the floor; trekreview exempt; absent
   opt = no check. CLI shim parses --min-version and skips its value token in
   filePath detection.

2. memory_alignment.status field (audit #5). brief-reviewer now emits
   status: verified | n_a | contradictions so a score-5 N/A (no memory) is
   distinguishable from a score-5 verified-aligned brief — the score≥4 gate
   passes in both, status reveals whether the wrong-premise defense ran.

3. Document pre-2.2 = zero framing enforcement (audit #4). HANDOVER-CONTRACTS
   §Handover 1 now states the producer-elective hole + two remedies. Also
   fixes a stale "current is 2.1" line (current is 2.2).

4. Soften flagship overselling (audit #6). CLAUDE.md Context-Engineering
   principle now hedges that main-context relief is asserted-by-design, not
   measured (T1 PoC found Δ≈0); README carried no false claim to fix.

TDD: 8 new tests written failing-first (5 validator, 1 trekbrief status pin,
2 doc-consistency cross-file pins). Suite 691→699 (697 pass / 2 skip / 0 fail).
No flagship prose-pin added (deliberate, per S19 anti-bloat).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 13:33:00 +02:00
736ae55d66 feat(voyage): S6 — v5.5 brief framing enforcement (brief_version 2.2)
Implements the CLAUDE.md cross-cutting invariant "brief framing must match
operator intent" as a controlled brief_version 2.1->2.2 bump (operator option A1).
Three defense layers, version-gated at >=2.2 so existing 2.0/2.1 briefs stay
valid (forward + backward compatible), mirroring the phase_signals >=2.1 gate:

- L1 framing: enum field (preserve|refine|replace|new-direction). Enum-checked
  on any version when present (BRIEF_INVALID_FRAMING); missing at >=2.2 ->
  BRIEF_MISSING_FRAMING. /trekbrief Phase 2.5 collects it BEFORE any brief prose
  (non-skippable, even in --quick).
- L2 memory alignment: new brief-reviewer dimension 6 comparing brief Intent/Goal
  + framing against operator memory for explicit contradictions; degrades to
  score 5 (N/A) when no memory context is supplied. Wired into Phase 4e gate
  (memory_alignment.score >= 4).
- L3 obligatory ## TL;DR (<=5 content lines) at >=2.2; soft cap ->
  BRIEF_TLDR_TOO_LONG warning.

trekreview briefs are exempt from the framing/TL;DR gate. Handover 1 PUBLIC
CONTRACT doc, README "What's new", and the CLAUDE.md invariant + agents table
(brief-reviewer 5->6 dimensions) updated to 2.2 (schema axis only; plugin
version badge + CHANGELOG remain S10).

Iron Law followed: validator tests red->green first. Tests 586 -> 606
(+20, 604 pass / 2 skip). claude plugin validate passes (pre-existing
CLAUDE.md root-context warning unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 13:09:50 +02:00
681f682abc fix(voyage): coerce brief_version to string + quote template + update doc pin (closes #8 #11)
v5.1.0 shipped with an unquoted brief_version: 2.1 in trekbrief-template.md.
parseScalar coerced it to Number 2.1, and the sequencing gate guarded on
typeof === 'string', silently bypassing BRIEF_V51_MISSING_SIGNALS.

Three-part atomic fix:
- brief-validator.mjs:87+149 now accepts both string and number forms via
  String(fm.brief_version) coercion.
- trekbrief-template.md quotes the value so new briefs parse as String.
- doc-consistency.test.mjs pins the QUOTED form going forward.

Three regression tests added in brief-validator.test.mjs.
2026-05-14 21:36:10 +02:00
efeba4d2cf feat(voyage): add phase_signals validation + sequencing gate to brief-validator (v5.1) 2026-05-13 21:08:37 +02:00
3683ae0070 chore(voyage): release v5.0.0 — remove bespoke playground + /trekrevise + Handover 8; render produced artifacts to HTML + link, annotate via /playground
The v4.2/v4.3 bespoke playground SPA (~388 KB), the /trekrevise command,
Handover 8 (annotation → revision), the supporting lib/ modules
(anchor-parser, annotation-digest, markdown-write, revision-guard), the
Playwright e2e suite, and the @playwright/test / @axe-core/playwright
devDeps are removed. A browser walkthrough found the playground borderline
unusable, and it duplicated the official /playground plugin's
document-critique / diff-review templates.

In their place: scripts/render-artifact.mjs — a small, zero-dependency
renderer that turns a brief/plan/review .md into a self-contained,
design-system-styled, zero-network .html (frontmatter folded into a
<details> block). /trekbrief, /trekplan, and /trekreview call it on their
last step and print the file:// link; to annotate, run /playground
(document-critique) on the .md and paste the generated prompt back.

Resolves the v4.3.1-deferred findings as moot (their target files are
deleted). npm test green: 509 tests, 507 pass, 0 fail, 2 skipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 14:05:07 +02:00
64e3861a12 test(voyage): pin forward-compat for revision/source_annotations/annotation_digest/revision_reason — v4.2 Step 2
3 new test files, 24 cases (8 per validator):
- baseline (no annotation fields) still valid
- revision: 0 / revision: 5 accepted
- source_annotations list-of-dict accepted
- annotation_digest string accepted
- revision_reason accepted
- all 4 fields together accepted
- unrecognized future field tolerated (forward-compat policy)

Pin against future strict-key refactors. No production code change — pure regression pin.
2026-05-09 12:50:22 +02:00
a1f256d000 feat(voyage): emit MANIFEST_PROFILE_DRIFT warning in plan-validator strict mode — brief assumption 7
Step 20 of v4.1 — implements drift detection in plan-validator.mjs per
brief Assumptions block 7: "Mismatch (e.g. korrupt manuell endring)
emitterer MANIFEST_PROFILE_DRIFT-warning fra plan-validator i --strict-modus."

Logic (after validateAllManifests in validatePlanContent):
  1. Strict-mode only — soft mode never emits drift warnings.
  2. Plan frontmatter must declare 'profile: <name>' to establish baseline.
  3. For each step manifest, if profile_used is set AND differs from plan
     profile, emit warning (NOT error) with code MANIFEST_PROFILE_DRIFT
     and location 'step N: profile_used = X, plan profile = Y'.

Forward-compat preserved: drift is a warning, plan remains valid:true.
Operators see the drift in --strict mode without parsing breaking.

New files:
  tests/validators/plan-validator-profile-drift.test.mjs — 4 tests
  tests/fixtures/plan-profile-drift.md                   — drift fixture

Tests verify:
  1. drift detected in strict mode → MANIFEST_PROFILE_DRIFT in warnings
  2. drift NOT detected in soft mode → strict gate honored
  3. matching profile → no drift warning
  4. no plan-level profile → drift detection silent (no baseline)

Tests: 479 pass + 2 skipped (Docker not installed).
2026-05-09 10:02:53 +02:00
b56ba13b04 feat(voyage): add lib/validators/profile-validator.mjs — SC #1, #2, #3
Step 5 av v4.1-execute (Wave 2, Session 2).

Profile-validator etter brief-validator-mønsteret eksakt: validateProfileContent
(pure), validateProfile (file-reader), CLI shim med --json flag. Eksporter
PROFILE_REQUIRED_FIELDS (frozen), PROFILE_REQUIRED_PHASES (frozen).

Validerer:
- Required frontmatter fields (name, phase_models, parallel_agents_min/max,
  external_research_enabled, brief_reviewer_iter_cap)
- phase_models = list-of-dicts med phase + model
- 6 required phases (brief, research, plan, execute, review, continue)
- parallel_agents_max ≥ parallel_agents_min
- Allowed model values: ['sonnet', 'opus']; haiku tillatt KUN ved
  VOYAGE_ALLOW_HAIKU=1 (per global CLAUDE.md modellvalg-prinsipp)

Issue codes: PROFILE_MISSING_FIELD, PROFILE_INVALID_MODEL, PROFILE_INVALID_ENUM,
PROFILE_READ_ERROR, PROFILE_NOT_FOUND.

Field-path-reporting i error-location: phase_models[N].model for SC #2.

Tester (10 nye, baseline 377 → 387):
- SC #1 x3 (innebygde profiler grønne)
- SC #2 (PROFILE_INVALID_MODEL med location phase_models[2].model)
- SC #3 (PROFILE_INVALID_ENUM for external_research_enabled: "yes" string)
- VOYAGE_ALLOW_HAIKU env-var deny/allow
- PROFILE_MISSING_FIELD når name fraværende
- PROFILE_NOT_FOUND for ikke-eksisterende fil
- 2 export drift-pins

Fixturer: profile-invalid-model.yaml (gpt-4 i phase_models[2]),
profile-invalid-enum.yaml (external_research_enabled som string "yes").

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:26:23 +02:00
c909466c99 feat(voyage)!: bulk content rewrite ultra -> voyage/trek prose [skip-docs]
Sed-pipeline (16 patterns, longest-match-first) sweeper residuelle ultra*-treff
i prose, command-narrativ, agent-prompts, hook-kommentarer, doc-prosa.

Pipeline-utvidelser fra V4-prompten:
- BSD-syntax [[:<:]]ultra[[:>:]] istedenfor \bultra\b (BSD sed mangler \b)
- 6 compound-patterns for ultraplan/ultraexecute/ultraresearch/ultrabrief/
  ultrareview/ultracontinue uten -local-suffiks
- ultra*-stats glob -> trek*-stats glob
- Linje-eksklusjon redusert til ultra-cc-architect (Q8); session-state-
  eksklusjonen var over-protektiv
- File-eksklusjon utvidet til settings.json, package.json, plugin.json,
  hele .claude/-treet (gitignored + V5-territorium)

Q8-undantak holdt: architecture-discovery.mjs + project-discovery.mjs urort.
Filnavn-konvensjon holdt: .session-state.local.json + *.local.* preservert.

Manuell narrative-fix: tests/lib/agent-frontmatter.test.mjs linje 10
mangled "/ultra*-local" til "/voyage*-local" (ingen slik kommando finnes);
korrigert til "/trek*".

Residualer utenfor scope (V5 handterer): package.json + .claude-plugin/
plugin.json (Step 12-14 versjons-bump). .claude/* er gitignored
spec-historikk med tilsiktet BEFORE/AFTER-narrativ.

Part of voyage-rebrand session 3 (Wave 4 / Step 10).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 15:08:20 +02:00
acc053ae6d feat(voyage)!: rename produced_by field values + validator comments [skip-docs]
- commands/trekexecute.md: produced_by literals -> trekexecute (4 occurrences)
- commands/trekendsession.md: produced_by literals -> trekendsession (2 occurrences)
- tests/validators/next-session-prompt-validator.test.mjs: 11 'ultraexecute-local' refs -> 'trekexecute'
- tests/commands/trekcontinue.test.mjs: 3 fixture strings updated
- tests/lib/cleanup.test.mjs: 1 fixture string updated
- lib/validators/next-session-prompt-validator.mjs: producer-list comment
- docs/HANDOVER-CONTRACTS.md line 432: example producer names updated

Part of voyage-rebrand session 2 (W3.4 / Step 6).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:42:21 +02:00
12f4391dca feat(voyage)!: rename type discriminators across validators + fixtures [skip-docs]
- brief-validator: BRIEF_TYPE_VALUES ['ultrabrief','ultrareview'] -> ['trekbrief','trekreview'] + dependent branches
- research-validator: 'ultraresearch-brief' -> 'trekresearch-brief'
- review-validator: 'ultrareview' -> 'trekreview'
- 3 templates frontmatter type:
- 4 synthetic fixtures: ultraplan-synthetic/ultrareview-synthetic -> trek* (frontmatter only; bodies untouched, Jaccard floor preserved)
- 2 trekreview fixtures: type: trekreview
- 6 validator-test fixtures + asserts
- agents/review-coordinator.md frontmatter example

Atomic: validator + fixtures committed together — partial state would cause vacuous
test passes or hard validator rejection.

Part of voyage-rebrand session 2 (W3.3 / Step 5).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:40:25 +02:00
deb42f43e9 feat(ultraplan-local): next-session-prompt-validator (Bug 3 consistency check) [skip-docs]
Step 6 of v3.4.1 plan. Adds the validator quartet
(Content/Object/Consistency/CLI) for NEXT-SESSION-PROMPT.local.md
frontmatter (produced_by, produced_at). State-anchored staleness check
is the primary refusal; 24h wall-clock drift downgraded to soft warning
to avoid false positives on weekend pauses.

Internal scaffolding consumed by Step 8 (Phase 1.5 wire-up). User-facing
docs land with Step 14 (CHANGELOG + README + version bump).

Tests 335 -> 346 (+11): 9 unit + 2 CLI shim cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:34:16 +02:00
Kjell Tore Guttormsen
282dcea518 feat(ultraplan-local): add session-state-validator + tests for /ultracontinue
Validator at lib/validators/session-state-validator.mjs:
- validateSessionStateObject(parsed, opts) — pure object validation
- validateSessionStateContent(jsonText, opts) — wraps JSON parse + validation
- validateSessionState(filePath, opts) — file-mode with existsSync guard
- CLI shim with --json output (errors→stderr, result→stdout, exit 0/1/2)
- Schema v1: schema_version, project, next_session_brief_path,
  next_session_label, status, updated_at
- Error codes: SESSION_STATE_PARSE_ERROR, SESSION_STATE_NOT_FOUND,
  SESSION_STATE_MISSING_FIELD, SESSION_STATE_INVALID_STATUS,
  SESSION_STATE_NOT_RESUMABLE (warning), SESSION_STATE_SCHEMA_MISMATCH,
  SESSION_STATE_INVALID_TIMESTAMP, SESSION_STATE_INVALID_PATH
- Forward-compat hard requirement: unknown top-level keys ignored —
  protects future graceful-handoff v2.2 dual-writes

Tests at tests/validators/session-state-validator.test.mjs — 15 subtests:
- happy path + 5 missing-field tests
- invalid status, completed warns NOT_RESUMABLE, schema mismatch, bad
  timestamp, malformed JSON, missing file
- fixture load (SC-1) + malformed fixture (SC-3)
- forward-compat: unknown keys ignored silently

167 → 182 tests, 0 fail.

Step 4 of /ultracontinue v3.3.0. Closes Session 1 of the execution
strategy (foundation: gitignore + util + fixtures + validator+tests).
2026-05-01 20:23:09 +02:00
Kjell Tore Guttormsen
7fee5b4490 feat(ultraplan-local): extend brief-validator to accept type:ultrareview 2026-05-01 13:31:39 +02:00
Kjell Tore Guttormsen
021f87f89a feat(ultraplan-local): add lib/validators/review-validator.mjs 2026-05-01 13:30:43 +02:00
Kjell Tore Guttormsen
f68cd950dd feat(ultraplan-local): Spor 1 wave 2 — 5 validators + doc-consistency, 108 tests grønn [skip-docs]
5 nye validator-moduler (alle m/ CLI-shim for invokering fra commands):
- brief-validator.mjs — frontmatter (type, brief_version, task, slug, research_topics, research_status), state machine (research_topics > 0 + skipped requires brief_quality: partial), body sections (Intent/Goal/Success Criteria)
- research-validator.mjs — type=ultraresearch-brief, confidence ∈ [0,1], dimensions ≥ 1, body sections, --dir mode for batch validering
- plan-validator.mjs — wrapper over plan-schema + manifest-yaml; håndhever step-count == manifest-count, plan_version=1.7
- progress-validator.mjs — schema_version, status enum, current_step in range, step shape, checkResumeReadiness
- architecture-discovery.mjs — EKSTERN KONTRAKT: drift-WARN ikke drift-FAIL; tolererer non-canonical filnavn, surfacer loose files som warnings

Doc-consistency-test pinning prose vs source-of-truth:
- agents/*.md count == CLAUDE.md agent-tabell rader
- commands/*.md mentioned i CLAUDE.md
- command frontmatter.name == filnavn
- templates/plan-template.md plan_version 1.7 invariant
- settings.json kun kjente scopes (ultraplan, ultraresearch)
- settings.json ingen exploration eller agentTeam (vestigial guard etter Spor 0)
- CLAUDE.md refererer alle 4 pipeline-commands

Wave 1 + Wave 2 = 108 tester grønn.

[skip-docs]: Test-infrastrukturen er ikke user-facing før Spor 1 wiring lander; README/CLAUDE.md oppdateres når commands faktisk endrer atferd (neste commit).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 05:39:47 +02:00