[Bugfix #870] Wire up max_iterations as safety ceiling; treat COMMENT and REQUEST_CHANGES asymmetrically#871
Merged
Merged
Conversation
… and REQUEST_CHANGES asymmetrically Before this fix, getMaxIterations() in porch/protocol.ts was exported but had zero callers — every verdict-handling decision ignored the per-phase max_iterations config. The rebuttal-exists branch in next.ts also unconditionally advanced the phase even when reviewers had returned REQUEST_CHANGES, so the rebuttal cycle was effectively one-shot. Per the policy adopted on the issue: - ADVANCE on no REQUEST_CHANGES (all APPROVE-or-COMMENT). Already handled by allApprove() in verdict.ts:57; this commit adds a regression test for the asymmetry. - RE-ITER on any REQUEST_CHANGES — no count limit in normal flow. The rebuttal-exists branch now increments state.iteration and clears build_complete so the next porch-next emits a fresh build task carrying the previous reviews + rebuttal as context. - SAFETY CEILING via getMaxIterations(). When state.iteration >= max_iterations and REQUEST_CHANGES persists, porch force-advances, records a force_advanced audit entry on status.yaml, and prepends a clear notice to the next task's description. The latest rebuttal file is preserved on disk as the audit trail. Defaults adjusted accordingly: - Default safety ceiling in protocol parsing bumped from 1 → 8 (runaway prevention, not a normal-flow cap). - SPIR and ASPIR protocol.json per-phase max_iterations bumped from 1 → 8 so build-verify cycles can re-iter on REQUEST_CHANGES. - PIR left at max_iterations: 1 — its docs explicitly require a single advisory pass; the new wiring makes that semantic correct (REQUEST_CHANGES on iter 1 hits the ceiling and force-advances). Tests cover the three acceptance cases: - all-APPROVE-or-COMMENT → advance (no rebuttal task emitted) - REQUEST_CHANGES + rebuttal + below ceiling → re-iter (iter increments, build_complete cleared, no force_advanced) - REQUEST_CHANGES + rebuttal at ceiling → force-advance, audit trail on status.yaml, ceiling notice on task description, rebuttal file preserved Fixes #870
Contributor
Author
|
Approving for merge — your dual-CMAP unanimous APPROVE earlier covered this thoroughly, and the asymmetric COMMENT/REQUEST_CHANGES policy is exactly the right answer for the data the reporter shared. Please merge with |
# Conflicts: # packages/codev/src/commands/porch/types.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #870
Root cause
getMaxIterations()inpackages/codev/src/commands/porch/protocol.ts:403was exported but had zero callers — porch ignored the configured per-phase cap on every verdict-handling decision. The rebuttal-exists branch innext.tsalso unconditionally advanced the phase even when reviewers had returnedREQUEST_CHANGES, so the rebuttal cycle was effectively one-shot. The phantom comment atnext.ts:617-618referencing a "max_iterations safety valve" pointed at code that had never landed.Fix
Adopts the asymmetric policy proposed on the issue.
COMMENTis a non-blocking note, not a change-request:REQUEST_CHANGES(allAPPROVE-or-COMMENT). Already handled byallApprove()inverdict.ts:57(COMMENTwas already counted as approve); this PR adds an explicit regression test for the asymmetry so future refactors do not silently regress it.REQUEST_CHANGES— no count limit in normal flow. The rebuttal-exists branch now incrementsstate.iterationand clearsbuild_completeso the nextporch nextemits a fresh build task carrying the previous reviews + rebuttal as context.getMaxIterations(). Whenstate.iteration >= max_iterationsandREQUEST_CHANGESpersists, porch force-advances, records aforce_advancedaudit entry onstatus.yaml, and prepends a clear notice to the next task's description. The latest rebuttal file is preserved on disk as the audit trail.The natural-experiment data cited on the issue (21 review iterations classified post-hoc) showed iteration-count is a poor signal —
52%of iters caught real bugs,24%wereCOMMENT-cycling. A per-iter cap missed bugs that surfaced at iter-3, iter-4. The new policy keeps re-iter responsive to verdicts (which DO carry signal) and reservesmax_iterationsfor runaway prevention only.Defaults
1→8(protocol.ts:228).max_iterationsbumped from1→8so build-verify cycles can re-iter onREQUEST_CHANGES.max_iterations: 1— its documented "single advisory pass" semantic is now mechanically enforced (REQUEST_CHANGESon iter 1 hits the ceiling and force-advances). BUGFIX/AIR are unaffected (their PR consultations areonce-type phases, notbuild_verify).Behavioral diff vs. before this PR
APPROVEAPPROVE+COMMENTREQUEST_CHANGES, no rebuttal yetREQUEST_CHANGES+ rebuttal,iter < ceilingREQUEST_CHANGES+ rebuttal,iter >= ceilingforce_advancedaudit + ceiling noticeTest Plan
next.test.tsrebuttal/advance tests still pass (max=1 protocol → iter=1 hits ceiling, force-advance path lands at same gate_pending response as before).advances when reviewers return only COMMENT verdicts (no REQUEST_CHANGES)— asymmetric policy explicit.re-iters when rebuttal exists and iteration is below the safety ceiling— confirms iter increments, build_complete cleared, no force_advanced.force-advances with audit trail when REQUEST_CHANGES persists at the safety ceiling— confirms force_advanced state field, ceiling notice on task, rebuttal preserved on disk.CMAP Review
3-way consultation (Gemini, Codex, Claude) via
consult --protocol bugfix --type pr:Reviewers independently confirmed: (a) the fix correctly wires up the previously dead
getMaxIterationsas a safety ceiling, (b) the asymmetric COMMENT vs REQUEST_CHANGES policy matches the superseding policy from the issue's follow-up comment, (c) regression tests cover all three code paths (advance, re-iter, force-advance), (d) scope is tight, no debug code, no stray TODOs, (e) the existing rebuttal-advance test still passes because the test fixture'smax_iterations: 1puts iter=1 at the ceiling, producing the samegate_pendingoutcome through the new force-advance path. Reviews saved tocodev/projects/bugfix-870-porch-max-iterations-enforceme/.