fix-recurring-shell-orphan-convergence

Fix recurring shell completion versus orphan-recovery race

Metadata

Statusopen
Agent identity02e879681e52e0a384106169be043416c4d946e850ab26b2269c57681b52a6e7
Created2026-08-06T13:58:05.610943782+00:00

Description

A successful recurring inline shell task can be terminalized, then rewritten to InProgress by generic orphan recovery before the cron reset is durably recorded. Incident: .html-publish-workgraph-itself agent-19 printed [publish] OK and Task completed, exited successfully, and had completed_at set, but every coordinator tick logged Reconciliation: recovered 1 orphaned task(s). The task stayed InProgress, last_cron_fire stayed at 13:35, and subsequent five-minute occurrences accumulated as missed. An operator retry restored it, proving the payload was successful and only convergence was broken.

This must be repaired in the one authoritative recurring-shell lifecycle path, not by special-casing HTML publication. A durable success/terminal receipt wins over generic orphan recovery. The recurring reset to Open plus last_cron_fire/next-fire advancement must happen exactly once after a successful occurrence, including when the inline shell has no worktree metadata and when execution spans multiple coordinator ticks. No coordinator pass may revive a completed occurrence as InProgress. Failed or still-live shell processes must not be reported successful. Preserve catch-up semantics without replay storms.

This task depends on the build-storage work because both touch coordinator/admission code; do not overlap their worktrees. Do not add another observer/controller or compatibility layer.

Validation

  • Installed service test runs at least three consecutive short-interval occurrences of a successful recurring shell payload. Each occurrence executes once, advances last_cron_fire once, returns to scheduled Open, and never logs orphan recovery for that terminal occurrence.
  • A payload longer than one coordinator tick is not recovered as orphaned or double-spawned.
  • Process exit between terminal receipt and cron reset converges correctly after daemon restart.
  • Failed payload remains failed/retriable according to existing policy and is not reset as successful.
  • Inline shell tasks without metadata.json do not trigger incorrect worktree cleanup or lifecycle recovery.
  • Add focused regression coverage; do not run the old broad 177-target suite.

Depends on

Required by

Log