docs(changelog): the review remediation, decisions 20, 22 and 23, with door lines

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-13 19:28:58 +02:00
commit d7db590c26
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
2 changed files with 153 additions and 9 deletions

View file

@ -11,9 +11,9 @@ A new plan version, 1.9, in which every path in a step's `Files:` and on its
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 2381 (2379 pass, 0 fail, 2 skipped),
measured by `npm test` on Step 13's commit (`acd0e3d`), the commit before this
section.
failed on the code before it. Suite 2459 (2457 pass, 0 fail, 2 skipped),
measured by `npm test` on the remediation's Step 13 commit (`5b94952`), the
commit before this section.
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
@ -23,8 +23,11 @@ warning per step whose `Files:` names a path that is not backticked.
- 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: every test file on the Test first File line — a revert reads the first file only again.
- 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.
@ -63,16 +66,25 @@ warning per step whose `Files:` names a path that is not backticked.
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.
- **Every test file on the `Test first:` `File:` line** is read, locked and
copied for red proof, not only the first.
- **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 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 on a severity tie
the reviewer-agent finding is kept over the engine finding, in the
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).
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
@ -87,11 +99,88 @@ warning per step whose `Files:` names a path that is not backticked.
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 on its wrapped lines, and a numbered `File:`
line names its test.** A line that is no list item continues the entry above
it, so a `Files:` list wrapped after a comma names every file: the step is
not tests-only, and K6 plans the second file too. The `Test first:` `File:`
line may open with `-`, `*`, `+`, `1.` or `1)`; a wrapped line joins it, 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 checks the test list against the plan, and the executor defines
the step's test files once** (review `cf241526`). With `--plan` and
`--step`, `red-proof.mjs` reads the step's test files from the plan as
decision 20 sets them: a `--tests` that names another set is exit 2 with a
reason that starts `tests-mismatch` and the plan's list in `plan_tests`;
without `--tests` the plan's list is used; 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: after a `tests-mismatch`
the executor reruns red proof once with `plan_tests`, and a second exit 2 is
read as the exit-2 row says. `step-implementer` reruns the same way, and its
lock's `--files` is the list red proof accepted.
- **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.
### 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.
## v6.3.1 — 2026-10-11 — Fixes from the release review of 6.3.0, and two verdict-gate holes closed

View file

@ -288,3 +288,58 @@ test('CHANGELOG: the Unreleased section\'s Known issues name the session split',
const known = lines.slice(start + 1, end).join('\n');
assert.match(known, /session split/, `Known issues name the session split: ${JSON.stringify(known)}`);
});
// Step 14 of the remediation: the CHANGELOG records the review fixes. The door
// line for the Test first files names operator decision 20 (the backticked paths
// right after File:), the workflow put-back names operator decision 23, the
// engine-provenance entry states the tier rank instead of "on a severity tie",
// Known issues name the default path's verdict gate (operator decision 25), and
// the intro's measurement names the remediation's Step 13 commit. Word
// boundaries keep "operator decision 2026-10-12" from counting as decision 20.
const knownIssues = (body) => {
const lines = body.split('\n');
const start = lines.findIndex((l) => /^### Known issues\s*$/.test(l));
assert.ok(start >= 0, 'the Unreleased section has a "### Known issues" heading');
let end = lines.length;
for (let i = start + 1; i < lines.length; i++) {
if (/^###? /.test(lines[i])) { end = i; break; }
}
return lines.slice(start + 1, end).join('\n');
};
test('CHANGELOG: the door lines name operator decisions 20 and 23, and none says "every test file on the Test first File line"', () => {
const { heading, body } = firstChangelogSection();
assert.equal(heading, UNRELEASED);
const texts = releaseCheck.parseDoors(body).entries.map((e) => e.text);
assert.ok(texts.some((t) => /\boperator decision 20\b/.test(t)),
`a door line names operator decision 20: ${JSON.stringify(texts)}`);
assert.ok(texts.some((t) => /\boperator decision 23\b/.test(t)),
`a door line names operator decision 23: ${JSON.stringify(texts)}`);
assert.ok(!texts.some((t) => /every test file on the Test first File line/.test(t)),
`no door line still says "every test file on the Test first File line": ${JSON.stringify(texts)}`);
});
test('CHANGELOG: the Unreleased section no longer says "on a severity tie"', () => {
const { heading, body } = firstChangelogSection();
assert.equal(heading, UNRELEASED);
assert.doesNotMatch(body, /on\s+a\s+severity\s+tie/);
});
test('CHANGELOG: Known issues name the verdict gate, the engine payloads and operator decision 25', () => {
const { heading, body } = firstChangelogSection();
assert.equal(heading, UNRELEASED);
const known = knownIssues(body);
assert.match(known, /verdict\s+gate/, `Known issues name the verdict gate: ${JSON.stringify(known)}`);
assert.match(known, /engine\s+payloads/, `Known issues name the engine payloads: ${JSON.stringify(known)}`);
assert.match(known, /\boperator\s+decision\s+25\b/, `Known issues name operator decision 25: ${JSON.stringify(known)}`);
});
test('CHANGELOG: the intro no longer names acd0e3d and names the remediation\'s Step 13 commit', () => {
const { heading, body } = firstChangelogSection();
assert.equal(heading, UNRELEASED);
const firstSub = body.search(/^### /m);
const intro = firstSub < 0 ? body : body.slice(0, firstSub);
assert.ok(!intro.includes('acd0e3d'), `the intro no longer names acd0e3d: ${JSON.stringify(intro)}`);
assert.match(intro, /the\s+remediation's\s+Step\s+13\s+commit/,
`the intro names "the remediation's Step 13 commit": ${JSON.stringify(intro)}`);
});