# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## Unreleased — The annotating skill, the run coupling and P10's model-free part ### Added - `voyage:annotating` (order B): the operator-annotation loop as one skill. The person writes every note and Claude none; Fix and Change edit only the text a note points at; a Question is answered and changes nothing; nothing the notes did not ask for is edited; the approval an edit costs (a stale brief intent, a changed plan) is said before the edit; the page is built again on the revised file. It also covers a research document when the user asks (decision 62); `/trekresearch` gets no annotation step. Red baseline with helpers (Opus 5.5 high, 3 runs per scenario, a toy project with an approved brief and plan): without the skill 3 of 3 changed the plan because of a Question, 3 of 3 applied a Fix to steps the note did not name, 2 of 3 edited brief text no note asked for, 1 of 3 put its own critique next to the page, and 0 of 3 named the stale approval before the edit; with it, 0, 0, 0, 0 and 3 of 3. Six eval cases `evals/skill-annotating-*`, written, not run. ### Changed - **The "run the thing" step names Claude Code's built-in `run` skill.** The plan's run step (`/trekplan`), the executor's end-to-end part (`/trekexecute`) and the plan template each say in one sentence that the app is seen and driven with `run`, and that the verdict is still the `End-to-end:` command through the criteria runner, because `run` gives no exit code (decisions 54 and 64). - **A quiet eval case may name Claude Code's own `run` as its owner** (R2). The routing test keeps a short fixed list of built-in owners (`BUILTIN_OWNERS`, only `run`); for such an owner, which is outside the corpus, only "the skill does not rank first" is checked, and the report says so. `evals/skill-writing-criteria-quiet-2` now has `owner=run` instead of `/trekexecute` standing in. - **P10's model-free part is done; the eval gate (P10) is exempted until the fixed test set runs again.** Every case in `evals/` now names the event it came from (`from=`), the eight test-set cases included (`from=proevesett-eval-suite`, `from=proevesett-intent-gate`). The routing test (`lib/skills/routing.mjs`) fails any case without it, routed or not, and its report gives both counts: cases checked for `from=` and cases routed. The release gate that would read the last test-set run is written into `docs/release-runbook.md` as exempted with its reason, not built: a gate that can never fire is not built. - `/trekbrief`, `/trekplan` and `/trekreview` name `voyage:annotating` where they build the page; the description of the page and the "revises freehand" loop left the three commands. The call to `scripts/annotate.mjs`, the not-a-gate line and the printed links stay. The printed report now says a Question is answered and Fix and Change notes revise the file. - **`/trekendsession` is operator-only, and the planning and research spawn sites follow the profile.** The model can no longer start `/trekendsession` (`disable-model-invocation: true`). With `--project`, where the resolver runs, `/trekplan` and `/trekresearch` pass the resolved model at their spawn sites, so the `economy` profile gives Sonnet helpers unless the brief's phase signal for that phase names a model; without a resolved model the agent's own `model:` applies (opus for Claude Code's built-in agents), and `/trekexecute`'s step helper and controller stay on opus. - **`~` and `$HOME` in the arguments of `/trekendsession`, `/trekcontinue` and `/trekreview` are no longer expanded** (ARG, fix round 4.5b). The arguments reach the arg parser as text on stdin, not as shell words, so nothing in them is expanded: write the path out (`~/x` stays the three characters `~/x`). ### Fixed Fix round 4.5b (decisions 80 to 87): the round's 39 findings, from the 4.5a review and its execution and three the operator added, proven by 41 test ids. Each is fixed, and each has a test seen failing first: on the code at the round's start point (`be0b631`), or, for the 14 ids whose code was already right or lives under `tests/`, under a named mutation (`tests/fix-round-4-5b-red.sh` proves both). **Verdict gate** - **The verdict gate reads `--repo=` and refuses an unknown option** (M6). `lib/review/verdict-gate.mjs` takes `--repo ` and `--repo=`; `--repo=` with no value and any other option, a `--x=value` one included, exit 2 with the usage line, so a misspelt flag no longer skips the stale check. `--json` stays. - **Only a full commit id opens the merge lock** (M11). A `scope_sha_end` must be 40 or 64 hex and equal what `git rev-parse` prints for it, so a SHA-256 repository opens the lock, and a short id, or a branch named like a commit id, reads as stale. The done line (`lib/verification/done-line.mjs`) and the release check (`scripts/release-check.mjs`) take only full commit ids too. - **A failed git call is not measured, not stale** (M4). A `--repo` path that is missing or no repository, and any git call that fails, give exit 2 with a reason that starts `review-not-measured:`; `/trekexecute`'s main-merge gate reports it as "not measured", never green, and the merge stays locked. Handover 6 names the prefix and lists `review_version` 1.1 as current. - **Free text inside the lessons block makes the review stale** (m4). Every line a later commit adds inside Voyage's block in `.claude/rules/voyage-review-lessons.md` must be a valid lesson line or the block's own header line. **Park tool** - **The park tool moves nothing when it cannot read HEAD** (M7). `lib/util/park-attempt-files.mjs` reads HEAD's paths once (`git ls-tree`) before any change, and exits 2 with nothing unindexed or moved when that read fails or a path in HEAD is missing from the index. Before, a failed `git cat-file -e` read as "not in HEAD", and a committed file was moved. - **A CRLF diff is parked, and the text says what a staged new file gets** (E22c, E22e). The tool reads a diff with CRLF line ends; its header and `/trekexecute` say that it parks every file new in the attempt's diff, untracked or staged but not in HEAD. - **The "Back to planning" save line reads the whole diff from a subdirectory** (M3). Its `git diff` carries `--no-relative`, so `diff.relative=true` no longer leaves files out. **Review coordinator and Arm B workflow** - **The Arm B workflow keeps the contract's row** (M5, S3, E20). `scripts/trekreview-armB.workflow.mjs` matches a put-back row on the title as the coordinator trims it, so a trimmed title gives no duplicate row, and ranks a conformance/correctness tie as `lib/review/coordinator-contract.mjs` does; the canonical sort of untitled findings is pinned in both. - **The coordinator's text says what the code does with a line number** (M9). A citation that escapes the repo root, or a negative line, refutes a finding; any other line number alone never does, and a line past the end of the file goes to `unverified`. - **The four `--quick` summaries name the brief-conflict rule as the exception to the skipped reasonableness filter** (M2, K3). `/trekreview`'s flag table, the review orchestrator, `docs/command-modes.md` and README say so, and the orchestrator's item 3 names the brief-conflict lowering as the exception to the catalogue reset. **Red proof** - **One red script for every round** (RS, M1, M1r, E23a, E23b, E23d, E23f). `tests/helpers/red-round.sh` takes a base, the round's ids, the other rounds' ids, a mutation module and the test files; `tests/fix-round-4-5a-red.sh` and `tests/fix-round-4-5b-red.sh` are thin wrappers over it. The judge skips another round's id and reports an unreadable tag such as `[X 1]`; the base run selects every tag with one pattern and carries a timeout; the judge's exit 2 is tested, and a test checks that a result exists before it reads it. The tests the 4.5a discovered-error fix added carry their 4.5a parent tags, so the red script judges them. **Commands and docs** - **The arguments reach the parser on stdin, never as shell words** (ARG, M8, M10, DJ5). Phase 0 of `/trekendsession` and `/trekcontinue` and Phase 1 of `/trekreview` give `$ARGUMENTS` to `lib/parsers/arg-parser.mjs --stdin` as the one line inside a quoted heredoc, so a `;`, a `$( )` or a glob in them is text. `/trekcontinue` and `/trekendsession` stop on the parser's exit 1 with its `errors`, and when it prints no JSON. `/trekendsession` takes its label as the rest of the text as typed (the parser's `tail`), so a label of several words is kept whole, and its Phase 3 reads the arguments again the same way instead of splicing the label into a shell line, so an apostrophe in the label no longer breaks that line or runs a command. - **The Bash guard blocks a parser heredoc that closes early** (R6). `hooks/scripts/pre-bash-executor.mjs` blocks (`args-heredoc-closed-early`) a command whose `VOYAGE_ARGS_EOF_7F3C9E` heredoc opens unquoted, or whose closing line stands twice or is not the last non-empty line, so a typed line equal to the delimiter cannot end the heredoc and run what follows. - **Every `/trekbrief` exit names Phase 7 with its `auto_result`** (M13, K2). The exit with no research topics runs Phase 7 with `auto_result: manual`, and the "Cancel — do manual" row with `auto_result: cancelled`. - **`/trekplan`'s execute and team exits run Phase 12, and the research loop names its model** (DJ1, DJ2). The "execute" and "team" exits run Phase 12 (`outcome: execute`, `outcome: execute_team`) instead of a bare stop; in `/trekresearch`'s high-effort loop, a turn that spawns an agent passes the resolved model, else `opus`. - **`run_seen` is kept in the progress file** (E14). `/trekexecute` writes it to `progress.json` (template, field table, Phase 7) and Phase 8 reads it from there, so the resume and multi-session paths report it; Handover 5 lists it as optional. - **Applying a lesson writes no pointer through a link or for an ignored file** (DJ4, PTR). `lib/review/recurrence.mjs` skips the `CLAUDE.md` pointer when `CLAUDE.md` is a symlink or git ignores the lessons file, and refuses a lessons file that is a symlink or whose directory lies outside the repo; `/trekexecute` Phase 7.2 commits only the review's paths git does not ignore. - **The research and review texts are said once and pinned exactly** (E17a, E17b, E18a, Da, Db, E16a). The two `/trekresearch` sentences on outbound queries and the F9 triage rows are pinned exactly; the deep-research adapter says where wave 2's contrarian findings merge; README's deep-research parenthesis says "when the engine is active", and the test that no README line stars `security-researcher` reads every line. The next-session validator's refusal of `--state-file` with no value is tested. Fix round 4.5a (decisions 57, 67 and 68): the round's 30 findings, where a Voyage control could be bypassed or was too lax, or where the text gave a guarantee no code held. Each is fixed, and each has a test that fails on the code before it, except DJ, whose sentences already stood and whose pins fail when they are deleted (`tests/fix-round-4-5a-red.sh` proves every other id red at the round's start point, and DJ under its two mutations). **Execute** - **The merge lock refuses a review of an older commit** (R6). `lib/review/verdict-gate.mjs` takes `--repo `: an ALLOW or WARN review then opens only when its `scope_sha_end` is HEAD, or an ancestor of HEAD whose later commits (side branches included) change nothing but the review lessons and the `CLAUDE.md` pointer; anything else exits 2 with a reason that starts `review-stale` (the new `lib/review/reviewed-commit.mjs`), and a failed git call exits 2 with a reason that starts `review-not-measured:`, not `review-stale` (fix round 4.5b). `/trekexecute` Phase 7.2 and the main-merge lock run the gate with `--repo .`, so the merge stays closed with the decline reason `review-stale`, also on `--resume`. - **`/trekexecute` runs the brief check it promised** (finding #33). With `--project` and a `brief.md`, Phase 1 runs the brief validator and the phase-model resolver (`lib/profiles/resolver.mjs --resolve-phase-model`) as `/trekplan` does, uses the effort it returns, and halts only on `BRIEF_V51_MISSING_SIGNALS`. Low effort runs the plan as one session, step after step; high effort changes nothing, and the text that set `gates_mode` from the effort and its `gates_mode_flag_override` record are gone. - **`/trekexecute` names and reads `--profile` and `--gates`** (finding #30). The argument hint, the usage block and Phase 1 carry both flags, Phase 1 strips `--profile ` before it reads the plan path, and the text says the profile changes no model here: the step helper and the controller stay on opus. - **The completion gate says which of its checks are commands and which are the executor's judgement** (finding #28). It no longer calls the counter check and the audit deterministic, and its two dead line references are gone. - **The final report says whether the app was seen with Claude Code's `run`** (decision 67). A ``**Seen with `run`:**`` line after End to end and a `run_seen` key in the summary JSON; the verdict is still the `End-to-end:` command. - **The park step no longer leaves an earlier attempt's files in the tree with exit 0** (6.5.0 Known issue: the park step). `lib/util/park-attempt-files.mjs` takes a file registered with `git add --intent-to-add` out of the index and parks it, strips colour codes from the diff and blocks on a non-empty diff with no readable header, reads the paths from the repository's top level whatever directory it runs in, and exits 2 when one of its git calls fails (a non-zero `git cat-file -e` reads as "not in HEAD"), before any file is moved. "Back to planning" saves the upward diff with `--no-color` and `core.quotepath=off`. **Gates** - **`--gates closed` turns gating on, and a bare `--gates` no longer swallows the next flag** (finding #1). The shim (`lib/util/autonomy-gate.mjs`) reads bare, `true` and `closed` as on and `false` and `open` as off, takes any other value as a usage error (exit 1), and leaves a following `--flag` in place. Before, only `true` was on. - **`--gates` means one thing in every command** (finding #1). `/trekbrief`, `/trekresearch`, `/trekplan` and `/trekexecute` share one rule and run the shim once to map the value. `/trekexecute` maps the value, and no phase of it pauses on it; its one stop is the merge into main. The executor strictness table (`adaptive`, `closed`, `open`) left README and `docs/`, and `/trekbrief` no longer promises pauses in the executor. **Brief** - **A brief with no research topics ends with its next steps** (finding #47). `/trekbrief` prints the manual path (`/trekplan --project`, then `/trekexecute --project`) and stops instead of entering the auto-only Phase 6, which now runs only after the operator opted into auto mode and Phase 4h approved the intent. **Plan** - **"execute" in `/trekplan` no longer builds the plan in the planning session** (finding #52). It prints the `/trekexecute` line and stops, so the approval check, the test lock, the step helpers and the review run; "team" and leaving plan mode do the same. - **The planning and research spawn sites take the resolved model** (findings #48 and #12). `/trekplan` passes `phase_signal_result.model` at its agent spawns, with the agent's own `model:` as the fallback and opus for the built-in Explore deep-dives; `/trekresearch`'s Phase 5 follow-ups do the same, with opus as the fallback. - **No turn budget is promised** (finding #57). The sentences that scaled `maxTurns` by codebase size left `/trekplan`, `/trekresearch` and the planning reference document; nothing set such a budget. **Research** - **The contrarian gets a conclusion to attack** (finding #113). `/trekresearch` launches `contrarian-researcher` as a second wave after every other agent of wave 1 returns, local ones included, with wave 1's leading answer, the claims for it and the alternatives it dismissed, taken from external findings only and with local parts removed; with `--engine deep-research` it runs after the engine returns. **Review** - **Core code outside the old deep-review patterns is now deep-reviewed** (6.5.0 Known issue: trial-5 finding 9). `/trekreview` triage makes deep review the default for every changed file it does not skip or mark summary-only, `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**` included; summary-only is for `docs/**`, root Markdown other than those two, and `tests/fixtures/**`. The review orchestrator, README, the review template and the workflow's fallback say the same. - **A line past the end of the file no longer refutes a finding** (6.5.0 Known issue: the coordinator's line numbers). The coordinator's Accuracy rule refutes only a citation that escapes the repo root or a negative line; a line past the end of the file goes to `unverified` with the new reason `accuracy:line-out-of-range`: the citation is wrong, the claim is unchecked. - **Deleting the Declined to Judge copy-through now fails a test** (6.5.0 Known issue: the Declined to Judge copy-through). The sentences in `/trekreview` Phase 6 and in the coordinator's Input and body section 9 that carry each reviewer's Declined to Judge lines into `review.md` are pinned, and the round's red script deletes those sentences and sees the pins fail. - **Which row a finding joins no longer depends on the order the reviewers' payloads are read** (6.5.0 Known issue: the row order). Inside one file, line and rule key, `dedupByTriplet` groups the findings in two passes, title first and the untitled ones last, each in a fixed order, and a full tie picks its survivor in that order too; the coordinator's Pass 1 text and the workflow's copy follow the same rule. The rows and their `#k` ids still stand in input order. - **On the `--workflow` path, the severity floor and the put-back match each finding to its own row** (6.5.0 Known issue: the workflow floor and put-back). A returned finding is matched to the row with its triplet and title; with no title match, to the only row on its triplet, else to the strictest one there, never a lower one, and `engine` is read from that row only. Each engine row no returned finding carries is put back at its own severity, one copy per row. **Continue** - **`/trekcontinue` runs the arg parser instead of naming a JavaScript function** (finding #66). Phase 0 runs `lib/parsers/arg-parser.mjs --command trekcontinue -- $ARGUMENTS` and reads its JSON; the review orchestrator's parser line also passes its arguments after `--`. - **`/trekcontinue` finds the master prompt file at the repo root, and the consistency check reads the state file** (finding #102). The master file is looked for at `git rev-parse --show-toplevel`, not an undefined plugin root. The consistency call passes `--state-file` when the project's session state exists, and the validator now takes that value as the flag's own instead of a third path, and is valid only when both prompt files are valid. **Endsession** - **`/trekendsession` parses its arguments with the arg parser** (finding #15). A slug or label that holds `-h` is no help request: help comes only on `--help` or a first argument that is exactly `-h`, and Phase 2 reads the brief path and the label from the parser's positionals. - **Only the operator starts `/trekendsession`** (finding #67). Its frontmatter sets `disable-model-invocation: true`, and CLAUDE.md names it as the one command that does. **Agents** - **A reviewer drops a finding only with a trace** (finding #111). code-correctness-reviewer and brief-conformance-reviewer emit an off-tier finding at the catalogue's severity and drop it only when they can say why it is wrong, as one Declined to Judge line with that reason; `voyage:reviewing-adversarially` says the same, and a rule key outside the catalogue is described as routed to `unverified`, as the coordinator contract does. - **research-scout has the Tavily tools its "Try Tavily first" needs** (finding #24). Its tools now hold `mcp__tavily__tavily_search` and `mcp__tavily__tavily_research`, in docs-researcher's order. - **code-correctness-reviewer no longer cites a "MANDATORY OVERRIDE rule above" that is not there** (finding #23). The sentence states the rule itself. **Docs** - **Nothing sends a reader to run the planning reference document** (findings #2 and #26). `/trekexecute`, `/trekbrief`, brief-reviewer, session-decomposer, `docs/HANDOVER-CONTRACTS.md` and `docs/architecture.md` name `/trekplan` where they named `planning-orchestrator`. - **The three reference documents hold read-only tools** (finding #26). planning-orchestrator, research-orchestrator and review-orchestrator list only `Read`, `Glob` and `Grep`. **Stats** - **No command promises a stats key its record does not write** (finding #46). The "Stats records emit `profile` …" sentences left `/trekbrief`, `/trekplan`, `/trekexecute`, `/trekreview` and `/trekcontinue`; `/trekresearch` keeps only `engine`, which its record writes; `docs/profiles.md`, `docs/operations.md` and README no longer say a profile reaches the stats records. **Across the round** - **The texts next to the fixes say the same** (siblings found during the round): `/trekreview`, the review reference and the Arm B coordinator prompt no longer drop a finding whose rule key is unknown; `/trekbrief` writes its stats record on every exit of its manual and auto paths, says that `--gates` adds one pause before its auto chain, and that the chain ends at the plan; `/trekexecute` says `--gates` changes nothing there, checks the wave marker before a low-effort single session, and names no validator check that does not exist; plan mode goes through the plan approval before it prints the `/trekexecute` line; the commands read only the two-token `--gates ` form, and `--gates=true` is the gates shim's own form (`lib/util/autonomy-gate.mjs`), which it reads as `--gates true`. ### Known issues - **A plan's `profile:` field has no writer.** README, `docs/`, `/trekexecute` and `/trekcontinue` say a plan carries or passes on a profile, but no command writes `profile:` to a plan; the plan validator's `MANIFEST_PROFILE_DRIFT` check reads it, and `resolveTrekcontinueProfile` has no caller outside its tests. Left whole for a later hardening part, which chooses between writing the field and taking the promises out. - **Splices and dropped `--x=` options outside fix round 4.5b** (decision 82). The commands' bash blocks still splice `{placeholder}` values into shell lines outside the four places the round closed (the Phase 0 parser lines of `/trekendsession`, `/trekcontinue` and `/trekreview`, and `/trekendsession` Phase 3), for example `"{brief_path}"` in `/trekplan` and the unquoted `{project_dir}` in `/trekendsession` Phase 4; and the release check, the lessons apply (`lib/review/recurrence.mjs`), the next-session validator and the park tool still drop an unknown `--x=` option without a word. One open finding, for fix round 4.5c or 4.5d. - **Two 4.5b findings moved to fix round 4.5c.** M12 (`lib/review/reviewed-commit.mjs` makes four git calls per path per commit; at most two paths per commit reach that loop) goes with 4.5c's single `git cat-file --batch` read, and Dc (the trekcontinue `line_ref` row in `tests/fixtures/jsonl-schemas.md`) with 4.5c's change of `line_ref` to a heading anchor. ### Doors - two-way: every case in `evals/` names its event, and the routing test checks every case (P10, R1) — a revert lets a case without `from=` through again; the eight tags added to the fixed test set stay harmless. - two-way: the coupling to Claude Code's `run` and the built-in owner list (R2) — a revert removes the three sentences and makes `owner=run` an unknown owner again; the criteria runner and `End-to-end:` are unchanged. - two-way: skill annotating and its pointers in three commands (order B) — revert the commit; the script, the page, the stored notes and the approval checks are unchanged. - two-way: fix round 4.5a (decisions 57, 67, 68) — a revert restores the old texts and checks - two-way: fix round 4.5b (decisions 80 to 87) — a revert restores the old checks, texts and red script and takes out the Bash guard's heredoc rule; `review.md` keeps `review_version` 1.1 either way. ## v6.5.0 — 2026-10-18 — Three skills for brief, criteria and review, English labels, and three trial-5 fixes Wave 3 adds three skills, each one source for a discipline that was copied or missing before: `voyage:interviewing` for the brief's question round, `voyage:writing-criteria` for criteria that can run and go red, and `voyage:reviewing-adversarially` for every reviewer's stance. The test repo's trial 5 ran all three end to end. The product now shows English where it showed Norwegian (decision 56), and three findings from trial 5 are fixed (decision 59), each with a test that failed on the code before it. Suite 2659 (2657 pass, 0 fail, 2 skipped), measured by `npm test` on `main` at `849b242`, the tree this release review covered. Nothing here asks anything of users. No brief, plan or review format changes. ### Doors - two-way: skill reviewing-adversarially and its skills: lines (order 7d) — revert f906ec9; the review contract (JSON, verdict) is unchanged. - two-way: skill writing-criteria and its pointers (order 7c) — revert 837e925; the criteria runner and the validators are unchanged. - two-way: skill interviewing and the /trekbrief Phase 3 pointer (order 7e) — revert f6e18a1 restores the inline Phase 3 text; no brief format change (Handover 1 untouched). - two-way: English UI labels (decision 56) — the stored annotation keys are unchanged, so a revert brings back the Norwegian labels and every saved annotation loads either way. - two-way: the brief validator warns on a criterion whose first backticked span is not a command while a later one is (trial-5 finding 1) — a warning, never an error; a revert stops the warning. - two-way: a re-planned step's earlier new files are parked before the fresh build (trial-5 finding 4) — a revert leaves them in the work tree again; files already parked stay in the git directory, never deleted. - two-way: one reviewer's two findings on one file+line+rule keep a row each (trial-5 finding 7) — a revert merges them again; earlier review.md files are not re-read. ### Added - **Skill `voyage:reviewing-adversarially`** (order 7d). One stance for every reviewer: no praise, a source for every finding (`file:line` or a quote), no downgrade without a reason, a Declined to Judge list, claims checked against the diff and not the report. Preloaded by the three `/trekreview` agents and scope-guardian, and named by `/trekreview` at spawn; it replaces the copied "Interaction Awareness" block. Each reviewer's Declined to Judge lines now reach `review.md`. - **Skill `voyage:writing-criteria`** (order 7c). One source for how a success criterion or a `Verify:`, `Regression:` or `End-to-end:` line is written so the criteria runner can run it and it can go red; anything more is `bash tests/.sh`. Preloaded by brief-reviewer and plan-critic, named by `/trekplan`. Baseline: 24 of 27 lines refused by the runner without the skill, 0 of 27 with it. - **Skill `voyage:interviewing`** (order 7e). `/trekbrief` Phase 3 asks for the interview form by name instead of carrying it: at most four questions per call, one decision each, the recommended answer first, facts looked up and never asked, the rest written down, and a hollow answer or unasked scope never written in as the person's decision. Measured with helpers: round-1 size 10–11 → 4, questions without a recommendation 15/31 → 0/12, a hollow answer kept as a decision 2/3 → 0/3. - **Eval cases for the three skills** (`evals/skill-interviewing-*`, `evals/skill-writing-criteria-*`, `evals/skill-reviewing-adversarially-*`: three that should fire, two that should stay quiet, one effect case each). Written, not run. ### Fixed - **English where the product showed Norwegian** (decision 56). The annotation page's intent buttons, sidebar badges and copied prompt read Fix / Change / Question; the stored keys stay `fiks` / `endre` / `spørsmål`, so annotations saved earlier still load. `/trekreview`'s project-memory approval offers "Add the line" / "Not now". README, CLAUDE.md, `docs/architecture.md`, `package.json` and `plugin.json` describe what the product shows. The Norwegian hollow-answer list in `approval-log.mjs` and `/trekbrief` stays: it matches what a user types. - **The brief validator sees a criterion the runner cannot run** (trial-5 finding 1). When a success criterion's first backticked span is not a command but a later span is, the validator now warns `BRIEF_SC_NOT_RUNNABLE`, as the criteria runner already reported it unrunnable. A criterion that only names a flag or a path stays prose and unflagged (Handover 1 says so). - **A re-planned step no longer builds on its earlier attempt's files** (trial-5 finding 4). `On failure: revert` leaves a step's new files on disk; `--resume` after a new plan now runs `lib/util/park-attempt-files.mjs` before the fresh build helper. It moves every still-untracked file the attempt created into the git directory (`voyage/parked/step-N-attempt-k`), never deletes one, never overwrites a parked file, and exits 1 while a file the attempt made is still in the tree. - **One reviewer's two findings on one triplet keep a row each** (trial-5 finding 7). Pass 1 merged two different `/code-review` findings on the same file, line and rule key, and the second lost its row and its action. A reviewer is never merged with itself: its second finding under another title stays its own row, with the id over `rule_key#2`, counted over the final list — also in `--workflow`, engine-findings and fidelity-diff. The decision-23 put-back stays one copy per triplet. ### Known issues The findings from the test repo's trial 5 that are not fixed in 6.5.0 (decision 59), grouped by consequence. **Too lax — can let through what should be stopped** - **Core code outside the deep-review patterns is never deep-reviewed** (trial-5 finding 9). `/trekreview` triage makes every file outside the deep-review patterns (for example `bin/` and `tests/`) summary-only, so code-correctness-reviewer gives no verdict on a CLI's core code; brief-conformance-reviewer still reads the whole diff. Planned for the fix round before v7 (decisions 57 and 58). **Too strict — can stop what should go on** - **A controller finding on a locked test line the plan gave has no way forward in the fix ladder** (finding 2). Fix rounds may not change a locked test (the one exception is a test not red at base), so rounds 1–3 repeat the same diff before the step goes up to the plan. - **The stop guard holds the session while it waits for the fix helper** (finding 3). Sub-step F sets the test lock to `pending` before a fix round; the `green` exception (operator decision 2026-10-08) covers only the wait for the controller. - **Phase 7.5 counts a re-approval of the plan as a stray commit** (finding 5). After the upward path the plan is approved again, but 7.5 lists only approvals from the review loop as process commits; read strictly, the run becomes partial and the merge into main stays closed. - **Plan dedup misses one finding reported by both plan reviewers when they cite it differently** (finding 6): an absolute and a relative path, another rule key, or overlapping line ranges, so one major is counted twice. - **`done-line.mjs --check --commit` with a short sha answers "no DONE line"** (finding 10), exit 1, though the line holds the full sha; Sub-step G only says `--commit {hash}`. **Inaccurate — wrong or unclear, nothing stopped or let through** - **Line numbers in review findings can be off** (finding 8). An engine finding cited the line after the code; `FINDING_LINE_OUT_OF_RANGE` catches only a line past the end of the file, and a patch line number written in a reviewer's prose, or `:135` with no file name, is not caught. - **With `--plugin-dir`, statistics go to the installed plugin's data directory** (finding 11): `stats-append` and `event-emit` write to `~/.claude/plugins/data/voyage-…`, so a development copy's statistics mix with the installed version's. - **`/trekplan` Phase 9 points the plan reviewers at their schema in `agents/plan-critic.md` and `agents/scope-guardian.md`** (finding 12), a path in Voyage outside the repo, in the same prompt that tells them to read only inside it. - **`/trekbrief`'s bounded budget is unclear** (finding 13): "8, the three fixed ones included" does not say whether the Phase 3.5 tier question counts, and Phase 3.5 puts the heuristic's proposal first as "(default)" even when the operator's own rule is to go up in doubt. - **`/security-review` diffs against the remote's default branch, not the review's range** (finding 14), so it can review more files than the review. In this release's review the opposite happened: the remote's `main` was ahead of `v6.4.0`, so the built-in diff missed the decision-56 commits, and its standard prompt was run over the whole range instead. The release review of 6.5.0 (`/trekreview` over `v6.4.0..main`, WARN: 0 BLOCKER, 13 MAJOR, 1 MINOR) found the following. None is a BLOCKER, so none opens a fix round before this release (decision 52). "Confirmed" means the release session reproduced it; "read" means it was traced in the code and not run. **Too lax — can let through what should be stopped** - **The park step can leave the earlier attempt's files in the tree and still exit 0** (the trial-5 finding-4 fix, `lib/util/park-attempt-files.mjs`). Confirmed: a file still registered with `git add --intent-to-add` (the revert was refused by the guard or declined) is read as "tracked since the attempt" and left in place; and an upward diff written under `color.ui=always` has no header the tool can read, so nothing is parked. Read: from a subdirectory the diff's paths are resolved against the wrong directory, and the tool's two `git` calls never check their exit status. - **On the opt-in `--workflow` path, the severity floor and the put-back read one row per file, line and rule key** (`scripts/trekreview-armB.workflow.mjs`), while the trial-5 finding-7 fix can now give two. Read: a finding can then be floored against the wrong row, or take an engine row's one legal lowering, and an engine row the coordinator did not return is not put back when its sibling was; a WARN can become ALLOW. The default path is not affected. - **Which row a finding joins can depend on the order the reviewers' payloads are read** (`lib/review/coordinator-contract.mjs`). Read: the same findings in another order can give other rows, severities and verdict. - **The coordinator dropped four engine findings as refuted because their line numbers lay past the end of the file.** The engine had cited positions in the diff; only the citation was checked, never the claim, and two of the four were confirmed true (the intent-to-add hole above and the brief warning below). Same class as trial-5 finding 8. - **No test holds a reviewer's Declined to Judge lines reaching `review.md`.** The copy-through in `/trekreview` and the coordinator is prose only; deleting it leaves the suite green. **Too strict — can stop what should go on** - **The brief validator's new `BRIEF_SC_NOT_RUNNABLE` warning fires on prose** (the trial-5 finding-1 fix). Confirmed: any bare word in a later backticked span counts as a command, so "`--verbose` prints the `login` field" is told to put `login` first. A warning, never an error. **Inaccurate — wrong or unclear, nothing stopped or let through** - **A finding's `#k` id depends on arrival order** (`lib/parsers/finding-id.mjs`), so the same finding can get another id in a second review; and a kept row can take the plain id that a set-aside row on the same triplet already carries. Read, not run. - **`/trekplan` tells the session to load `voyage:writing-criteria` by name but does not list the `Skill` tool in `allowed-tools`**, as `/trekbrief` now does. Whether Claude Code treats that list as a limit is not verified. - **The bake-off's arm A still merges each triplet to one row** (`scripts/bakeoff-armA-merge.mjs`, not changed in this release), so a fidelity measurement now shows an artificial gap; the grouping rule lives in three copies. - **A new eval scaffold has a non-ASCII character** (`evals/skill-writing-criteria-effect/scaffold.sh:42`, an em dash). ## v6.4.0 — 2026-10-17 — plan_version 1.9, the trial-4 findings, session-clean tests, the converging critic loop A new plan version, 1.9, in which every path in a step's `Files:` and on its `Test first:` `File:` line stands first, in backticks, so the reader no longer guesses paths from prose (decision 16). The same delivery closes the six findings from the test repo's trial 4 and stops `npm test` from pointing a live session's stop guard at a temp-repo lock. Every fix began with a test that failed on the code before it. Suite 2517 (2515 pass, 0 fail, 2 skipped), measured by `npm test` on the third remediation's Step 2 commit (`829da48`), the commit before this section. The converging critic loop came after that measurement (decisions 43 and 44). From round 2 the plan gate counts a critic round by rule A, and both reviewers state rule B. Suite 2602 (2600 pass, 0 fail, 2 skipped), measured by `npm test` on `main` at `4e28dc5`, the tree this release review covered. Nothing here asks anything of users. Older plans warn, they do not fail: a plan below 1.9 is read as in 6.3.1, apart from the fixes under Fixed, and gets one warning per step whose `Files:` names a path that is not backticked. ### Doors - two-way: plan_version 1.9 — a 1.9 plan read by 6.3.1 gets PLAN_VERSION_MISMATCH as a warning and the 6.3.1 reader, so a revert rewrites no plan. - two-way: Files reader (three 6.3.0 answers restored) — a revert brings back 6.3.1's answers; no file format changes. - two-way: the test files on the Test first File line are the backticked paths right after File: (operator decision 20) — a revert reads every path-shaped span again. - two-way: red proof checks --tests against the plan — a revert accepts any list again. - two-way: brief-conflict mark on review findings — an older verdict gate ignores the field. - two-way: review Pass 1 ranks by catalogue tier and a dropped duplicate never lowers its group — a revert restores the asserted-severity ranking. - two-way: the workflow review puts back every engine finding the coordinator did not return (operator decision 23) — opt-in path only; a revert restores the old floor. - two-way: approval commits require a Co-Authored-By trailer — only Voyage's own commands call the CLI, and they pass it. - two-way: explorer prompts, stamp order, test env — prose and test-side only. - two-way: a 1.9 wrapped line keeps its paths only after a comma (operator decision 29), and a File: line with nothing after it takes its first wrapped line — a revert joins every wrapped line again. - two-way: below 1.9 a test file after a note in brackets, and, plus or + is read when it is clearly a test (operator decision 28 and operator decision 31) — a revert reads only the run right after File: again. - two-way: red proof reads the step's test files from the plan, prints them, and refuses a plan it cannot read (operator decision 30) — the older prose that passes --tests still runs against it. - two-way: original_severity names what the kept finding asserted — only tests read the field. - two-way: the workflow review fails closed when its coordinator returns nothing, and names every reviewer that did not run in allow_blocked_by — opt-in path only. - two-way: below 1.8, when the plan names no test file, the helper and the executor give red proof the files the helper wrote (operator decision 41) — a revert leaves such a step unproven and unlocked. - two-way: rule A in the plan gate (decision 43) — an older gate ignores the new verdict fields, and a revert counts every round fully. - two-way: rule B and the security key in the reviewers (decision 43) — prose only; a revert restores the old rating. - two-way: plan dedup passes the reviewers' marks and rule-B fields through, and its two fixes — a revert drops the fields and brings back the line-0 collapse and the crash. - two-way: the post-compact hook test's timeout (decision 44) — test-side only. - two-way: the critic-loop matcher needs overlapping texts, and a new finding never takes an old id (operator decision 48) — a revert matches by id or line alone again. - two-way: plan dedup keeps a lowered_from that is not a severity (operator decision 48) — a revert counts it as no lowering again. - two-way: plan dedup ranks a merged pair by what rule B counts (operator decision 48) — a revert brings back the order-dependent merge. ### Added - **plan_version 1.9: the file first on every line.** Each entry of `Files:` and each `Test first:` `File:` line opens with its backticked path or paths; everything from the first other text on is description and is never read. A 1.9 plan that breaks this gets `PLAN_STEP_PATH_NOT_FIRST` or `PLAN_STEP_PATH_NOT_A_PATH` (errors under `--strict`, warnings without). The parser, the validator, the tests-only check, the plan-file sweep (K6) and red proof read a 1.9 plan by this grammar. 1.9 is the current target: Handover 4, the plan template, `/trekplan`, the planning orchestrator and CLAUDE.md say so, and the rules introduced at 1.8 say "1.8 or later". - **A warning for older plans.** Below 1.9, a path in `Files:` that is not backticked gets the warning `PLAN_STEP_PATH_UNTICKED`, under `--strict` too. - **The brief-conflict mark.** A `/code-review` finding at the MAJOR tier whose recommended action goes against a brief Non-Goal or another stated choice drops to MINOR, marked `contradicts_brief` and `brief_lowered_from: MAJOR`; any other engine finding only gets the mark, and a BLOCKER is never lowered. `/trekreview` passes the brief's choices to the coordinator, which writes the mark into `review.md`; the opt-in workflow review applies the same rule and floors an illegal lowering. On an ALLOW or WARN review the verdict gate answers exit 2 for a finding lowered or marked outside that one shape: `brief_lowered_from` on any other finding, a mark on a reviewer finding, a mark or an engine finding below its catalogue tier, or a mark with a missing or unknown rule key. - **The critic loop converges by rule A, counted by the plan gate** (decision 43). Round 1 is unchanged. From round 2 on, `plan-gate.mjs --diff` prints what changed since the text the last round reviewed. Both reviewers get it and mark each previous finding by id. Then `--record` counts the round: a new major that cites a plan line outside that diff counts as minor. A blocker, a security finding and a finding with no plan line count at full severity. A previous finding stays counted until it is marked resolved. The gate keeps each recorded round's text in the git directory, so a snapshot is never committed. A plan outside any git repository keeps none, and its next round counts fully. Every new verdict field is optional, and absent means round-1 behaviour, so an older verdict block gives the same exit codes. Phase 9, Handover 4, the planning orchestrator, CLAUDE.md and the README say so. - **Rule B in both reviewers** (decision 43). plan-critic and scope-guardian state it: a major that a named test, `Regression:` command or gate in the plan will fail on during execution is minor, never a blocker and never a security finding. The gate records each such lowering from round 1 on. Plan dedup passes the reviewers' marks and rule-B fields through. The operator answered three questions on 2026-10-15: rule B applies from round 1 and rule A from round 2; both reviewers tag a security finding with the review catalogue's security key; a lowered finding that is re-reported as major stays minor, and only a re-report as blocker counts as blocker. ### Fixed - **The suite no longer hands the session id to the lock CLI.** `npm test` preloads a helper that removes `CLAUDE_CODE_SESSION_ID` for the whole run, and every test that spreads the process environment into a child uses a shared helper without it. A live session's stop guard is no longer pointed at a temp-repo lock. A test file run on its own with `node --test` still passes the id to a child it starts without an `env` (release review). - **The three `Files:` regressions from 6.3.1's Known issues** give 6.3.0's answer again: a source file after a described test is kept, a path that a description only mentions is not read as a file, and a backticked bare name such as `LICENSE` alone on a following line is read as a file. - **The test files on the `Test first:` `File:` line** are the backticked paths that stand right after `File:`, separated only by commas or spaces, and below plan_version 1.9 also each further path after a note in brackets (`(new)`, `*(new)*`, `(existing …)`) or after `and`, `plus` or `+`, as long as it is clearly a test (operator decision 28, 13.10, and operator decision 31, 14.10; review `bd2520b0`). Every one of them is read, locked and copied for red proof, not only the first. A path in the description after them is no test file, at every plan_version (operator decision 20, 12.10; review `6c31212c`), so a step whose `File:` line names its source in the description is no longer read as tests-only. - **A 1.9 `Test first:` names its test only on a line that opens with `File:`**, the way the executor, K6 and red proof read it. Below 1.9 the check reads as before. - **Engine provenance in the review.** Ingest takes `engine` from the payload, never from a field a reviewer wrote on its own finding, and dedup ranks by catalogue tier, so a reviewer-agent finding is kept over an engine finding, and the kept finding carries the group's highest severity, in the coordinator's Pass 1 and in the workflow dedup. A brief-conflict mark can no longer lower a reviewer's MAJOR (operator decision 2026-10-12). On the workflow path, floor (b) and the put-back of every engine finding the coordinator did not return (both below) hold the same line after the coordinator answers. - **Explorers and reviewers stay in the repo.** `/trekplan` tells its brief-reviewer, the eight Phase 5 explorers, the Phase 6 deep-dives, the plan-critic and the scope-guardian to read local files only inside the repo under exploration plus the paths their prompt gives, and every explorer gets the brief. - **The brief review stamp covers only text the reviewer saw.** For a `small` brief, the reviewer's gaps are written after the stamp, so the stamp reads stale and `/trekplan` reviews the brief once more. - **Approval commits carry the caller's Co-Authored-By trailer.** `artifact-commit.mjs` takes `--trailer` and refuses (exit 1, before anything is staged or committed) a missing, multi-line or malformed trailer, an unfilled `{model}`, and one that names a session link. `/trekbrief`, `/trekplan` and `/trekexecute` pass it; `/trekexecute` prints the reason and goes on when the approval is logged but not committed. - **A list joiner no longer ends the read of a plain path below 1.9.** In `Files:`, a `+`, `&`, `and` or `or` between backticked paths is no word of description, so a plain path after them is read as a file again, as 6.3.1 read it, and a step of two tests joined by `+` and a plain source is not tests-only (review `182ceb93`). - **A 1.9 entry keeps the paths of a line wrapped after a comma, and a numbered `File:` line names its test.** A line that is no list item keeps its paths only after a comma, when the entry so far ends with one (operator decision 29, 14.10; reviews `d21ff81e`, `eaeb398e`), so a `Files:` list wrapped after a comma names every file: the step is not tests-only, and K6 plans the second file too. Otherwise that line, and every later wrapped line of the entry, is description and never read. A `File:` line with nothing after it takes its first wrapped line. The `Test first:` `File:` line may open with `-`, `*`, `+`, `1.` or `1)`, and any list item ends it (reviews `b4fa1927`, `4b6460e5`). - **A 1.9 plan refuses placeholders and mixed-case bare names as files** (operator decision 22, 13.10; review `33f37f53`). A leading backticked span that is a placeholder (`none`, `TBD`, `TODO`, `TBA`, `N/A`, `NA`, `...`, in any case) or a bare name that is neither in capitals nor a build file, such as the mixed-case `Parser`, is `PLAN_STEP_PATH_NOT_A_PATH`, and its hint says to write `./Name` for such a file. `LICENSE`, `README` and `Makefile` stay files; below 1.9 nothing changes. - **The engine of a payload is read from an own property.** Ingest no longer gives the findings of a payload whose reviewer is named `toString`, `constructor`, `__proto__` or another name `Object.prototype` carries an `engine` (it gave them a function or an object), and `toReviewerPayload` refuses an engine named `toString` with its "engine must be one of" error (review `3799ea6c`). - **Pass 1 ranks by catalogue tier, and a duplicate never lowers its group.** Of findings with the same `(file, line, rule_key)`, the coordinator's Pass 1 and `dedupByTriplet` keep the one with the higher catalogue tier, then a reviewer-agent finding over an engine finding, then the higher asserted severity, then the `brief-conformance-reviewer` finding, then the first seen, and write the kept finding at the highest severity its group asserted. Before, a marked code-review MAJOR beat a reviewer's MINOR on the same triplet and the review came out ALLOW; now it is WARN (review `bc7f4e23`; the coordinator's prose, operator decision 24). - **The workflow review puts back every engine finding the coordinator did not return** (operator decision 23, 13.10; reviews `ab1b5d9f`, `bc7f4e23`). On the opt-in workflow path, dedup ranks as Pass 1 does, and every engine finding with no returned finding at its exact `(file, line, rule_key)` is put back at its own severity, one per triplet (the higher-severity copy when two share it), so dropping, moving or relabelling an engine finding no longer lowers the verdict. Beside it, floor (b): a returned finding is never below the lower of its reviewer counterpart's severity and its catalogue tier (for a key outside the catalogue, the counterpart's severity). The workflow path is now stricter than the default path (see Known issues). - **An approval trailer with a blank or padded name is refused.** `artifact-commit.mjs` refuses a trailer whose name is empty or only spaces, or that holds two spaces in a row, so an empty `{model}` ("Claude" and two spaces) fails as the module header promises. A name with a parenthesis, such as "Claude Opus 5.5 (1M context)", is still accepted (review `8420915b`). - **The plan validator parses each step once.** `validatePlanContent` reads a step's fields once and every check, `--steps-from` included, reads them from there; its errors and warnings are unchanged (review `93382464`). - **Red proof reads the step's test files from the plan and prints them, and the executor defines them once** (review `cf241526`; operator decision 30, 14.10; reviews `793fc1aa`, `09ae46d8`, `d01df508`, `11ee78c5`). With `--plan` and `--step`, `red-proof.mjs` reads the step's test files from the plan as decision 20 and, below 1.9, decision 31 set them, and prints the list it ran as `tests` (a `tests:` line in text mode). The helper and the executor pass no `--tests`, and the lock's `--files` is that printed list. A `--tests` that names another set is exit 2 with a reason that starts `tests-mismatch` and the plan's list in `plan_tests`; a plan or step it cannot read is exit 2 with a reason that starts `plan-unreadable`, and the executor corrects its own call; a step whose plan names no test file reads as before. `commands/trekexecute.md` defines the step's test files in one sentence the other places point to. - **The `/trekbrief` pass branch names no `## Brief Quality`, and the stats rows span their blocks** (operator decision 21, 12.10). That section belongs to the exhausted and force-stopped branches only. In `tests/fixtures/jsonl-schemas.md` the `line_ref` of the trekbrief, trekplan and trekreview stats rows runs from the phase heading to the closing fence of its stats-append block, and a test pins all four command rows (trekexecute's too) by exact equality. - **`original_severity` names what the kept finding asserted** (review `08deae68`). When Pass 1 raises a finding to its duplicate group's severity, Pass 3 writes `original_severity` from the finding's own severity, and only when that differs from its catalogue tier; the carrier field `pass1_raised_from` never leaves the contract. - **The workflow review fails closed when its coordinator returns nothing** (review `edf2ec56`). A coordinator that returns no verdict and findings counts as a missing reviewer: the merged findings are read at their catalogue tier or higher (never lowered), the verdict starts at WARN (a BLOCK stays BLOCK), and every reviewer, engine and coordinator that did not deliver is named in `allow_blocked_by` as `missing-reviewer:`, so the verdict gate exits 2 on such a WARN. - **K6 keeps its own normaliser and `LIST_ITEM` is one literal again** (operator decision 27, 13.10; review `7961a700`). The two `/simplify` edits that crossed the first remediation's fence around K6 are reverted. - **The control-run test leaves headroom over a slow start** (review `703d87e1`). Under full-suite load the start-point run of red proof's control-run test was killed at its 2 s timeout. The test now gives red proof a 15 s timeout and starts every run but the control slowly on purpose, so a timeout without headroom fails on demand; the numbers live in `tests/helpers/timing.mjs`. - **Below 1.8 a plan that names no test file gets the files the helper wrote** (review `7b3b59ed`; operator decision 41, 14.10). A `File:` line below 1.8 may name its test without backticks, so red proof reads no test file from the plan and answers `no test files given`. The helper then runs the same red proof again with `--tests` naming the files it wrote, and the executor gives red proof that same list, so such a step is proven and locked. - **The post-compact hook test survives a slow start** (decision 44). Its hook child had a fixed 5 s timeout and was killed under full-suite load. The timeout now comes from `tests/helpers/timing.mjs`, and a killed hook child reads as a failure instead of exit 0. - **Plan dedup keeps distinct file-level findings apart, and no longer crashes on a bad field** (decision 43). Findings of one rule key on line 0 or with no line no longer collapse into one. An empty `file` or a `line` that is not a whole number no longer crashes the finding id; the line becomes null and the finding stands. - **The critic loop no longer folds a new finding into an old one by its id or line alone** (reviews `4ab24b07`, `d03835c4`; operator decision 48, 16.10). - What happened: an equal id or the old finding's line was enough. The new text was lost, and a new file-level major could count as an old rule-B minor. - Now the texts must overlap, a finding with a plan line is never matched by id, and a new finding never takes an old finding's id. - **A `lowered_from` that is not a severity now counts as blocker** (reviews `8782602b`, `ebe164e2`; operator decision 48, 16.10). It was read as no lowering. A blank one is still no lowering. - **Plan dedup no longer lets reviewer order lower a blocker** (review `69c9cebd`; operator decision 48, 16.10). - A merge keeps the copy rule B counts highest, on the merged keys. - This also covers a blocker claim merged into a plain major, found during this round. ### Known issues - The session split reads a 1.9 plan as an older plan (operator answer 3). - Marked MINOR findings still feed `recurrence` / project-memory proposals. - The default review path's verdict gate does not compare `review.md` with the engine payloads, so only the opt-in workflow path puts an engine finding the coordinator did not return back (operator decision 23). The operator made that check a separate delivery later (operator decision 25, 13.10). - Below 1.9 the plan-file sweep (K6) keeps its own wider reader of the `File:` line (operator 2026-10-11): it plans every backticked path on that line, also one in the description that decision 20 no longer counts as a test file. - Red proof accepts a `--tests` that matches the plan's list and prints it in the spelling it was given, not the plan's (review `2d624b54`; deferred by operator decision 42, 14.10). - `ingest` keeps a `pass1_raised_from` and an `original_severity` that a payload wrote on its own finding (reviews `c06d5385`, `e031a480`; deferred by operator decision 42, 14.10). - When its coordinator returns nothing, the workflow review raises the merged findings in place; this has no effect on its output today (review `6ff82e75`; deferred by operator decision 42, 14.10). - A whitespace-only line ends a 1.9 `Test first:` `File:` entry but not a `Files:` entry, to be skipped in both by operator decision 40 (review `4b6460e5`; deferred by operator decision 42, 14.10). The same id stands in a Fixed bullet above, which fixed the list-item case of that review; the whitespace-only case came back open. - A 1.9 wrapped line read as description is dropped without a warning, even when it opens with a backticked path, to be warned on by operator decision 39 (review `4e1607cb`; deferred by operator decision 42, 14.10). - Handover 4's `Files:` bullet words its empty-entry rule as for a `File:` line (review `4f22b101`; deferred by operator decision 42, 14.10). - Accepted deviation: the 1.9 `File:` selector repeats the list-marker set of `LIST_ITEM` (review `4dce7c74`; operator decision 38, 14.10, decision 27 stands). - The line diff's LCS table has no size bound. A rewritten gap of tens of thousands of lines takes seconds to minutes and gigabytes, and can end outside exit 0/1/2. Real plans measure about 1,200 lines (review `8a9b5a17`; deferred by operator decision 48, 16.10). - A previous finding re-reported on its own edited line is counted twice. Such a re-report of a lowered finding counts at its full severity (review `8004ea85`; deferred by operator decision 48, 16.10). - A `line` sent as a numeric string (`"42"`) is read as no line and counted at full severity. The agent templates give `line` as a number (review `c257625e`; deferred by operator decision 48, 16.10). - `npm test` does not run `tests/e2e-critic-diff-mode.sh`. It runs under `## Verification` and in `/trekreview`'s success-criteria check (review `818b1346`; deferred by operator decision 48, 16.10). - The matcher's residual (review `4ab24b07`; operator decision 50, 16.10): a previous finding marked resolved by every raiser and re-reported in other words (content overlap below 0.7) on an unchanged line is a new finding, which rule A can lower to minor. The same holds for a re-report in the same short words (fewer than 6 content words) away from the previous finding's place. - A short new finding at a previous finding's place is matched to it when all its content words appear in the old text: the overlap is measured against the shorter text, and the place clause has no word floor. The new text is lost, and the old finding's severity is counted, a rule-B minor included (review `ea8c1752`; deferred by operator decision 51, 16.10). - In a merge of three or more copies, a copy's rule-B claim that ties on the keys merged so far is dropped. When the security key arrives with a later copy, reviewer order still decides between minor and major (reviews `436ade33`, `f9ba85e1`; deferred by operator decision 51, 16.10). - A `lowered_from` such as `"none"`, `"n/a"`, `false` or `0` counts as blocker, by design (fail-closed). A reviewer that writes one on a finding it did not lower turns a minor into a BLOCK (review `79d1dc97`; deferred by operator decision 51, 16.10). - The rule that a blank `lowered_from` is no lowering lives only in plan dedup. A `--record` input that bypasses dedup with `lowered_from: ""` counts as blocker (review `2e7afd61`; deferred by operator decision 51, 16.10). - When the plan has not changed since the previous round, the gate counts the round fully, and a previous finding that no reviewer reports again leaves the count without being marked resolved. This predates the critic loop's diff mode (review `4c340d4a`; deferred by operator decision 51, 16.10). - A near-duplicate merge in plan dedup keeps only the survivor's place, so rule A can lower a new major in the changed text to minor when its partner cites an unchanged line, and the round can record PASS. 6.3.1 counted that merge major (review `ef1633b6`; deferred by operator decision 52, 16.10). - Below 1.9, regression A's restored reading also takes a plain slash path that a description only mentions after a comma (`` `tests/a.test.mjs` — covers the parser, lib/parse.mjs stays as is ``). 6.3.1 read only the test file; now the step is no longer tests-only, and the validator warns `PLAN_STEP_PATH_UNTICKED` on the mentioned path (review `38a8ad34`; deferred by operator decision 52, 16.10). - The verdict gate's brief-lowering check compares severities in upper case only, so an engine finding written `"severity": "major"` reads as an illegal lowering and the gate exits 2 (fail-closed) (review `20b626e2`; deferred by operator decision 52, 16.10). - The opt-in workflow review's floor raises an illegally lowered or marked reviewer finding but keeps its `brief_lowered_from` and `contradicts_brief`, so the verdict gate still exits 2 on that review (fail-closed) (review `c614baad`; deferred by operator decision 52, 16.10). ## v6.3.1 — 2026-10-11 — Fixes from the release review of 6.3.0, and two verdict-gate holes closed Rounds 7 to 10 of the release review of 6.3.0. Round 7 is the WARN 6.3.0 was released with, round 8 was BLOCK (1 BLOCKER), rounds 9 and 10 were WARN. Every fix began with a test that failed on the code before it. Suite 2236 (2234 pass, 0 fail, 2 skipped). Nothing here asks anything of users. Measured against 6.3.0 over the marketplace and the test repo: the plan validator reports the same errors and warnings for all 233 plan files, the verdict gate gives the same exit for all 123 review files, and tests-only reads the same for all 1408 plan steps. ### Doors - two-way: tests-only is decided by the plan's `Files:` alone, and red proof no longer reads the step's diff (operator decision 2026-10-11) — a revert brings the diff check back; plans stay valid. - two-way: the `Files:` reader keeps a plain file beside a backticked path, reads numbered entries, and keeps a description together across commas and lines — it feeds only the `PLAN_STEP_TESTS_ONLY` warning and red proof's `tests_only`; a revert restores the 6.3.0 reading. - two-way: a trailing `# comment` is dropped from a backticked check too, so such a check now runs; one whose comment holds a double quote, `$`, a backtick or a backslash is refused out loud — 6.3.0 refused every backticked check with a comment, so nothing that ran stops running. - two-way: the verdict gate reads the last fenced block once and answers exit 2 unless its info string is exactly `json`, or when it is never closed; a `~~~` fence is a fence — a review written by `/trekreview` reads as before; a revert reopens the two holes under Fixed. - two-way: stops and timeouts, the release check's `--review`, `isMain` in every CLI, the test lock's command comparison, one fence reader, and cleanups — fixes; a revert restores the old behaviour. ### Fixed - **Two verdict-gate holes, present in 6.3.0.** A review that ended with a clean json block and then a block holding a BLOCK verdict, written as `~~~json` or opened with more text after `json` on its line, passed with exit 0: the gate did not see the second block. Both are exit 2 now. - **Tests-only steps.** The plan's `Files:` alone decides, and red proof, `/trekexecute`, `step-implementer` and the handover contract say so. A change already in the tree when the step began no longer counts against it, and a plan outside `.claude/` reads the same. - **The `Files:` reader** keeps a plain file beside a backticked path (", Dockerfile", "and Makefile"), reads a numbered entry (`1.` or `1)`) as an entry, keeps a description together past a comma and onto the next line, and starts a description at a plain file followed by a colon. Lowercase `makefile`, `rakefile` and `justfile` are build files. - **Checks with a comment.** A trailing `# comment` is dropped in a backticked check and in a command passed as written, so the words screened are the words run. A comment with a double quote, `$`, a backtick or a backslash is refused instead, because the executor hands the `Verify:` span to red proof, the test lock and the done line inside double quotes. Every reader refuses it out loud (`PLAN_VERIFICATION_NOT_RUNNABLE`, `BRIEF_SC_NOT_RUNNABLE`). A span that is only a comment is not-a-command. - **Stops.** Red proof reports a command killed by its timeout as killed after the timeout, not "could not start". The release check tells a timeout from output past its buffer and from another signal. One reading of a stop (`stoppedBy`) serves red proof, the criteria runner, the test lock, the done line and the release check. - **Release check.** A relative `--review` is read in `--repo`, or from the current directory when only that one exists. Two different files are exit 2, never guessed, and one file reached through a symlinked `--repo` is one file. - **Every CLI uses one `isMain` helper.** Before, some did nothing and exited 0 when run through a symlink or a path with a space. - **Test lock.** It compares `--cmd` by its words and without its trailing comment. - **One fence reader** for the gate and every reader of a trailing json block. A fence closes only on a run at least as long as its opener, as in Markdown, and CRLF and an indented fence read alike everywhere. A fence indented four spaces or more still counts, on purpose: Markdown's rule made a BLOCKER block inside a list item invisible. - **Cleanups.** The 15-minute timeout is defined once, the findings check reads each cited file once per validation, and the guard writes its no-one-to-ask refusal once. ### Known issues Round 11 of the release review (`0f400d3..10ac9c5`) is WARN: 0 BLOCKER, 10 MAJOR, 0 MINOR. All ten come from Claude Code's `/code-review`, which gives no category, so each enters as MAJOR. Voyage's two reviewers and `/security-review` found none. The operator chose to release 6.3.1 with it (2026-10-11). None of the ten lets a gate pass. The regressions below were checked by running them against 6.3.0. None of them occurs in the 1408 plan steps measured above. - The `Files:` reader still guesses paths from prose and misreads in both directions. Two misreads are regressions from 6.3.0: - A source file after a described test is dropped ("`tests/a.test.mjs` - new test, src/a.mjs - the fix"). The step that builds code then reads as tests-only and goes to the plan. - A path that a description only mentions is read as a file ("covers the parser in src/parse.mjs"). A step of only tests is then not caught and goes through fix rounds (at most five, then the operator). Red proof has no diff check behind the reader. The structural fix is to require every path in `Files:` to be backticked. It changes the plan contract and is left for a planned release. - A json block closed on the same line as its JSON is no longer read (a regression from 6.3.0). The gate answers exit 2, and a reviewer is asked again. An opener with a blank before `json` is not json either, as in 6.3.0. - A trailing comment with a double quote, `$`, a backtick or a backslash is refused in every backticked check. That includes checks that never reach a shell: a `## Verification` bullet, `Regression:`, `End-to-end:` and a brief criterion. 6.3.0 refused these too. - Cleanups: a dead branch for a span that is only a comment, the comment dropped up to four times per command, a re-export of the timeout that nothing imports, and a test helper that copies a PATH lookup. - An engine run that was stopped and not counted in the verdict reported three more, each checked by running: - A backticked bare name such as `LICENSE`, alone on a line after a description, is no longer read as a file. 6.3.0 read it. - One unclosed fence earlier in a review hides the review's own json block from the review validator. 6.3.0 found the block, and the gate answers exit 2 there. - An indented json example after a review's own block is read as the last block, as in 6.3.0. - The example plan's steps 1-2 keep their tests-only warning (operator decision 2026-10-09). ## v6.3.0 — 2026-10-11 — The executor is coupled to the review gate, three skills, and a drilled release runbook Wave 2 of the practice build (five orders, merged 2026-10-09) and the fix round after it, which closes finding 1 of the test repo's third trial: a step of only tests can never be proven red. Every fix began with a test that failed on the old code. Suite 2194 (2192 pass, 0 fail, 2 skipped). Two changes ask something of users (see Doors): `/trekexecute` now refuses a plan that has no logged approval for its current content, and a check in a brief or plan runs with no shell, as plain words with a runner's read-only options. Plan 1.7/1.8, brief 2.0–2.2 and review 1.0/1.1 files still validate; the new step fields are optional. ### Doors - one-way: `/trekexecute` refuses a plan whose logged approval does not cover its current sha256 (K2) — a plan written before 6.2.0, written by hand, or edited after its approval stops at Phase 1; run `/trekplan --project ` and answer "Approve" (from 6.3.0). - two-way: `/trekexecute` reviews by itself in the closing run (`/simplify` → `/trekreview` → verdict gate, K7) and keeps the main merge closed on BLOCK or an undecided verdict; step check (K9), `Regression:` (K10), architecture rules (K5) and plan-file sweep (K6) run at step end and after the last step — a revert restores the old executor; nothing to do for users. - two-way: the approval guard refuses a merge into main, a push, a tag or publish and destructive git in the permission mode that shows no prompts — a revert lets them through again; nothing to migrate. - two-way: `progress-validator` rejects the runner's `exitCode` in `plan_verification.failed_criteria` (C15) — the executor's own prose always wrote `exit_code`. - two-way: skills workshop — form check, model-free routing test, `test-first` and `debugging` preloaded into `step-implementer` — new files and one `skills:` line; a revert removes them. - two-way: `researching-sources` skill, preloaded by the five web-search agents and named by `/trekresearch` — the agents' copied rule text moved into the skill; a revert puts it back. - two-way: `Regression:` (K10) and `On failure:` action words (K11) — an optional field and a warning; plans without them validate as before. - two-way: trial 2's minor fixes (B8, B11, B12, C13, C14, C16, C17) — checks, prose and agent text; a revert restores the old behaviour. - two-way: release check and runbook — new files; a revert removes them, and nothing else reads them. - two-way: tests-only steps (`PLAN_STEP_TESTS_ONLY`, red-proof `--plan/--step` → `tests_only`, which also reads the step's own diff, executor routes them to the plan) — a warning and an optional flag; a revert removes them, plans stay valid. - two-way: timing tests under load (hook helper kill limit 30 s, SC #14 fastest of three against 800 ms) — test-only. - two-way: example plan `On failure:` lines open with a K11 word, and its verbose-content test moves into the step that wires the output (6 steps, progress.json follows) — text in an example. - two-way: `/trekreview` saves the reviewer's whole answer for the findings check and names `FINDING_PROSE_LINE_OUT_OF_RANGE` — command text. - two-way: the criteria runner's commands run without `NODE_TEST_CONTEXT` — a false green under `node --test` is now red; nothing to do for users. - two-way: the fixes from the release review of 6.3.0 (rounds 1-6) — checks and prose; `progress.json` may now say `simplify: "revert-refused"` (an optional value); a revert restores the old behaviour. - one-way: a check in a brief or plan (criteria, `Regression:`, proof of red, the done line, the test lock) runs with no shell: its words reach the runner as written, so only plain words run (no quote, backslash, `$`, brace, or `~`/`@` at a word's start; a glob only for `node --test` on Node 21 and later; no path that climbs out with `..` or starts at `/`, git included; a trailing `# comment` in a shell fence is dropped) with a short list of read-only options per runner — git without `--output` or `--no-index`, `node --test` with a built-in `--test-reporter` only, nothing after `make test`, only paths after `npm test --`; an option that writes a file or loads code is refused — a criterion that used one (`git log --grep="x"`, `pytest -k foo`, `pytest tests/test_*.py`, `jest --coverage`, `go test -timeout 30s`) is now NOT RUN at review and not runnable on a 1.8 plan; wrap it in `bash tests/