Commit graph

174 commits

Author SHA1 Message Date
581489a513 test(trekresearch): pin deep-research adapter output contract 2026-06-30 13:38:09 +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
440594f1b2 feat(eval): SKAL-1·4b offline gold-scored output eval
Scores committed agent-run fixtures against the golden corpus at
(file, rule_key) granularity, building on the deterministic coordinator
contract (4a). Offline: committed reviewer payloads, no live agent spawn,
no LLM, no network (the LLM-in-the-loop grading is the separate 4c tier).

- lib/review/gold-scorer.mjs: scoreFindings (precision/recall/f1 at
  (file,rule_key) granularity, line+severity ignored) + scoreVerdict; pure,
  with documented vacuous-set conventions.
- tests/fixtures/bakeoff-rich/runs/run-perfect.json: committed run that
  reproduces all 5 seeded gold findings through runContract.
- tests/lib/gold-eval.test.mjs: the scoring RUN (precision/recall/f1 = 1.0,
  verdict == expected_verdict BLOCK, nothing suppressed/skipped).
- lib/util/test-census.mjs: third census category (goldEval) — a scoring run
  is neither behavior coverage nor a doc-pin; honest-count invariant now 3-way.
- docs/eval-corpus/README.md: 4b moved from Future hardening to implemented.

Suite 809 -> 822 (820/0/2). gold-scorer covers TP+FP+FN+degenerate paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJQYC5vpkJWxndS55vQQZ6
2026-06-30 09:00:33 +02:00
4bda2621eb test(agents): pin examples-in-body invariant (RED before M4 relocation) 2026-06-29 10:11:53 +02:00
68c9bef38f test(observability): close 2 MAJOR test gaps from SKAL-2 review
F1 cache-analyzer regression guard (SC5): pin percentile (wall_time_ms_p50/p90)
and time-range (oldest/newest_event_iso) — 2 of 3 'unchanged' categories were
previously un-asserted on the mixed-input fixture.

F2 lastMainChainModel: add direct coverage — last-wins across 2 distinct
main-chain models, sidechain exclusion (even when the sidechain is the last
record), and model-absent → null propagating to deriveCost refuse-to-estimate.

804 -> 807 tests (805 pass / 0 fail / 2 skipped). No test pins the test count.
2026-06-26 17:14:03 +02:00
7e78d076f9 docs(observability): document token-usage schema + main-context v1 scope 2026-06-26 14:47:24 +02:00
46d51f8088 feat(observability): opt-in token capture in Stop hook (VOYAGE_TOKEN_METER) 2026-06-26 14:42:58 +02:00
62ebc28e3f feat(stats): aggregate token/cost totals in cache-analyzer 2026-06-26 14:38:16 +02:00
a9c442c201 feat(exporters): allowlist token-usage schema + assert metric export (CWE-212) 2026-06-26 14:36:17 +02:00
708ba04571 feat(stats): add pure token-usage parser + cache-aware cost derivation 2026-06-26 14:32:10 +02:00
844492fbcf test(eval): two-sided gate coverage for BRIEF_* BLOCKERs 2026-06-26 11:57:10 +02:00
971604d870 feat(eval): add review-coordinator contract reference impl + deterministic test 2026-06-26 11:54:48 +02:00
e374a7c0ff feat(eval): add gold.json golden corpus + loader/validator test 2026-06-26 11:51:46 +02:00
fd0e5775eb docs(voyage): harmonize fan-out hedge + add banned-phrase guard
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:35:40 +02:00
65a51b2667 feat(voyage): surface iterations_remaining signal in trekexecute
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:33:21 +02:00
e34082d79a feat(voyage): document recovery/retry iteration caps in trekexecute
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:31:07 +02:00
d2f9ccb690 feat(voyage): add machine-verifiable completion gate to trekexecute
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:29:05 +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
2df0cbb372 docs(voyage): S33 — reconcile agent inventory (21 spawnable + 3 reference docs) + record D1–D3 considered-and-kept
Balance-backlog S33 (DOC, non-breaking). The D1–D3 forks resolved conservatively
(balance-backlog-plan.md), collapsing the model + observability work into a
documentation record. Three deliverables, all doc-only, no code/frontmatter change:

- V35 (doc half): the "24 agents" headline is reconciled to its honest split —
  21 spawnable (one dormant: synthesis-agent, Δ≈0) + 3 orchestrator reference
  docs (planning-/research-/review-orchestrator document the inline /trek*
  workflow; not spawned). Each orchestrator header now declares itself a
  "reference document, not a spawnable capability". README + CLAUDE.md state the
  split; counts in the new pins are DERIVED from agents/ so they survive reword.
- D2 (V32 rationale): docs/observability.md gains a "Why direct export rather
  than a native collector" section — direct export keeps the path / SSRF /
  field-allowlist guards in audited in-process code (the S21 hardening) instead
  of re-hosting a collector; textfile mode remains the collector escape hatch.
- D3 (kept-opus): docs/voyage-vs-cc-balance-analysis.md §10 decision record —
  opus on V09 (glue), V35 (dormant), V11 (retrieval), V16 (mechanical), V08
  (researchers) was reconsidered for sonnet and KEPT (pin 40d8742 firm).

No agent frontmatter changed — tests/lib/agent-frontmatter.test.mjs is the
structural model source-of-truth and is untouched (diff is description-only:
model: opus + tools lists unchanged, no Agent tool granted). No Handover-1
change; no exporter/gemini-bridge removal. Non-breaking, no version bump.

tests/lib/doc-consistency.test.mjs: +5 S33 pins (inventory split derived from
agents/; synthesis-agent dormant; orchestrator relabel; observability D2
rationale; analysis-doc D1–D3 record). Tests 739 (737 pass / 2 skip / 0 fail),
bar `node --test`; `claude plugin validate` green (1 accepted warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-20 09:49:11 +02:00
2849157ba2 docs(voyage): S32 — audit V01/V07/V08/V11/V24 native-delegation; document "delegate the engine, keep the policy"
Balance-backlog S32 (CODE+AUDIT). Audited whether the brief interview and the
research / exploration / reviewer swarms ride NATIVE Claude Code primitives or
hand-roll their own engine. Finding: all five ALREADY delegate natively — no
re-implementation, so no command-file change. Documented the principle + a
standing regression guard instead.

- V01 (trekbrief Phase 3): Q&A turn-taking is `AskUserQuestion` (line 144 / step
  4); the "selection rule" is section-selection POLICY, not a hand-rolled menu.
- V07 (research interview): `AskUserQuestion`, one-at-a-time.
- V08/V11/V24 (research / exploration / reviewer swarms): parallel `Agent`
  fan-out in a single message ("in parallel … single message" / "via the Agent
  tool — one message, multiple tool calls"). Policy layers (dimensions/schemas/
  triangulation, typed roles/effort/scaling, 12-key rule catalogue/no-cross-feed/
  dedup) cleanly separated from the engine.

- docs/architecture.md: new cross-cutting principle note "delegate the engine,
  keep the policy" recording the native primitives, the per-command policy, and
  the audit verdict.
- tests/lib/doc-consistency.test.mjs: +3 S32 pins (architecture note present;
  each swarm command lists Agent + mandates single-message parallel spawn;
  trekbrief Phase 3 delegates to AskUserQuestion). Guards engine creep-back.

No command-file edits (all native). No model/frontmatter change (D3 firm). No
Handover-1 change. Non-breaking. Tests 734 (732 pass / 2 skip / 0 fail), bar
`node --test`; `claude plugin validate` green (1 accepted warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-20 09:36:06 +02:00
9dc50a2047 refactor(voyage): S31 — V15 trim plan-export to headless-only (decompose alias)
Drop the pr/issue/markdown variants from `/trekplan --export`. Claude Code
reformats a plan into a PR body, issue comment, or stripped markdown ad-hoc
on request, so a dedicated export path added maintenance without value.
Keep `--export headless` as a backwards-compatible alias for `--decompose`
and relabel it as the decomposition entry it actually is.

- commands/trekplan.md: Phase 1 parse rejects non-headless formats and sets
  mode = decompose for headless; delete the Export phase; rename Phase 1.6 →
  Phase 1.5 (Decompose); update the mode enum, argument-hint, and usage block.
- docs/command-modes.md, README.md: export row relabeled as a --decompose alias.
- tests/commands/trekplan.test.mjs: +2 V15 pins (variants gone, headless kept).

Non-breaking (plan D-register). Tests 731 (729 pass / 2 skip / 0 fail), bar
`node --test`; `claude plugin validate` green (1 accepted warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-20 09:23:21 +02:00
8485ea1d36 docs(voyage): S28 — locate plan_version in plan header line, not frontmatter
HANDOVER-CONTRACTS.md was the lone source that called plan_version a
frontmatter field. The plan template (templates/plan-template.md:21) emits it
ONLY in the prose "Generated by" header line; brief-generated plans carry no
frontmatter at all (the sole frontmatter block, source_findings, is
trekreview-only and additive). planning-orchestrator.md:228 ("metadata line
below the title"), the parser (lib/parsers/plan-schema.mjs, S26), and the
plan-schema.test.mjs comment all already say prose. The contract was the
outlier — the deferred doc-side closure the S26 commit named as scope to avoid
then ("a 3-file doc reconciliation").

Operator-chosen direction (Option A + A1): correct the contract to the
artifact, doc-only — NOT move the field to frontmatter (which would alter every
plan's shape and fight the trekreview-only frontmatter design). A1 keeps the
standardized "Frontmatter schema" heading, corrects the row, and notes the real
(optional, trekreview-only) source_findings frontmatter.

Three surgical spots in HANDOVER-CONTRACTS.md:
- versioning table: `plan_version` (frontmatter) → (plan header line)
- Handover 4 "Frontmatter schema": no-required-frontmatter note + Location
  column locating plan_version in the "Generated by" header line + parser ref
- Handover 5 progress.json: "Mirrors plan's frontmatter" → "Mirrors the plan
  header's plan_version"

TDD (red first): new doc-consistency pin asserts the contract no longer labels
plan_version a (frontmatter) field, drops "Mirrors plan's frontmatter", and
positively locates it in the plan header line. Red on the old wording (L15 +
L264), green after the edits.

Scope: only HANDOVER-CONTRACTS.md + the one pin. Template/orchestrator/parser/
examples untouched (already correct). Example-01's bare-line emission drift is
noted out-of-scope for a possible later item.

Tests: 729 (727 pass / 2 skip / 0 fail; live `node --test`, = 728 baseline +1).
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 22:26:02 +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
fe97f6172c docs(voyage): S24 — autonomy-gate truth-pass + guard pin (S21b doc/code drift)
operations.md:15 + command-modes.md described an autonomy surface that does
not exist in code. Truth-pass against lib/util/autonomy-gate.mjs (the source
of truth) closes three false claims found while auditing the autonomy surface
in S21 (devils-advocate-results.md S21b forward-pointer):

  F1 (MAJOR) — fabricated state machine. operations.md claimed
      `idle → approved → executing → merge-pending → main-merged`; only `idle`
      exists. Real states: idle → gates_on|auto_running → paused_for_gate →
      completed (events: start/phase_boundary/resume/finish).
  F2 (MINOR) — event-emit.mjs does NOT "record each transition"; it emits 3
      named lifecycle events (brief-approved, main-merge-gate, user_input) and
      is decoupled from the pure, no-I/O autonomy-gate.
  F3 — `--gates {open|closed|adaptive}` is false: the CLI shim + all 4 command
      docs take a BOOLEAN `--gates {true|false}`. open/closed/adaptive is a
      DERIVED gates_mode policy, /trekexecute-only, mapped from the brief effort
      signal (low→open, standard→adaptive, high→closed; trekexecute.md:1562/74/75).

Operator-chosen fix (S24): boolean-true representation + a gates_mode policy
note, applied to BOTH operations.md and command-modes.md (4 rows) — same
false-claim class, fixed in one pass (fix-errors-found-in-scope).

TDD: doc-pin in doc-consistency.test.mjs imports STATES from autonomy-gate.mjs,
forbids the fabricated names + the flag-enum, requires the real states. Red
first (failed on "merge-pending"), green after the truth-pass.

Tests: 725 (723 pass / 2 skip / 0 fail). 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:36:15 +02:00
b4edc12bec fix(voyage): S23 — make /trekplan Phase 9 dedup executable (defect #1)
Phase 9's dedup hand-off was broken on two layers, both surfaced by the S22
dogfood: (a) plan-critic + scope-guardian (Read/Glob/Grep, no Write) were told
to write /tmp/*-out.json the dedup helper reads — they cannot; (b) even with
Write, their Output format emits markdown, not the helper's
{agent,findings:[{file,line,rule_key,text}]} schema. readJsonOrNull then
swallowed the absent files -> a silent empty merge that discarded every finding.

Fix (operator-chosen A'): keep the reviewers read-only; make the hand-off run.
- plan-review-dedup.mjs gains a --stdin mode reading {plan_critic,scope_guardian};
  malformed stdin exits non-zero so a broken hand-off surfaces loudly instead of
  collapsing into a silent empty merge. File mode + its tests are untouched.
- plan-critic.md + scope-guardian.md now emit a trailing machine-readable `json`
  findings block (the inline hand-off; no Write tool needed).
- trekplan.md + planning-orchestrator.md Phase 9 rewritten in lockstep: extract
  both blocks, pipe via heredoc into --stdin. No temp files, portable, no
  pathguard dependency.

TDD: malformed-stdin test failed first (CLI ignored stdin -> exit 0 = the bug),
green after impl. New S23 doc-pin asserts both docs use --stdin (not the dead
/tmp paths) and both agents declare the json block. Suite 724 (722/2/0); live
HEAD baseline was 720, not the stale 705 STATE carried forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 21:12:36 +02:00
b208e4ee04 fix(voyage): S21 — close IPv4-mapped IPv6 SSRF bypass + security/safety audit (blind spot #2)
S21 = devil's-advocate blind spot #2 (security/safety), operator scope
"security-core": fix genuine defects, honestly record the rest.

SSRF fix (CWE-918). validateOtlpEndpoint classified the host by literal
string match. Decimal/hex/octal/trailing-dot encodings are already caught
(the WHATWG URL parser canonicalizes them), but IPv4-mapped IPv6 literals
(::ffff:127.0.0.1, ::ffff:192.168.x, ::ffff:169.254.169.254) render as
::ffff:HHHH:HHHH and matched neither the loopback set, the RFC-1918 regex,
link-local, nor HARD_BLOCKED_HOSTS — they passed over https and would reach
loopback / private / cloud-metadata, defeating the comment's "PERMANENTLY
block metadata" promise. Added mappedV4() to decode the embedded IPv4
(dotted + hex-pair forms) and classify on it. TDD: 4 tests failing-first —
mapped loopback/RFC-1918/metadata rejected (metadata stays HARD_BLOCKED even
with VOYAGE_OTEL_ALLOW_PRIVATE=1), mapped public ::ffff:8.8.8.8 still valid
(no over-block). Threat model narrow (endpoint is operator-set env; export
opt-in; a brief cannot set env).

Survivor #18 honest-residual. T2-bakeoff §3 "Classifier interference: 0"
read as satisfied, but the auto/bypass-mode re-run that matters for headless
trekreview was never run (mode is operator-set, not settable in-session) —
footnoted, not gating. Per recommendation #9, moved to an OPEN RESIDUAL
(untested), guarded by a new doc-consistency pin.

Audit record. ## S21 resolution block in devils-advocate-results.md
dispositions all four sub-questions: SSRF (fixed), hooks-block (verified;
advisory-rail residuals: Write-only matcher, Bash-redirect, regex gaps — by
design), malicious-brief-headless (catastrophe-blocked, exfil NOT blocked —
inherent limit). S21b flagged (NOT done): operations.md:15 mis-describes
autonomy-gate.mjs state machine + --gates table.

Test count: real baseline 700 (698 pass / 2 skip), NOT 715 — the node:test
headline carried in S20 commit msgs was stale/miscounted (census figures
were correct). Now 705 (703 pass / 2 skip / 0 fail); census behavior
601->605, doc-pins 71->72, total 672->677.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 20:02:56 +02:00
6ed0c27fe2 docs(voyage): S20-fix2 — correct false custom-profile lookup claims in operations.md
Operator directive (same as S20-fix): a real error must be fixed, not
carried as "flagged, out of scope". docs/operations.md §Custom profiles
made three claims that contradict findProfilePath (resolver.mjs:57-78):
  - custom profiles created in lib/profiles/<custom>.yaml — that is the
    BUILT-IN dir; custom profiles live in voyage-profiles/
  - "custom profiles override built-ins of the same name" — the built-in
    is resolved FIRST and wins; a custom file cannot shadow it
  - "lookup is alphabetical with <custom> taking precedence" — resolution
    is by directory order (built-in -> repo-root voyage-profiles/ ->
    ~/.claude/voyage-profiles/), never alphabetical

Corrected to match the code and the behavior already pinned by
profile-application.test.mjs SC #8 (custom = new name, voyage-profiles/,
repo-root > home).

TDD: anti-false-claim doc-consistency pin written failing-first, then
prose fixed. Suite 714->715 (713 pass / 2 skip / 0 fail); census
doc-pins 70->71, total 671->672.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 15:10:56 +02:00
04063fe60f docs(voyage): S20-fix — correct stale "Use Sonnet for all sub-agents" in 3 orchestrator docs
Follow-up to e7a58b0 (S20). Operator directive: errors found during a
task must always be fixed, not flagged out-of-scope. The three
orchestrator reference docs (review/research/planning) carried a
pre-pinning "Cost: Use Sonnet for all sub-agents" rule that contradicts
the operator-pinned all-opus reality (40d8742 — all 24 named agents are
model: opus, guarded by agent-frontmatter.test.mjs). The authoritative
command (trekresearch.md) was already correct.

Corrected all three to mirror trekresearch.md: sub-agents use their
pinned model: frontmatter (currently opus); a phase_signals model signal
or the active --profile (e.g. economy) overrides per-phase. Legitimate
sonnet uses (economy profile, low-effort path) are per-phase overrides,
not a blanket default — left untouched. The two "(Sonnet, Explore)"
ad-hoc follow-up/deep-dive hints are outside the 24-agent pinning and
align with the global "Sonnet for retrieval" model strategy — left as-is.

TDD: anti-false-claim doc-consistency pin written failing-first (3 hits)
in doc-consistency.test.mjs, then the prose fixed. Suite 713->714
(712 pass / 2 skip / 0 fail); census doc-pins 69->70, total 670->671.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 14:27:03 +02:00
494a344700 docs(voyage): S19 — leanness: honest test census + prune 3 redundant prose-pins
Closes devils-advocate audit §Top changes #8 (MINOR×MED). Reports the
behavior-test count separately from the doc-consistency prose-pin count so the
cited total no longer oversells behavior coverage, and removes the clearest
reword-fragile redundancies. Conservative scope (operator-chosen): no genuine
regression guard dropped.

1. Suite census (report separately). lib/util/test-census.mjs +
   tests/lib/test-census.test.mjs walk tests/**/*.test.mjs and bucket top-level
   test() declarations into behavior vs doc-consistency-pins (bucket per file,
   regex PIN_FILE_RE), asserting the two sum to the total so neither can drift
   silently. Split emitted as a t.diagnostic: behavior=601 doc-consistency-pins=69.
   Metric = top-level declarations; node:test's runtime total counts subtests
   too and is therefore >= it.

2. Conservative prune (3 tests, each provably subsumed):
   - "trekexecute.md still parses v1.7 plan schema" — tautological OR-chain;
     real coverage = the plan_version:1.7 template pin + plan-validator /
     plan-schema behavior tests.
   - "CLAUDE.md mentions all six pipeline commands" — hardcoded six-string list
     subsumed by the filesystem-driven "commands table mentions every
     commands/*.md file" structural pin.
   - "CLAUDE.md mentions /trekcontinue command" — same subsumption.
   Each removal leaves an in-place note (why + where coverage lives).

3. doc-consistency.test.mjs header now documents the structural-invariant vs
   prose/existence-pin distinction so new pins land in the right kind.

TDD: census test written failing-first (ERR_MODULE_NOT_FOUND before
lib/util/test-census.mjs existed). Suite 699->698 (696 pass / 2 skip / 0 fail):
-3 prune +2 census. plugin validate passes (1 accepted warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-19 13:52:30 +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
eb5a7324a4 fix(voyage): S17 — downgrade NW2 bake-off verdict + drop orchestrator Agent-grants
Survivor #3 (bake-off data un-archived): per-run JSON a1..b3.json was never
committed (git diff-filter=A empty), so the medians/jaccard ladder cannot be
re-derived or audited. Commit-path would require fabricated data (forbidden) →
downgraded "POSITIVE" to "opt-in-defensible (single un-archived run)" in
docs/T2-bakeoff-results.md (verdict line + §5 header + new §Reproducibility
caveat) and the v5.5.0 CHANGELOG entry. New doc-consistency pin fails if the
doc re-asserts bare POSITIVE or drops the un-archived disclosure.

Survivor #5 (latent dispatch risk): planning/research/review orchestrators are
inline reference docs no command invokes, yet shipped tools:["Agent",...]. The
harness cannot spawn sub-agents with Agent, so the grant was pure latent risk.
Dropped "Agent" from all three frontmatters; flipped the agent-frontmatter
invariant (its canonical home) from "must include Agent" to "must NOT include
Agent". Removed the duplicate orchestrator pin from doc-consistency to avoid a
double guard (S19 anti-bloat).

Tests 690 → 691 (689 pass / 2 skip / 0 fail). claude 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 06:24:27 +02:00
6ba58fda9b docs(voyage): S16 — stale counts/strings truth-pass + 4 doc-consistency pins
Truth-pass over the README/CLAUDE/contract docs the S14 audit flagged as
stale (findings #2/#6/#7/#8/#9). Re-grepped every count against the actual
files first — line numbers in the audit are S14 snapshots that had already
rotted. docs + tests only; lib/ runtime and all behaviour untouched.

Corrections:
- README architecture block: 23 → 24 agents; 5 → 7 hooks (add the two it
  omitted: post-compact-flush, otel-export); dropped the rotting test-count
  ("109" — already wrong twice, 109→683→686) for "comprehensive node:test
  suite" so the number can never drift again (operator choice).
- brief-reviewer five → six dimensions (+ memory alignment); plan-critic
  9 → 10 dimensions (README ×2 + CLAUDE.md), matching the agent's 10 numbered
  dims and the v5.5 flagship 6th brief dimension.
- phantom "v5.4" contract-freeze references → v5.5.0 (CLAUDE.md + HANDOVER-
  CONTRACTS ×3). v5.2–5.4 never shipped; the formalization landed with 2.2 in
  v5.5.0 (CHANGELOG:9), so line 46 got a prose tweak (one release both
  established 2.1 and evolved it to 2.2). CHANGELOG history left intact — it
  correctly explains the phantom.
- trekplan Phase-8 inline-sealing rationale "Opus 4.7" → 4.8.
- bonus (operator-approved): end-session helper name trekplan-end-session →
  trekendsession (the actual command).

New doc-consistency pins (TDD red→green): README agent-count and hook-count
(file counts), plan-critic dim-count (computed from ### N. headers),
brief-reviewer dim-count (cross-file, excludes agent-list lines that
co-mention plan-critic's count). Updated the existing pin that guarded the
phantom "v5.4 froze 2.1" string to the corrected wording + a !/v5.4/ guard.
Version-string pins (Opus 4.8 / v5.5.0) deliberately omitted as S19 prose-bloat.

Tests 686 → 690 (688 pass / 2 skip / 0 fail). claude 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-18 21:42:05 +02:00
7a5749ddcc docs(voyage): S15 — cost-claim truth-pass + premium default-profile pins
Resolve the S14 default-profile contradiction. Investigation overturned
the audit addendum's guess ("code is the bug → balanced"): commit 40d8742
(2026-05-13, "pin all sub-agents to Opus permanently (operator request)")
plus VOYAGE_PROFILE=premium in ~/.zshenv establish premium as the deliberate
default. Operator confirmed in-session: premium is the shipped default; fix
the stale docs, not the code. No code or behaviour changed (lib/ untouched).

Docs (default-name → premium, consistent across resolver + all three docs):
- README + docs/profiles.md + docs/operations.md: 3 lookup-order sites and
  3 profile tables now mark `premium` as the default.
- premium table row corrected to all-opus (matches premium.yaml — a third
  inconsistency the audit missed; README/profiles.md showed opus/sonnet/...).

Cost narrative made honest (premium = all-Opus reality):
- §Cost profile rewritten: uniform model per phase, no orchestrator-vs-swarm
  split; cheaper via --profile balanced/economy.
- Removed false "Sonnet exploration/review swarm" claims (README 195/223/266
  model-neutral; 804 parenthetical; the "Switch the planning model" note).
- profiles.md custom-profile prose corrected: built-in wins over same-named
  custom (findProfilePath), dropping the bogus "balanced is the locked default".

Pins (TDD red→green, doc-consistency.test.mjs):
- default-profile name invariant (resolveProfile ↔ README/profiles/operations)
- profile tables ↔ each built-in yaml phase_models (structural, catches drift)
- cost-claim regression guard (no resurrected Sonnet-swarm phrasing)

S16/S18 surface untouched: counts (23 agents, 9/10 dims, 5/6 dims), versions,
framing gates unchanged. Full suite 686 (684 pass / 2 skip / 0 fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 21:06:36 +02:00
056720e7f3 feat(voyage): S13 — RELEASE v5.5.0 (framing 2.2 badge + NW1–NW3 + W2/W3 roll-up)
The coordinated release held since S6. Bumps 5.1.1 → 5.5.0 across plugin.json,
package.json, package-lock.json, README badge, and CHANGELOG (operator-confirmed
version; matches the codebase-wide v5.4/v5.5 milestone labels). Additive — no
breaking change for existing consumers; new brief requirements gate only on
briefs that declare brief_version 2.2.

Lands:
- brief_version 2.2 framing enforcement (framing enum + memory-alignment dim +
  obligatory TL;DR), held since S6 — badge now bumped
- Handover 1 PUBLIC CONTRACT formalization (the unreleased "v5.4")
- W2: Opus 4.8 baseline + native effort: on 8 agents + resolver model-gate fix
- W3: exec-form hooks (CC-14) + disallowed-tools on trekexecute (CC-11)
- NW1 reviewer-output schema contract; NW2 --workflow opt-in (bake-off POSITIVE);
  NW3 synthesis-agent dormant (declined per measurement)

CC 2.1.130→181 dispositions (docs/cc-upgrade-2.1.181-decision-matrix.md §S13):
- CC-08: GH#36071 (hooks in headless) CLOSED AS NOT PLANNED, not fixed →
  in-prompt safety preamble retained
- CC-29/31: verified clean / aligned, no code change
- CC-07/12/13: DEFER confirmed (recorded, no code)
- CLAUDE.md root warning: ACCEPTED BY DESIGN (universal across marketplace,
  advisory only; repo/maintainer context, not shipped consumer context)

TDD: version-consistency + v5.5.0-entry tests added first (RED→GREEN).
Tests 695 → 697 (695 pass / 2 skip / 0 fail). `claude plugin validate` passes
(one accepted advisory warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 18:12:51 +02:00
6b30483304 feat(voyage): S12 — NW3 synthesis-agent built + measured → declined per measurement [skip-docs]
NW3 (CC-26 §6 PoC): delegate trekplan Phase 7 synthesis to a synthesis-agent,
adopt only if Δ main-context ≥30% with no quality loss. Operator chose the
deterministic-proof path (live ≥3-run bake-off was env-blocked: no API key;
installed plugin is a cache copy so a new agent is invisible to `claude -p`).

Decisive structural finding: trekplan Phase 5 runs the swarm FOREGROUND, so its
outputs are already resident in main before Phase 7. Delegating only Phase 7
evicts nothing → Δ_faithful = 0% (BASE-independent). The ≥30% saving needs an
out-of-scope Phase-5 redesign (swarm-writes-to-disk / nested orchestrator).
VERDICT: DECLINED per measurement.

- agents/synthesis-agent.md — dormant, schema-conformant deliverable (NOT wired)
- lib/plan/synthesis-digest-schema.mjs — digest output contract (+ tests)
- scripts/synthesis-measure.mjs — deterministic Δ-accounting core (+ tests)
- tests/fixtures/synthesis/ — 7 exploration outputs + representative digest
- docs/T1-synthesis-poc-results.md — measurement + verdict (reproducible)
- CLAUDE.md — agent table row (doc-consistency: 24 agents)

Tests 670 → 695 (693 pass / 2 skip / 0 fail). `claude plugin validate` clean
(only the pre-existing root-CLAUDE.md warning). commands/trekplan.md untouched.

[skip-docs] rationale: no user-facing feature ships (NW3 declined; agent dormant
and unwired). The substantive doc is docs/T1-synthesis-poc-results.md; the
README/CHANGELOG roll-up for NW1–NW3 is the S13 coordinated release per
docs/W1-narrow-wins-plan.md §S13.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 17:58:39 +02:00
9fb536e2d8 feat(voyage): S11 — NW2 part B, integrate opt-in --workflow flag
Make the bake-off-validated Workflow substrate (Arm B) reachable behind an
opt-in --workflow flag for /trekreview. Default Phase 5-6 path stays prose
to preserve the lower portability floor; --workflow raises the consumer
floor to Claude Code 2.1.154+ (the Workflow tool).

- arg-parser: --workflow added to trekreview boolean flags
- commands/trekreview.md: flag row + Phase 5 substrate-routing gate +
  new section 'Phase 5-6 via the Workflow substrate' (invocation contract,
  S10 gotchas, bake-off citation, auto/bypass residual as Known limitation)
- docs/command-modes.md: --workflow row in /trekreview table
- routes to existing scripts/trekreview-armB.workflow.mjs (byte-identical to
  the S10 part-B POSITIVE build); integration is pure routing, no script change

TDD: 8 new tests (arg-parser flag recognition + combine; command/doc prose
pins for route, opt-in posture, 2.1.154+ floor, bake-off evidence).
Suite 662 -> 670 (668 pass / 2 skip / 0 fail). plugin validate clean modulo
known root-CLAUDE.md warning. Resolves W1-narrow-wins-plan.md S11.
2026-06-18 17:22:09 +02:00
f7c8aa45ab feat(voyage): S10 part B — NW2 full bake-off (rich fixture) → verdict POSITIVE
Run the full T2 §5 prose-vs-Workflow /trekreview bake-off (operator GO,
choice "a"): 3 runs/arm on a rich-finding JWT-auth fixture, resolving the
smoke's 0-finding limitation.

Deliverables:
- tests/fixtures/bakeoff-rich/ — JWT-auth brief + diff with 5 seeded blatant,
  brief-traceable issues (varied severity/rule_key, one dual-flaggable).
- scripts/bakeoff-armA-merge.mjs — Arm A (prose) validate (NW1) + triplet-dedup,
  matching Arm B's dedup exactly.
- scripts/bakeoff-fidelity.mjs — cross-arm + within-arm + granularity-ladder
  fidelity analysis over the structured arm outputs.
- docs/T2-bakeoff-results.md §Full run — the T2 §5 verdict.

Result (3 runs/arm, both arms ran the coordinator):
- Verdict fidelity EQUIVALENT — all 6 runs BLOCK, cross-arm verdict-match 1.0.
- Finding-set: substrate is fidelity-neutral. Cross-arm jaccard 0.41 (triplet)
  → 0.71 (file,rule_key) → 1.0 (file); cross-arm ≈ within-arm at every
  granularity. Issue coverage 5/5 in 6/6 runs. Low triplet jaccard is
  line-citation noise shared by both arms, not a substrate effect.
- Token +4.4% (Arm B vs A; <=+15%). Classifier interference 0 at 9-agent
  concurrency. JSON-robustness: Arm B schema-forced; Arm A 6/6 valid via NW1.
- VERDICT POSITIVE → S11 proceeds with opt-in --workflow flag.

Caveat (per plan posture): strict triplet-jaccard>=0.7 flag is 0/9, a
metric-calibration artifact (both arms sub-0.7 against themselves), not a
regression. Residual: F4 auto/bypass explicit-mode check (mode not settable
in-session).

Suite green (662/660 pass, 2 skip); plugin validate clean (modulo the
pre-existing root-CLAUDE.md warning). No production code changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 15:44:24 +02:00
869bf318d2 feat(voyage): S10 — NW2 part A (Workflow port + fidelity harness + smoke)
Build the prose-vs-Workflow bake-off machinery for /trekreview Phase 5-6 and
run a 1-run/arm smoke to de-risk before the full measurement (operator posture:
build + smoke, then pause for go/no-go on the full >=3-runs/arm run).

New:
- lib/review/fidelity-diff.mjs (+ tests) — the PRIMARY metric: parse two
  review.md (or two structured arm outputs) and compare verdict + jaccard over
  (file,line,rule_key)-IDs + per-finding severity/rule_key. Reuses jaccard +
  frontmatter + NW1 findings-schema + finding-id. fidelityDiffStructured avoids
  rendering review.md per run.
- scripts/trekreview-armB.workflow.mjs — Arm B: Phase 5-6 as a Workflow
  (parallel([conformance, correctness]) schema-forced -> JS dedup-by-triplet ->
  agent(review-coordinator) verdict schema). Path-based input via args (reviewers
  carry Read). Inlines dedup + the 12-key rule_key enum (scripts have no imports).
- tests/fixtures/bakeoff/ — committable fixture: real diff of b149538 (NW1) +
  brief reconstructed from plan S9. Both arms review the same pinned input.
- docs/T2-bakeoff-results.md — smoke results + verdict + go/no-go recommendation.

Smoke result: SMOKE PASS. Arm B runs the full pipeline (3 agents) with ZERO
classifier interference; fidelity EQUIVALENT to Arm A at the verdict level
(both ALLOW; jaccard 1.0). Caveat: the clean TDD'd fixture yielded ~0 findings,
so finding-SET fidelity was not stressed (only verdict fidelity proven). A
reviewer-level divergence appeared (Arm B raised 1 raw finding, coordinator
filtered it; Arm A raised 0) — to be quantified in the full run on a
richer-finding-surface fixture. NOT the T2 §5 POSITIVE/NEGATIVE verdict.

Suite 647 -> 662 (660 pass / 2 skip / 0 fail; +15 fidelity-diff). claude plugin
validate clean (known root-CLAUDE.md warning only). Plan: docs/W1-narrow-wins-plan.md S10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 14:40:19 +02:00
b149538d43 feat(voyage): S9 — NW1 reviewer-output schema contract (TDD, ungated)
Codify the /trekreview Phase 5 reviewer JSON contract as a validated schema so
main validates each reviewer's output instead of merely JSON.parse-ing it, and
re-asks on schema failure (not just parse failure). Retires the fragility at
trekreview.md:202-204. No Workflow dependency (S8 tier 1, ships regardless).

New lib/review/findings-schema.mjs (3-layer Content -> Raw-text -> CLI shim,
reusing result.mjs error-shape + rule-catalogue RULE_KEYS/SEVERITY_VALUES):
- validateFindings(payload): hard errors on load-bearing fields the dedup
  triplet + verdict depend on — file, rule_key (in catalogue), severity (enum),
  line (integer >= 0); accumulates all errors; per-finding location.
- extractFindingsBlock(text): last fenced ```json block (the :202 contract).
- validateReviewerOutput(text): extract + parse + schema, unifying parse and
  schema failures under one bounded re-ask path.
Stable codes: FINDINGS_NOT_OBJECT/_NOT_ARRAY/_NO_JSON_BLOCK/_PARSE_ERROR (top),
FINDING_MISSING_FILE/_MISSING_RULE_KEY/_UNKNOWN_RULE_KEY/_BAD_SEVERITY/_BAD_LINE
(per-finding). Descriptive fields + unknown keys tolerated (forward-compat).

Phase 5 prose: replace "parse last json block; on parse error re-emit" with
"validate against findings-schema; on failure re-ask conforming JSON, bounded
N=2; never feed unvalidated findings to the coordinator".

TDD: 27 failing tests first, then minimal code to pass. Suite 606 -> 647
(645 pass / 2 skip / 0 fail). claude plugin validate clean (only the known
root-CLAUDE.md warning). Plan: docs/W1-narrow-wins-plan.md S9.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 14:06:07 +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
fa23b16443 docs(voyage): S5 — formalize Handover 1 brief-schema as public contract (v5.4)
Elevate Handover 1 (brief.md → research) from an internal pipeline handover
to an explicit PUBLIC CONTRACT — the only public producer↔Voyage integration
boundary (Trinity asymmetry invariant: Voyage stays unaware of upstream tiers;
any compatible producer may feed it; no producer privileged).

Scope = freeze + document (operator-gated, option A). No schema change, no
plugin version bump (that is S10 RELEASE). Per S3, phase_signals stays optional
and brief_version 2.1 is the frozen public-contract baseline.

- docs/HANDOVER-CONTRACTS.md: PUBLIC CONTRACT label + callout on Handover 1
  (asymmetry, breaking-for-downstream, additive-vs-breaking, frozen 2.1 baseline);
  resolve the speculative "v5.4 may promote phase_signals to required → 3.0" line
  to the S3 freeze decision; fix stale schema-table baseline 2.0 → 2.1; annotate
  the Stability summary row (symmetric with Handover 3's "external" flag).
- CLAUDE.md: Trinity note now points at docs/HANDOVER-CONTRACTS.md §Handover 1.
- tests/lib/doc-consistency.test.mjs: +4 failing-first doc-truth pins (Iron Law)
  — PUBLIC CONTRACT label, callout + breaking-for-downstream guarantee, frozen
  2.1 baseline (no stale 2.0), freeze-not-promote. 586/584 pass/0 fail/2 skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 12:40:02 +02:00
fdd3ad80d7 feat(voyage): W2 impl (S4) — gate resolver model, adopt native effort:, doc-truth
S4 of the 2.1.181 upgrade — implementation, not a gate. TDD: failing test
written first for the resolver gate, then the fix; suite green throughout.

- Resolver MAJOR (FIX): lib/profiles/phase-signal-resolver.mjs now imports
  BASE_ALLOWED_MODELS from profile-validator and gates `model`
  (if 'model' in entry && BASE_ALLOWED_MODELS.includes(entry.model)),
  mirroring the EFFORT_LEVELS gate one line up. Out-of-allowlist models
  (gpt-4, haiku) are dropped instead of handed to an agent spawn —
  defense-in-depth behind brief-validator's validation-time check. No
  circular import (brief-validator already imports the same symbol).
  +2 tests (drops-invalid / keeps-valid).
- Native effort: (SHIP, static additive): effort: frontmatter on 8 agents —
  retrieval (task-finder, git-historian, dependency-tracer,
  architecture-mapper) = medium; adversarial-reasoning (plan-critic,
  risk-assessor, contrarian-researcher, review-coordinator) = high. The
  other 15 stay unset -> inherit Opus-4.8 default (high). This per-spawn
  REASONING effort is a different axis from brief phase_signals.effort
  (ORCHESTRATION shape) per the S3 decision.
- Doc-truth + axis distinction: new canonical docs/profiles.md
  §Model & effort axes (opus->Opus 4.8 default-high; orchestration vs
  reasoning effort table; native-effort precedence; per-agent levels).
  Short notes in CLAUDE.md (after Agents table) and README.md (Cost
  profile), both pointing to profiles.md.
- Open (non-blocking, unchanged): only STATIC effort shipped — the
  verified-safe minimum. Profile-driven DYNAMIC effort still needs
  verification of the per-spawn effort param or env-var injection.

Matrix: new "S4 resolutions" section. Tests 582 total / 580 pass / 0 fail /
2 skip (was 578 pass; +2). claude plugin validate passes (only pre-existing
root-CLAUDE.md warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 12:27:07 +02:00
66b3b15fb6 chore(voyage): W3 hardening (S2) — exec-form hooks, enforced disallowed-tools, F2 decision
S2 of the 2.1.181 upgrade. Schemas verified verbatim against the official
slash-commands and hooks docs before editing (a first-pass camelCase
'disallowedTools' claim was caught and corrected to kebab-case against the doc).

- CC-14 (SHIP): migrate all 7 hooks in hooks/hooks.json to exec-form
  {command:"node", args:["${CLAUDE_PLUGIN_ROOT}/hooks/scripts/X.mjs"]}. Doc
  recommends exec-form whenever a hook references a path placeholder; protects
  consumers installing under a path with spaces. ${CLAUDE_PLUGIN_ROOT}
  interpolates inside args (verified). hooks-json-stop-wired test made
  form-agnostic (normalizes command+args to one invocation string).
- CC-11 (SHIP): add `disallowed-tools: Agent, TeamCreate` to trekexecute
  frontmatter, enforcing its documented "No Agent tool, no TeamCreate" rule.
  allowed-tools grants auto-approval but does NOT remove tools from the pool,
  so the prior omission left Agent callable; disallowed-tools removes it.
  trekexecute is the only command with a documented exclusion.
- CC-15 (DECIDE: keep universal): re-affirm F2 deferral. pre-bash/pre-write
  executors stay universal -- session-agnostic safety (rm -rf /, ~/.ssh, .env)
  that narrowing to execute-only would only weaken. Header comments corrected.
- CC-10 (DECIDE: design note, no code): no blanket Agent(model:opus) deny rule
  -- would break balanced/economy profiles; any model-enforcement must be
  profile-aware, deferred into W2. Folded into open question #3.

Matrix updated with S2 resolutions section. Tests 578 pass / 0 fail / 2 skip;
claude plugin validate passes (only pre-existing root-CLAUDE.md warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 12:03:11 +02:00
f16ad3690e test(voyage): retarget phase_models/phase_signals doc-consistency to canonical doc homes
The v5.x doc consolidation (67f6dd5) moved phase_models into docs/profiles.md and phase_signals into docs/HANDOVER-CONTRACTS.md, leaving CLAUDE.md to only link them via Reference docs. Two doc-consistency assertions still read CLAUDE.md and went red on main. Retarget both to the canonical doc homes (legacy-alias check preserved on docs/profiles.md). Suite: 578 pass / 0 fail / 2 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 11:10:51 +02:00
098ba15a5b feat(voyage): define high-effort behavior + amend brief Non-Goal/SC1 + coordinator normalization (Decision B)
Wave 6 / Step 10 — autonomy-gated. Operator confirmed: gemini-bridge
substitution for plan-critic doubling AND SC1 amendment to
resolver-invariant encoding (decisions.local.json recorded).

- commands/trekplan.md: gemini-bridge plan-review Pass 2 on
  post-revision plan in high-effort mode (replaces fragile
  plan-critic doubling per risk-assessor).
- commands/trekresearch.md: full swarm + contrarian-researcher +
  gemini-bridge always-on.
- commands/trekreview.md: skip Pass 3 reasonableness + invoke
  coordinator normalization rule.
- commands/trekexecute.md: gates_mode = closed (strict manifest-audit,
  main-merge pauses); flag override still wins.
- agents/review-coordinator.md: Pass 3 high-effort normalization —
  substitute unknown rule_key with PLAN_EXECUTE_DRIFT, preserve
  original in original_rule_key.
- .claude/projects/2026-05-13-trekflow-solo-lane/brief.md (gitignored,
  not committed): Non-Goal amendment locks low/high tiers; SC1
  amendment authorizes resolver-invariant interpretation.
- tests/lib/doc-consistency.test.mjs: +4 pins for the
  "### High-effort behavior (v5.1.1)" heading per command.

Tests: 578 pass, 0 fail, 2 skipped (+4 from 574).

Closes #7 (operator-gated decisions captured + coordinator
normalization landed).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 16:07:37 +02:00
f8cc299e9d test(voyage): refactor 4 downstream command tests to runtime SC4+SC7 (closes #2 #3 #6 #10) 2026-05-14 21:46:11 +02:00
2b2c45c1df test(voyage): refactor trekbrief command test to runtime SC1 (closes #1) 2026-05-14 21:44:38 +02:00
001df01332 test(voyage): add profile-resolver non-interference tests (closes #4 SC5) 2026-05-14 21:36:57 +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