Repository navigation
design(recovery): reconcile abandoned claims without stealing work #1245
Description
Problem
Persisted assignment labels/claims can exclude otherwise eligible work after the original worker disappears or its identity changes. A claim is not proof of active execution, but absence of a Courier CoderRun is not proof of abandonment either.
Observed 2026-10-13: windowstead#398, pinchflat#109, and Courier#243 retained legacy agent/courier assignments. The configured frontier consumer was courier-frontier; default queue filtering excluded the other identity's claims. An operator explicitly released those three claims through Dispatch, after checking the corresponding cluster attempts; frontier immediately picked up windowstead#398. This demonstrates stale ownership can strand work, not that every legacy assignment should be released automatically.
Required design
- Inventory current claim, lease, acknowledgement and AgentWork semantics. Define authoritative ownership/liveness evidence separately from GitHub assignment and status labels.
- Support arbitrary worker clients, not just Courier. Define a minimal optional client capability for durable ownership/renewal/terminal disposition; specify safe handling for clients without that capability.
- Distinguish abandoned execution, legitimate long-running work, review-owned work, external dependency waits, deliberate human assignments, and maintainer holds.
- Specify bounded reconciliation, expiration/grace periods, restart recovery and explicit operator controls. Evidence that a worker is unreachable or telemetry is missing must not immediately mean abandonment.
- Release only verified obsolete ownership atomically, with fencing against a renewed/replaced owner. Preserve attempt history, audits, genuine blocker reasons and linked-PR ownership; select the next eligible state rather than always forcing ready.
- Treat legacy identity migration explicitly. Do not alias all
agent/courier*identities, steal another consumer's assignment, or assume one app owns a whole family of labels. - Keep GitHub/cache/lease state consistent and expose unresolved or conflicting ownership as unknown. Bound reconciler retries and repeated release/reclaim churn.
Acceptance / design deliverable
An ownership state model, evidence hierarchy, compatibility/migration policy, reconciliation transition table, operator escape hatch, and race/failure cases. Include active renewal concurrent with release, disconnected workers, missing events, closed issues, open linked PRs, explicit holds and generic legacy assignments. Inspect existing mechanisms first; identify improvements rather than inventing a parallel lease system.
Related: misospace/courier#287 is local run retention; deleting local history must not become Dispatch's recovery algorithm. misospace/courier#320 concerns model exhaustion; quota reset alone must not release unrelated claims.
Non-goals
Design only. No claim release, blanket label cleanup, requeue, implementation, worker credential migration or deployment changes. Genuine human decisions remain held until explicitly resolved.
Activity
joryirving commentedon Oct 13, 2026
Implementation handoff (2026-10-13)
Both remain
status/blockeduntil design PR #1246 is accepted. Related #1202 is the existing lifecycle evidence stream, not something these issues should duplicate. Do not aliasagent/courier*identities or turn missing telemetry into permission to steal work. Docs merge completes design, not implementation.docs(recovery): specify two-sided release boundary for cross-system f…
docs(recovery): serialize the claim side of the release boundary (#1245)
docs(recovery): scope the intent invariant and pin claim-intent replay (
docs(recovery): trace requirements and refresh citations after #1259 …
docs(recovery): fix legacy-migration cross-ref and child-issue status…
docs(recovery): ownership reconciliation design (#1245) (#1246)