compiler-driven-edit returns DONE on a no-op edit (verdict vacuously true on a clean tree) #11
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
A
compiler-driven-editrun returnedstatus: DONE("behaviour-preservingedit verified; edits unstaged in the working tree for the orchestrator to
commit") when no edit had been made at all — the working tree was
completely clean. Only the orchestrator's own post-run tree inspection
(
git statusempty, the target crate absent, the source file unchanged)caught that the reported DONE was vacuous. An orchestrator that trusted the
verdict and proceeded to "commit the unstaged changes" would have committed
nothing under a DONE banner, or — worse, in a less careful run — concluded the
work shipped. The done-signal must not be satisfiable by doing nothing.
Problem
implement/workflows/compiler-driven-edit.jsPhase 3 (Verdict):The conjunction
build_clean && suite_green_unchangedis vacuously true onan empty edit. When the Phase-1 edit agent no-ops — in the observed run it
made 2 tool calls (just the standing reads), then returned
{build_clean: true, hole_needs_decision: false, sites: 0}without touchingany file — Phase 2 runs against a clean tree and correctly reports
suite_green_unchanged: true(its own detail field even said so: "Workingtree is completely clean … there is no edit in the working tree to verify").
Phase 3 then reads that as DONE. The verdict cannot distinguish "a
behaviour-preserving edit was applied and the suite stayed green" from "no
edit was applied, so of course nothing changed".
The Phase-1
EDIT_SCHEMAalready carriessites, and the workflow has accessto whether the working tree differs from HEAD, but neither is used as a
precondition for DONE. A guard is missing: the verdict should require positive
evidence that an edit actually landed (a non-empty
git diff HEAD, orsites > 0) before concluding DONE; an empty working tree after the editphase is a failed / no-op edit, not a behaviour-preserving success, and should
surface as a distinct non-DONE status (e.g. a BLOCKED/
infra-style "editproduced no changes" rather than a silent green).
Secondary, related trigger worth noting for whoever fixes this: the no-op was
provoked by handing the arm a task outside its shape — a crate extraction
(scaffold a new crate + move definitions), whereas the Phase-1 prompt is
verb-shaped entirely around "propagate MECHANICALLY across every site the
build flags — let the type checker enumerate the edit sites". A
create-and-move has no "type checker enumerates sites" framing for the
create part, and the agent appears to have resolved that mismatch by doing
nothing and reporting
sites: 0. Even if the arm is meant only for in-placetype/signature edits (not crate scaffolding), the vacuous-DONE guard is still
needed — a no-op edit of any cause should never read as DONE.
Fixed in
89cc4bb(closes on push)The done-signal now requires positive evidence that an edit landed, checked at two independent points:
applied_changes— ground truth fromgit status --porcelain/git diff HEAD, not intent. No hole + clean tree -> distinctBLOCKED(kind: no-op-edit), so we don't run a full suite against an empty tree.DONEnow also conjoins the verify agent's independentworking_tree_dirty. The verify agent never sees the edit agent's self-report, so even a falseapplied_changes: trueon a clean tree is caught. A green build+suite over a clean tree routes to the sameBLOCKED, not todebug-- a clean tree is no regression, so there is nothing to reproduce RED-first.Design decisions worth recording
sites > 0. A legitimate behaviour-preserving edit can touch only the definition site and have the compiler flag zero propagation sites (sites: 0) while still dirtying the tree. Gating onsites > 0would false-reject that. Tree-diff is ground truth: a real edit always dirties the tree (we never commit), a no-op never does -- so it separates DONE from no-op exactly. (Also fixed: the DONE note coerced a legitimatesites: 0tonullvia|| null; now?? null.)BLOCKEDreason names that re-route hint, so the orchestrator sees why the arm produced nothing.Adversarial review
An independent reviewer traced every
return:closes_hole: true(no script-logic path returns DONE on a clean tree -- undefinedworking_tree_dirtyalso fails safe toward non-DONE),false_negative_risk: false(thesites: 0legitimate edit still reaches DONE). Verdict: SOUND. The only residual DONE-on-clean-tree exposure requires the verify agent to actively misreportworking_tree_dirty: true-- an agent-honesty failure, not a script hole.A sibling scan turned up the same anti-pattern elsewhere (notably
implement-loop.js, whoseDONEhas no positive-evidence precondition and even computesfiles_touchedbut never asserts it> 0). Filing those as separate follow-ups; they are out of scope for this issue.