Recover orphaned authored operations without duplicate writes #319

Closed
opened 2026-08-08 16:30:02 +00:00 by rockachopa · 0 comments
Member

Problem

A durable idempotency reservation can survive a worker crash forever. Retries receive 503 indefinitely, stale pending rows count against ledger capacity, and authored mobile work can remain blocked without a safe resolution path.

Vertical slice

  • Expire stale pending reservations into an explicit uncertain outcome without replaying the upstream mutation.
  • Return a structured, non-transient response so the outbox stops automatic retry and isolates the affected item.
  • Allow the user to explicitly confirm the operation was not posted and retry with a fresh operation key; unrelated queued work must continue.
  • Preserve joining/replay while the original in-process task is still alive.

Acceptance

  • Stale pending rows no longer consume active capacity.
  • A restart/orphan performs no automatic Gitea POST and returns an explicit uncertain-delivery response.
  • The affected outbox record requires deliberate retry with a new key while other records continue draining.
  • Live in-process reservations retain current join/replay semantics.
  • Completed replay and payload-conflict behavior remain unchanged.

Evidence: src/main.py treats ledger pending without a local task as permanent 503; src/idempotency.py expires only completed rows and counts pending rows toward capacity. No open/closed issue title or recent commit implements orphan lifecycle recovery.

## Problem A durable idempotency reservation can survive a worker crash forever. Retries receive 503 indefinitely, stale pending rows count against ledger capacity, and authored mobile work can remain blocked without a safe resolution path. ## Vertical slice - Expire stale pending reservations into an explicit uncertain outcome without replaying the upstream mutation. - Return a structured, non-transient response so the outbox stops automatic retry and isolates the affected item. - Allow the user to explicitly confirm the operation was not posted and retry with a fresh operation key; unrelated queued work must continue. - Preserve joining/replay while the original in-process task is still alive. ## Acceptance - Stale pending rows no longer consume active capacity. - A restart/orphan performs no automatic Gitea POST and returns an explicit uncertain-delivery response. - The affected outbox record requires deliberate retry with a new key while other records continue draining. - Live in-process reservations retain current join/replay semantics. - Completed replay and payload-conflict behavior remain unchanged. Evidence: `src/main.py` treats ledger `pending` without a local task as permanent 503; `src/idempotency.py` expires only completed rows and counts pending rows toward capacity. No open/closed issue title or recent commit implements orphan lifecycle recovery.
timmy was assigned by rockachopa 2026-08-08 16:30:02 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stackchain/stackchain-dashboard#319
No description provided.