docs(review): stop rule in the plan loop, review loop and critic prompts (decision 217, 220)
/trekplan Phase 9: when --record or the gate reports the stop rule there
is no new round; AskUserQuestion with the class and counts, "Known issue"
(--accept-open, a security finding refused) or "New mechanism" (stop, the
plan stays unapproved); the round-3 blocker path never offers
--extra-round after the stop rule. Phase 10 prints round of
max_rounds + extra_rounds.
/trekexecute Phase 7.2 step 4: after a round-2 BLOCK or fixed-pending,
before any R-step, review-rounds.mjs prepare --dry-run; review-stop-rule:
gives the same question ("Known issue" = /trekreview --answers, a BLOCKER
keeps the merge locked; "New mechanism" = stop). /trekreview Phase 3 tells
the stop rule's exit 1 from the cap's. plan-critic and scope-guardian:
rule_key names the class, never the instance.
New pins in review-loop-docs, critic-severity-rules and review-prose-pins.
Part 1, step 1.4 of the E plan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
6b44be4c43
commit
08e8aa1c66
8 changed files with 134 additions and 12 deletions
|
|
@ -61,6 +61,11 @@ for (const rel of AGENTS) {
|
|||
assert.ok(t.includes("A security finding uses the catalogue's security `rule_key`"));
|
||||
});
|
||||
|
||||
test(`${rel}: [STP] rule_key names the class, never the instance (the stop rule's class, decision 217)`, () => {
|
||||
const t = norm(read(rel));
|
||||
assert.ok(t.includes('`rule_key` names the class, never the instance'), `${rel} must say rule_key names the class, never the instance`);
|
||||
});
|
||||
|
||||
test(`${rel}: round 2+ lists every previous finding by id and cites the exact line`, () => {
|
||||
const t = norm(read(rel));
|
||||
assert.ok(t.includes('From round 2 the prompt gives you the diff since the last reviewed text'), `${rel}: round-2 diff sentence missing`);
|
||||
|
|
|
|||
|
|
@ -138,3 +138,32 @@ test('Handover 4 states the overlap match and the distinct id', () => {
|
|||
assert.ok(h4.includes('only on overlapping text'), 'Handover 4 says the gate matches "only on overlapping text"');
|
||||
assert.ok(h4.includes('`<rule_key>#n`'), 'Handover 4 names `<rule_key>#n`');
|
||||
});
|
||||
|
||||
// ---- [STP] the stop rule (E plan, Part 1 step 1.4; decisions 217, 220) ----------------
|
||||
|
||||
const P10 = flat(phase(read('commands/trekplan.md'), 10));
|
||||
|
||||
/** Phase 9's stop-rule paragraph: from its bold lead to the next bold lead that opens a line. */
|
||||
function stopPart() {
|
||||
const at = P9.indexOf('**The stop rule**');
|
||||
assert.ok(at >= 0, 'Phase 9 has a **The stop rule** paragraph');
|
||||
const next = P9.indexOf('**After round 3', at);
|
||||
return P9.slice(at, next < 0 ? undefined : next);
|
||||
}
|
||||
|
||||
test('[STP] Phase 9: the stop rule gives no new round and asks Known issue or New mechanism, never one more round', () => {
|
||||
const s = stopPart();
|
||||
for (const want of ['stop_rule.fired', 'PLAN_GATE_STOP_RULE', 'no new round', 'AskUserQuestion',
|
||||
'**Known issue**', 'plan-gate.mjs --accept-open', 'PLAN_GATE_SECURITY_OPEN',
|
||||
'**New mechanism**', 'the plan stays unapproved', 'the direction goes to the operator']) {
|
||||
assert.ok(s.includes(want), `the stop-rule paragraph says ${JSON.stringify(want)}`);
|
||||
}
|
||||
assert.doesNotMatch(s, /\*\*One more round\*\*/, 'the stop-rule question has no "One more round" option');
|
||||
assert.ok(P9.includes('never offers `--extra-round` after the stop rule'),
|
||||
'the round-3 blocker path says it never offers --extra-round after the stop rule');
|
||||
});
|
||||
|
||||
test('[STP] Phase 10 prints the round of max_rounds + extra_rounds', () => {
|
||||
assert.ok(P10.includes('**Critic rounds:** {round} of {max_rounds + extra_rounds}'), 'Phase 10 prints round of max_rounds + extra_rounds');
|
||||
assert.ok(!P10.includes('**Critic rounds:** {N} of {max}'), 'the old "{N} of {max}" is gone');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -338,3 +338,27 @@ test('[DPR] /trekreview Phase 4 says a changed instruction file at any depth, do
|
|||
assert.ok(lines.includes('| `summary-only` | `docs/**`, Markdown files at the repo root other than `CLAUDE.md` and `AGENTS.md` (README, CHANGELOG), `tests/fixtures/**`. |'),
|
||||
'Control: the summary-only row is unchanged');
|
||||
});
|
||||
|
||||
// ---- [STP] the stop rule in the review rounds (E plan, Part 1 step 1.4; decisions 217, 220) ----
|
||||
|
||||
test('[STP] /trekreview Phase 3 tells the stop rule\'s exit 1 from the cap\'s', () => {
|
||||
const p3 = flat(section(CMD, '## Phase 3 — Discover scope SHA range'));
|
||||
assert.ok(p3.includes('`review-stop-rule:`'), 'Phase 3 names the review-stop-rule: reason');
|
||||
assert.ok(p3.includes('`review round cap reached`'), 'Phase 3 names the cap reason');
|
||||
assert.ok(p3.includes('Known issue') && p3.includes('New mechanism'), 'Phase 3 names the two recommendations');
|
||||
});
|
||||
|
||||
test('[STP] /trekexecute Phase 7.2 step 4 runs prepare --dry-run after a round-2 BLOCK, before any R-step, and asks Known issue or New mechanism', () => {
|
||||
const p72 = flat(section(read('commands/trekexecute.md'), '## Phase 7.2 — Simplify, review, verdict (P11)'));
|
||||
const cmd = 'review-rounds.mjs prepare --project "{project_dir}" --since {session_start_sha} --repo . --dry-run --json';
|
||||
const at = p72.indexOf(cmd);
|
||||
assert.ok(at >= 0, `Phase 7.2 runs ${cmd}`);
|
||||
const loop = p72.indexOf('**A BLOCK is fixed by new plan steps');
|
||||
assert.ok(loop > at, 'the dry-run check comes before the loop adds any R-step');
|
||||
const part = p72.slice(at, loop);
|
||||
for (const want of ['`review-stop-rule:`', 'AskUserQuestion', '**Known issue**', '/trekreview --answers',
|
||||
'the review is still current', 'a BLOCKER keeps the merge locked', '**New mechanism**', 'no R-step is added']) {
|
||||
assert.ok(part.includes(want), `the stop-rule paragraph says ${JSON.stringify(want)}`);
|
||||
}
|
||||
assert.doesNotMatch(part, /one more round/i);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue