Skip to content

fix loop: stateless-between-runs overcorrects on anchoring — persist reviewer verdicts, not diffs #57

@ooloth

Description

@ooloth

Background

The fix loop is intentionally stateless between runs: when a stalled issue is retried, the next run starts completely fresh with no memory of what was tried or why it failed. The original reasoning was sound — showing a new agent what was previously attempted risks anchoring it to the prior approach, producing minor variations of the same wrong solution rather than fresh thinking.

This issue argues that the design overcorrects, and identifies a more precise cut.

The Inconsistency

Within a single run, the implement→review→redraft loop already passes reviewer feedback to the implement agent on round 2+. That is anchoring too — it's accepted as necessary for iteration to work. Statelessness between runs prevents cross-run anchoring but not within-run anchoring. It's a half-measure.

The Key Distinction

Anchoring risk is not symmetric across what you pass:

Prior diff → high anchoring risk. The agent sees the specific approach taken and iterates on it rather than reconsidering from first principles. Even when told to think fresh, it tends toward variations on what it sees.

Prior reviewer verdict → low anchoring risk, high signal value. "The previous attempt was rejected because it changed the public API surface" is a constraint, not a prior viewpoint. It tells the agent what to avoid without prescribing an approach. This is the same quality of signal the within-run loop already passes — the original design suppressed it across runs without justification.

Proposed Behavior

When the fix loop picks up an issue that has a prior stalled run:

  1. Read persisted state: branch name + structured reviewer verdict from the last run
  2. Seed the implement step with: "A prior attempt was stalled. The reviewer rejected it for this reason: [structured verdict]. The branch already exists and reflects what was tried — you may read it, but you are not required to continue from it."
  3. Continue on the existing branch rather than creating a new one

The agent gets the failure mode without the prior solution being handed to it. It can inspect the branch if useful, ignore it if it wants to think fresh. The reviewer verdict is information; the prior diff is an anchor.

What to Persist

Per issue, in a state file written by the fix loop after each run:

{
  "branch": "fix/issue-42",
  "last_reviewer_verdict": {
    "approved": false,
    "feedback": "...",
    "round": 3
  }
}

Not persisted: the prior diff. The agent can read the branch directly if it wants to understand what was already implemented. Fresh read, no anchoring to change sequence.

Implementation

The state file lives in .logs/ keyed by project and issue number rather than by run timestamp — a prerequisite reorganization worth tracking separately. The fix loop reads state on entry and writes it on exit regardless of outcome.

Relationship to #54

Issue #54 addresses within-run degradation: the implement agent on round N+1 receives only a summary of reviewer feedback rather than the full structured output. That issue explicitly calls cross-run persistence out of scope. This issue is the cross-run counterpart — same root insight, different scope.

Both issues point toward the same resolution: pass structured reviewer output verbatim, at every boundary where the implement agent re-enters.

Definition of Done

  • Fix loop reads a per-issue state file on entry; if present, seeds the implement prompt with the prior reviewer verdict and branch name
  • Fix loop writes the state file on exit (success or failure), including the final reviewer verdict and branch name
  • The implement prompt template has a conditional section for "prior attempt context" that is omitted on round 1 of a fresh run
  • Existing behavior (fresh runs with no prior state) is unchanged
  • Decision documented in docs/decisions/ with rationale for verdict-not-diff choice

Out of Scope

  • Persisting the prior diff (deliberately excluded — see above)
  • Shared agent sessions across runs
  • Cross-run context for scan or groom loops

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestscope:agentClaude subprocess wrapper, transcript, timeoutscope:fixFix loop, implement, review, PR opening

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions