implement-loop quality re-loop oscillates to a false BLOCKED when a finding contradicts the ratified plan #10
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
The
implement-loopquality re-loop can exhaust its retry budget and emit afalse
BLOCKEDwhen a quality finding contradicts the ratified spec/plan —most sharply on a name the plan fixes. This cost a full implement-loop run
(~860s, 10 agents) that ended
BLOCKEDon a task whose code was objectivelygreen + clippy-clean + spec-faithful; the orchestrator had to verify the gates by
hand and overrule the gate to proceed. It will recur on any cycle whose plan
prescribes a public symbol name a reviewer would nitpick.
Problem
Observed in an aura cycle (plan task: a
TraceStore::ensure_name_freewrite-guard,a name fixed by the ratified spec/plan and the prescribed downstream callers):
quality-reviewerflags Minor: "ensure_name_freeimplies thename is unused, but
Okalso covers same-kind overwrite." (changes_requested)implementerwith that finding as the repair brief(
implement/workflows/implement-loop.js, the per-task spec/quality repairloops ~
:215+). The implementer "satisfies" it by renaming toensure_writable_name— i.e. deviating from the ratified plan.quality-reviewernow flags Minor: the rename "diverges fromspec/plan and the prescribed Task-2/3 callers ... won't compile against the
prescribed downstream callers. Reconcile end-to-end." (
changes_requested)"name is misleading" and "name diverges from the plan" until the retry cap →
review-loop-exhausted (quality)→BLOCKED.files_touchedends at theplan's value; the code was green the whole time.
Root gap: there is no path for a finding that contradicts the ratified
spec/plan to be rejected/held. The loop treats every
changes_requestedas"deviate to satisfy", but a ratified-design name (or any spec-fixed choice) must
be kept, with the finding recorded as a non-blocking concern — not chased into a
deviation that the next review then flags. Two plausible fixes:
quality-reviewer(implement/agents/quality-reviewer.md): a Minor findingwhose remedy would contradict the task's own prescribed code/names is a Nit at
most (Nits never gate) — i.e. do not gate on a name the plan fixes.
implement-loop.jsre-loop: when the implementer judges a finding contradictsthe ratified plan, let it return the task
DONEwith the finding attached as aconcern(surfaced in the end-report for the orchestrator to weigh) instead ofbeing forced to deviate. A finding that round-trips to "you diverged from the
plan" is the signal it should never have gated.
Severity is bounded (the orchestrator can verify gates and overrule), but the
failure wastes a full loop run and mis-reports a green task as
BLOCKED, which isexactly the kind of false verdict the gate's own instructions should prevent.
Implemented directly on
main(52db1ab). Design notes:Chose the issue's option 2 over option 1. Option 1 (downgrade a plan-fixed-name finding to a Nit inside
quality-reviewer) is not cleanly implementable: the quality-reviewer is deliberately blind to the task text (its Iron Law is QUALITY ONLY; it never reads the plan/task files — that is the spec-reviewer's domain). It therefore cannot know which names a plan fixes, so option 1 would have required breaching the two-reviewer separation. The plan knowledge lives with the implementer, which holds the task text — so the plan-vs-finding judgement belongs in the per-task quality re-loop + the implementer's repair brief, and generalises to any plan-prescribed name/signature/structure, not just names.What changed (
implement/workflows/implement-loop.js, plusimplement/agents/quality-reviewer.mdandimplement/SKILL.md):heldfield; the loop surfaces it as a concern instead of chasing a deviation. A finding the implementer judges correctness-breaking escalates to BLOCKED — never a silent hold.DONE_WITH_CONCERNS): theheldarray, and a no-op backstop over a now-requireddiff_fingerprint. Achanges_requestedverdict over an already-seen diff-state (tracked in a Set, so A-B-A edit-then-revert is caught too) means the repair was a no-op/cycle => re-running quality is futile => hold.implement/SKILL.mdStep 3 now routes a held/unresolved quality finding to orchestrator hand-verification before committing, even under/boss.Residual, disclosed: the held/no-op partition is the implementer's judgement, not enforced in code (the script cannot semantically verify a
helditem is truly cosmetic). The residual fail-open is bounded to cosmetic-on-green findings (the #10 class) and disclosed in the header; the orchestrator's Step-3 inspection is the backstop — the same trust placed in every other implementer self-report.Verification: three rounds of adversarial review. An early single-enum draft was rejected for still oscillating on the plain-DONE / BLOCKED held-the-plan paths and for an over-broad fail-open; the round-2 fix was rejected for an optional fingerprint and an A-B-A gap. The committed version passes all lenses sound, holes closed.
Closes on push.