feat(gate): stop rule in the plan gate (decision 217, 220)
recordVerdict appends each round's summary to a new optional verdict field `rounds` (carried from the previous verdict; newByClass null for a round counted in full) and stores `stop_rule`; extractVerdict shape-checks both. After a fired stop rule --record exits 1 with PLAN_GATE_STOP_RULE and writes nothing (--extra-round included). The bare gate stops with PLAN_GATE_STOP_RULE and the operator line in place of the open-blocker and open-major reasons; --json and --record output carry the decision. --accept-open after a fired stop rule is allowed with rounds left, covers open blockers and majors (`under: "stop-rule"`), refuses a counting security finding (PLAN_GATE_SECURITY_OPEN); the gate then warns. Known issue fixed: REVIEW_LOG_SECTIONS drops "Adversarial Pass 2 (v5.1.1 high-effort)"; the CHANGELOG known-issue line closes and Handover 4 names the heading list, the new fields and codes. Existing tests updated for the planned rule: fixtures that ran a later round after one with no fewer blocking findings now use a falling count (plan-gate.test round cap, plan-gate-open-major lastRound, diff-mode 5/18/27 resolve two earlier majors in round 2); the diff-mode CLI pipe case now expects PLAN_GATE_STOP_RULE (round 3: 2 blocking) after its clean round 2. Part 1, step 1.2 of the E plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7e09edb24f
commit
a576391e28
7 changed files with 448 additions and 32 deletions
|
|
@ -172,8 +172,12 @@ test(`--record counts rounds; round ${MAX_ROUNDS + 1} needs the operator's extra
|
|||
assert.equal(MAX_ROUNDS, 3);
|
||||
let text = buildPlan();
|
||||
assert.equal(rec(text, dedupOut(), { extraRound: true }).code, 2, '--extra-round within the cap is refused, not banked');
|
||||
// A falling count of blockers (3, 2, 1), so the stop rule (lib/review/stop-rule.mjs,
|
||||
// "not fewer") never fires and the cap is what refuses round 4.
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
const r = rec(text, dedupOut(finding('blocker', `still broken ${i}`)));
|
||||
const blockers = Array.from({ length: 4 - i }, (_, k) => finding('blocker', `still broken ${i}.${k}`));
|
||||
const r = rec(text, dedupOut(...blockers));
|
||||
assert.equal(r.verdict?.stop_rule?.fired, false, `round ${i}: the stop rule does not fire on a falling count`);
|
||||
assert.equal(r.code, 0, r.message);
|
||||
assert.equal(r.verdict.round, i);
|
||||
text = r.text;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue