Skip to content

Attempt whose only residue is the spec's own frontmatter flip still pauses for manual rollback #123

Description

@pbean

Follow-up from #109 (split out of PR #122, which fixes the root cause for the Claude adapter).

Problem

When a dev session dies early — before writing any code — the working tree's only divergence from the attempt baseline is often the spec file's own 2-line frontmatter flip (status: ready-for-dev → in-progress), written by the skill as its first act. On the retry decision with the default scm.rollback_on_failure = false + isolation = "none", that flip counts as attempt dirtiness, so _rollback_or_pause pauses the run with the manual-recovery notice instead of retrying.

For the operator this reads as "the loop keeps needing manual rollback / hitting git trouble" when nothing of value would be lost by resetting: the residue is a file whose lifecycle the orchestrator itself owns, and the retry re-drives it from ready-for-dev anyway.

Where it lives

Engine._rollback_or_pause (engine.py): the dirty check excludes the orchestrator-owned artifact folders (_protected_relpaths() — output/implementation/planning) only on the resolved-redrive path:

protected = self._protected_relpaths() if redrive else ()
if task.baseline_commit and not verify.attempt_dirty(..., exclude=protected):
    self.journal.append("rollback-skipped-clean", ...)
    return

A plain stopped/crashed attempt passes exclude=(), so the spec flip alone is enough to trigger the pause.

Design notes / cautions

  • This deliberately interacts with rearm/baseline semantics (the re-arm paths strip stale ## Auto Run Result sections; the resolved-redrive carve-out exists precisely so a corrected spec doesn't read as a failed attempt). Any relaxation needs to keep those invariants.
  • Scope question: exclude the full protected folders on the plain path too, or only the dispatched story's own spec file? The narrow version (spec-file-only diff → auto-restore + rollback-skipped-clean-style journal entry) is the safer shape: a session that wrote real code into an artifact folder should still pause.
  • Stories mode: the spec folder ([stories] spec_folder) is user-chosen and not necessarily inside _protected_relpaths() — the carve-out needs to cover the id-keyed story spec path as well.
  • Whatever resets/keeps the flip must leave the retried session's read-back deterministic: the next attempt's synthesize_result must not mistake leftover state for this session's output (mtime launch-floor already guards the read side).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions