Skip to content

fix(status): hide stale incomplete-turn recovery after workspace cleanup #421

Description

@moncher-dev

Problem

gh-symphony repo status can keep reporting a "Recoverable incomplete turn" after the associated issue workspace has already been removed.

Observed local state:

  • status.json still contains recovery.kind = "incomplete-turn-dirty-workspace".
  • The recovery workspacePath points to a deleted repository directory.
  • The run record is still preserved with status = "suppressed" and recovery != null.
  • The issue workspace record has status = "removed" and its repositoryPath no longer exists.
  • gh-symphony repo recover --dry-run --json returns [], so the status output advertises a recovery that the recovery command cannot act on.

This makes repo status look actionable even though the recovery context is stale.

Root cause

This appears to be an Observability Layer bug crossing the Execution Layer workspace lifecycle boundary:

  • cleanupTerminalIssueWorkspace() removes the issue workspace and marks the workspace record as removed, while intentionally preserving run records.
  • buildProjectSnapshot() derives snapshot.recovery from allRuns only.
  • findLatestRecovery() suppresses stale recovery after a later recovery run completes, but it does not know whether the workspace backing the recovery has since been removed.
  • repo status renders snapshot.recovery without validating that the workspace still exists or is still active.

Proposed fix

Prefer keeping run records immutable/preserved, and make the status snapshot smarter:

  1. Pass issue workspace records into buildProjectSnapshot() or otherwise provide a resolver for recovery workspace state.
  2. Treat an incomplete-turn-dirty-workspace recovery as resolved/stale when its issue workspace record is removed.
  3. Optionally also suppress the recovery when the recorded recovery workspacePath no longer exists.
  4. Keep the run record intact for audit/history.

This keeps the cleanup behavior intact while making the Observability Layer report only currently actionable recovery.

Expected behavior

After a terminal cleanup removes an issue workspace:

  • gh-symphony repo status should not show "Recoverable incomplete turn" for that removed workspace.
  • status.json.recovery should be null.
  • Historical run records may still preserve their recovery payload.
  • repo explain should not warn that dispatch will start a recovery turn for a removed workspace.

Test cases

  • Unit: buildProjectSnapshot() does not surface recovery when the matching workspace record has status: "removed".
  • Unit: buildProjectSnapshot() still surfaces recovery when the workspace record is active and dirty recovery is unresolved.
  • Orchestrator/service: create a suppressed incomplete-turn dirty-workspace run, then run terminal workspace cleanup; the saved project status should have recovery: null.
  • CLI: repo status does not render the "Recoverable incomplete turn" block when snapshot recovery is null.

Notes

This should not modify docs/symphony-spec.md. The change aligns status reporting with the existing workspace lifecycle instead of changing the upstream spec.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingchangeset:patchRequires a patch changeset for CLI package releaseobservabilityLogs, status, events, dashboards

Projects

Status
In review

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions