docs(changelog): the second review remediation, decisions 27 to 31, with door lines
Review findings of S147; operator decisions 26 to 31. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f746f27788
commit
2cca61170a
2 changed files with 153 additions and 28 deletions
77
CHANGELOG.md
77
CHANGELOG.md
|
|
@ -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 2459 (2457 pass, 0 fail, 2 skipped),
|
||||
measured by `npm test` on the remediation's Step 13 commit (`5b94952`), the
|
||||
commit before this section.
|
||||
failed on the code before it. Suite 2508 (2506 pass, 0 fail, 2 skipped),
|
||||
measured by `npm test` on the second remediation's Step 8 commit
|
||||
(`f746f27`), 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
|
||||
|
|
@ -30,6 +30,11 @@ warning per step whose `Files:` names a path that is not backticked.
|
|||
- 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.
|
||||
|
||||
### Added
|
||||
|
||||
|
|
@ -68,11 +73,14 @@ warning per step whose `Files:` names a path that is not backticked.
|
|||
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 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.
|
||||
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.
|
||||
|
|
@ -104,11 +112,15 @@ warning per step whose `Files:` names a path that is not backticked.
|
|||
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
|
||||
- **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
|
||||
|
|
@ -151,17 +163,19 @@ warning per step whose `Files:` names a path that is not backticked.
|
|||
- **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.
|
||||
- **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
|
||||
|
|
@ -169,6 +183,21 @@ warning per step whose `Files:` names a path that is not backticked.
|
|||
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:<name>`, 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.
|
||||
|
||||
### Known issues
|
||||
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ test('CHANGELOG: the Unreleased section\'s Known issues name the session split',
|
|||
// 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
|
||||
// the intro's measurement names the second remediation's Step 8 commit. Word
|
||||
// boundaries keep "operator decision 2026-10-12" from counting as decision 20.
|
||||
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();
|
||||
|
|
@ -373,12 +373,108 @@ test('CHANGELOG: Known issues name the verdict gate, the engine payloads and ope
|
|||
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', () => {
|
||||
test('CHANGELOG: the intro names the second remediation\'s Step 8 commit, and no longer acd0e3d, 5b94952 or the 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)}`);
|
||||
assert.ok(!intro.includes('5b94952'), `the intro no longer names 5b94952: ${JSON.stringify(intro)}`);
|
||||
assert.doesNotMatch(intro, /the\s+remediation's\s+Step\s+13\s+commit/,
|
||||
`the intro no longer names "the remediation's Step 13 commit": ${JSON.stringify(intro)}`);
|
||||
assert.match(intro, /the\s+second\s+remediation's\s+Step\s+8\s+commit/,
|
||||
`the intro names "the second remediation's Step 8 commit": ${JSON.stringify(intro)}`);
|
||||
});
|
||||
|
||||
// Second remediation, Step 9: the CHANGELOG records round 2. Door lines name
|
||||
// operator decisions 29, 30 and 31; the Fixed bullets that name `b4fa1927`,
|
||||
// `6c31212c` and `cf241526` follow decisions 29, 31 and 30; three new Fixed
|
||||
// bullets name `08deae68`, `edf2ec56` and `7961a700` (operator decision 27).
|
||||
// Each bullet is read on its own with bullet(): the CHANGELOG's bullets have no
|
||||
// blank line between them. Phrases are looked for with runs of whitespace
|
||||
// read as one space, so a phrase wrapped over two lines still counts.
|
||||
const oneSpace = (text) => text.replace(/\s+/g, ' ');
|
||||
|
||||
test('CHANGELOG: door lines name operator decisions 29, 30 and 31, none bad, and the decision-29 line says "takes its first wrapped line"', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const d = releaseCheck.parseDoors(body);
|
||||
assert.deepEqual(d.bad, [], 'every top-level door line reads "- one-way: ..." or "- two-way: ..."');
|
||||
const texts = d.entries.map((e) => e.text);
|
||||
for (const re of [/\boperator decision 29\b/, /\boperator decision 30\b/, /\boperator decision 31\b/]) {
|
||||
assert.ok(texts.some((t) => re.test(t)), `a door line matches ${re}: ${JSON.stringify(texts)}`);
|
||||
}
|
||||
const d29 = texts.filter((t) => /\boperator decision 29\b/.test(t));
|
||||
assert.ok(d29.some((t) => /takes\s+its\s+first\s+wrapped\s+line/.test(t)),
|
||||
`the door line naming operator decision 29 says "takes its first wrapped line": ${JSON.stringify(d29)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: the section names 08deae68, edf2ec56 and operator decision 27', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
assert.ok(body.includes('08deae68'), 'the Unreleased section names 08deae68');
|
||||
assert.ok(body.includes('edf2ec56'), 'the Unreleased section names edf2ec56');
|
||||
assert.match(body, /\boperator decision 27\b/, 'the Unreleased section names operator decision 27');
|
||||
});
|
||||
|
||||
test('CHANGELOG: the b4fa1927 bullet follows operator decision 29', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const b = bullet(body, /b4fa1927/, 'Fixed bullet b4fa1927');
|
||||
assert.match(b, /\boperator decision 29\b/, `the b4fa1927 bullet names operator decision 29: ${JSON.stringify(b)}`);
|
||||
assert.ok(b.includes('4b6460e5'), `the b4fa1927 bullet names 4b6460e5: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /only\s+after\s+a\s+comma/, `the b4fa1927 bullet says "only after a comma": ${JSON.stringify(b)}`);
|
||||
assert.match(b, /takes\s+its\s+first\s+wrapped\s+line/, `the b4fa1927 bullet says "takes its first wrapped line": ${JSON.stringify(b)}`);
|
||||
const flat = oneSpace(b);
|
||||
assert.ok(!flat.includes('a wrapped line joins it'), `the b4fa1927 bullet no longer says "a wrapped line joins it": ${JSON.stringify(b)}`);
|
||||
assert.ok(!flat.includes('keeps the paths on its wrapped lines'),
|
||||
`the b4fa1927 bullet no longer says "keeps the paths on its wrapped lines": ${JSON.stringify(b)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: the 6c31212c bullet names operator decision 31 below 1.9 and keeps decision 20 at every plan_version', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const b = bullet(body, /6c31212c/, 'Fixed bullet 6c31212c');
|
||||
assert.match(b, /\boperator decision 31\b/, `the 6c31212c bullet names operator decision 31: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /\bplus\b/, `the 6c31212c bullet names plus: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /separated\s+only\s+by\s+commas\s+or\s+spaces,\s+and\s+below\s+plan_version\s+1\.9/,
|
||||
`the 6c31212c bullet qualifies "separated only by commas or spaces" below 1.9: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /at\s+every\s+plan_version\s+\(operator\s+decision\s+20\b/,
|
||||
`the 6c31212c bullet keeps "at every plan_version (operator decision 20": ${JSON.stringify(b)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: the edf2ec56, 08deae68 and 7961a700 bullets say what was fixed', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const e = bullet(body, /edf2ec56/, 'Fixed bullet edf2ec56');
|
||||
assert.match(e, /allow_blocked_by/, `the edf2ec56 bullet names allow_blocked_by: ${JSON.stringify(e)}`);
|
||||
assert.match(e, /catalogue\s+tier\s+or\s+higher/, `the edf2ec56 bullet says "catalogue tier or higher": ${JSON.stringify(e)}`);
|
||||
const o = bullet(body, /08deae68/, 'Fixed bullet 08deae68');
|
||||
assert.match(o, /own\s+severity/, `the 08deae68 bullet says "own severity": ${JSON.stringify(o)}`);
|
||||
assert.match(o, /pass1_raised_from/, `the 08deae68 bullet names pass1_raised_from: ${JSON.stringify(o)}`);
|
||||
const k = bullet(body, /7961a700/, 'Fixed bullet 7961a700');
|
||||
assert.match(k, /\boperator decision 27\b/, `the 7961a700 bullet names operator decision 27: ${JSON.stringify(k)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: the cf241526 bullet follows operator decision 30', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const b = bullet(body, /cf241526/, 'Fixed bullet cf241526');
|
||||
assert.match(b, /\boperator decision 30\b/, `the cf241526 bullet names operator decision 30: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /pass\s+no\s+`--tests`/, `the cf241526 bullet says the callers pass no \`--tests\`: ${JSON.stringify(b)}`);
|
||||
assert.match(b, /decision\s+20\s+and,\s+below\s+1\.9,\s+decision\s+31/,
|
||||
`the cf241526 bullet says "decision 20 and, below 1.9, decision 31": ${JSON.stringify(b)}`);
|
||||
assert.match(b, /printed\s+list/, `the cf241526 bullet names the printed list: ${JSON.stringify(b)}`);
|
||||
assert.ok(b.includes('plan-unreadable'), `the cf241526 bullet names plan-unreadable: ${JSON.stringify(b)}`);
|
||||
assert.ok(b.includes('tests-mismatch'), `the cf241526 bullet names tests-mismatch: ${JSON.stringify(b)}`);
|
||||
assert.doesNotMatch(b, /as\s+decision\s+20\s+sets\s+them/, `the cf241526 bullet no longer says "as decision 20 sets them": ${JSON.stringify(b)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: the old rerun wording is gone from the Unreleased section', () => {
|
||||
const { heading, body } = firstChangelogSection();
|
||||
assert.equal(heading, UNRELEASED);
|
||||
const flat = oneSpace(body);
|
||||
for (const phrase of ['reruns red proof once with `plan_tests`', 'reruns the same way', 'the list red proof accepted']) {
|
||||
assert.ok(!flat.includes(phrase), `the Unreleased section no longer says "${phrase}"`);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue