docs(changelog): fix round 4.5b

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-26 18:02:58 +01:00
commit ad053e0e0e
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
3 changed files with 143 additions and 4 deletions

View file

@ -9,7 +9,9 @@
// Untagged tests (prefixes `helpers:`, `step 25:`, `keep:`, `control:`,
// `arch:`, `e2e script:`, `red script:`, `CHANGELOG:`) are outside the
// round's id list; a `[M1r]` test carries a 4.5b id and is that round's to
// judge.
// judge. Fix round 4.5b edits some pins here in place where its fixes change
// the text they pin (for example the CHANGELOG siblings entry, K4): each keeps
// its tag or untagged prefix and still fails at ab6b32c.
// #23 code-correctness-reviewer cites a "MANDATORY OVERRIDE rule above"
// that is no longer there; the sentence says the rule itself.
// #24 research-scout says "Try Tavily first" but its tools held no Tavily
@ -1747,7 +1749,8 @@ const SIBLINGS_ENTRY = '- **The texts next to the fixes say the same** (siblings
+ '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 gates shim reads `--gates=true` as on.';
+ 'line; the commands read only the two-token `--gates <value>` form, and `--gates=true` is the gates shim\'s own form '
+ '(`lib/util/autonomy-gate.mjs`), which it reads as `--gates true`.';
test('CHANGELOG: ### Fixed holds the siblings entry, exactly', () => {
assert.ok(roundBullets('### Fixed').includes(SIBLINGS_ENTRY), '### Fixed has no siblings entry with the exact text');

View file

@ -48,6 +48,16 @@
// M1 No test name in the 4.5a prose file starts with `found in execution:`;
// the tests f6bdc2d added carry their 4.5a parent tag (red under the
// M1 mutation, which puts the names back).
// CHANGELOG (the round's entry in the existing Unreleased section):
// K4 the siblings entry says the commands read only the two-token
// `--gates <value>` form and that `--gates=true` is the gates shim's own.
// M4 the merge-lock entry says a failed git call is reported as
// `review-not-measured:`, not `review-stale`.
// M2 ### Fixed records the brief-conflict exception in the four `--quick`
// summaries.
// ARG ### Fixed names the Bash-guard block on a parser heredoc that closes
// early (R6), and ### Changed says `~` and `$HOME` in the arguments are
// no longer expanded.
// No static import of a new export: the file must load at be0b631.
// Fix the SOURCE a pin guards, not the pin.
@ -503,3 +513,90 @@ test('[M1] no test name in the 4.5a prose file starts with found in execution:',
const untagged = names.filter((n) => n.startsWith('found in execution:'));
assert.deepEqual(untagged, [], `${PROSE_4_5A} still names ${untagged.length} test(s) "found in execution:"`);
});
// --- K4 / M4 / M2 / ARG: the round's CHANGELOG entry --------------------------------
// The round's entry stands in the existing Unreleased section (no release lies
// between 4.5a and 4.5b). The section is found by its title, by the rule
// tests/helpers/changelog-section.mjs uses for the 6.4.0 delivery:
// `## Unreleased — <title>` before the release, `## vX.Y.Z — <date> — <title>`
// after it, exactly once, up to the next `## ` heading. The helper is bound to
// the 6.4.0 title, so its rule is repeated here for this section's title.
const CHANGELOG_TITLE = "The annotating skill, the run coupling and P10's model-free part";
const CHANGELOG_HEADING = new RegExp(`^## (?:Unreleased|v\\d+\\.\\d+\\.\\d+ — \\d{4}-\\d{2}-\\d{2}) — ${CHANGELOG_TITLE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`);
/** The lines of the round's CHANGELOG section, heading excluded. */
function changelogSection() {
const lines = read('CHANGELOG.md').split('\n');
const at = [];
lines.forEach((l, i) => { if (CHANGELOG_HEADING.test(l.replace(/\s+$/, ''))) at.push(i); });
assert.equal(at.length, 1, `CHANGELOG.md must hold the "${CHANGELOG_TITLE}" section exactly once (found ${at.length})`);
let end = lines.length;
for (let i = at[0] + 1; i < lines.length; i++) if (/^## /.test(lines[i])) { end = i; break; }
return lines.slice(at[0] + 1, end);
}
/** The bullets of one `### ` subsection of the round's CHANGELOG section, each flattened to one line. */
function changelogBullets(heading) {
const lines = changelogSection();
const s = lines.findIndex((l) => l.replace(/\s+$/, '') === heading);
assert.ok(s !== -1, `the "${CHANGELOG_TITLE}" section of CHANGELOG.md must have "${heading}"`);
const out = [];
for (const l of lines.slice(s + 1)) {
if (/^### /.test(l)) break;
if (/^- /.test(l)) out.push(l);
else if (out.length && l.trim() !== '' && /^\s/.test(l)) out[out.length - 1] += ` ${l}`;
else if (l.trim() !== '') out.push('');
}
return out.filter((b) => b !== '').map(flat);
}
test('[K4] the CHANGELOG names --gates=true as the shim\'s own form', () => {
const hits = changelogBullets('### Fixed').filter((b) => b.startsWith('- **The texts next to the fixes say the same**'));
assert.equal(hits.length, 1, `### Fixed must hold one siblings entry; found ${hits.length}`);
assert.ok(hits[0].includes('the commands read only the two-token `--gates <value>` form'),
`the siblings entry does not say the commands read only the two-token \`--gates <value>\` form: ${hits[0]}`);
assert.ok(hits[0].includes('`--gates=true` is the gates shim\'s own form'),
`the siblings entry does not name \`--gates=true\` as the gates shim's own form: ${hits[0]}`);
assert.doesNotMatch(hits[0], /the gates shim reads `--gates=true` as on\./,
`the siblings entry still ends on the gates shim reading \`--gates=true\` as on, which reads as a command form: ${hits[0]}`);
});
test('[M4] the Unreleased entry says review-not-measured for a failed git call', () => {
const hits = changelogBullets('### Fixed').filter((b) => b.startsWith('- **The merge lock refuses a review of an older commit**'));
assert.equal(hits.length, 1, `### Fixed must hold one merge-lock entry; found ${hits.length}`);
assert.doesNotMatch(hits[0], /a failed git call included/,
`the merge-lock entry still counts a failed git call among the \`review-stale\` reasons: ${hits[0]}`);
const said = sentencesWith(hits[0], 'failed git call');
assert.ok(said.some((s) => /a failed git call exits 2 with a reason that starts `review-not-measured:`, not `review-stale`/.test(s)),
`the merge-lock entry does not say a failed git call exits 2 with \`review-not-measured:\`, not \`review-stale\`: ${said.join(' | ') || hits[0]}`);
});
test('[M2] the Unreleased entry records the brief-conflict exception in the flag summaries', () => {
const hits = changelogBullets('### Fixed').filter((b) => b.includes('`--quick`') && b.includes('brief-conflict rule'));
assert.equal(hits.length, 1, `### Fixed must hold one entry on the \`--quick\` summaries and the brief-conflict rule; found ${hits.length}`);
assert.match(hits[0], /name the brief-conflict rule as the exception to the skipped reasonableness filter/,
`the entry does not say the summaries name the brief-conflict rule as the exception: ${hits[0]}`);
for (const where of ['`/trekreview`', 'the review orchestrator', '`docs/command-modes.md`', 'README']) {
assert.ok(hits[0].includes(where), `the entry does not name ${where} among the four summaries: ${hits[0]}`);
}
});
test('[ARG] the CHANGELOG names the Bash-guard block on a parser heredoc that closes early', () => {
const hits = changelogBullets('### Fixed').filter((b) => b.includes('`args-heredoc-closed-early`'));
assert.equal(hits.length, 1, `### Fixed must hold one entry naming \`args-heredoc-closed-early\`; found ${hits.length}`);
assert.ok(hits[0].includes('`hooks/scripts/pre-bash-executor.mjs`'), `the entry does not name the Bash guard's file: ${hits[0]}`);
assert.ok(hits[0].includes('`VOYAGE_ARGS_EOF_7F3C9E`'), `the entry does not name the heredoc's closing line: ${hits[0]}`);
assert.match(hits[0], /not the last non-empty line/, `the entry does not say when the guard blocks: ${hits[0]}`);
assert.match(hits[0], /\(R6\)/, `the entry does not carry the R6 mark: ${hits[0]}`);
});
test('[ARG] the CHANGELOG says ~ and $HOME in the arguments are no longer expanded', () => {
const hits = changelogBullets('### Changed').filter((b) => b.includes('`~`') && b.includes('`$HOME`'));
assert.equal(hits.length, 1, `### Changed must hold one entry on \`~\` and \`$HOME\`; found ${hits.length}`);
for (const cmd of ['`/trekendsession`', '`/trekcontinue`', '`/trekreview`']) {
assert.ok(hits[0].includes(cmd), `the entry does not name ${cmd}: ${hits[0]}`);
}
assert.match(hits[0], /are no longer expanded/, `the entry does not say they are no longer expanded: ${hits[0]}`);
assert.match(hits[0], /write the path out/, `the entry does not tell the reader to write the path out: ${hits[0]}`);
});