supervise: daemon robustness edges — retry bound across re-attach, lock-reclaim TOCTOU, stall blind spots #255

Open
opened 2026-08-25 18:16:28 +00:00 by jbr870 · 3 comments
Owner

Spawned from finding F-PO-46-4-21 (in-scope-deferrable) on issue #46 during decision D-PO-46-4-19.
Also collects the folded findings F-PO-46-4-22 (stale-lock reclaim TOCTOU) and F-PO-46-4-24 (stall-detection blind spots) from the same QA round — three robustness edges of the supervise daemon that each need a designed fix plus its own test scenario, not a point patch.

Original scope note (CR-21): the per-incident retry bound does not survive a daemon crash: supervisor-watch.sh hard-initializes the incident counters and supervisor-attach.sh always writes incident{attempt:0}, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert-dedup state. The state file already persists the counters precisely so they could be restored.

Disposition rationale: each fix is substantial (state-restore contract on reclaim; holder-identity-aware lock reclaim; stall-clock design for no-assistant/empty-transcript windows) and the risks are bounded and rare — deferred out of #46's QA round rather than grown into it.

This issue was deferred out of the parent feature's scope; it carries no PREQ yet. Run /dev:requirements --issue={new-number} to flesh it out before planning.

Spawned from finding `F-PO-46-4-21` (in-scope-deferrable) on issue #46 during decision D-PO-46-4-19. Also collects the folded findings F-PO-46-4-22 (stale-lock reclaim TOCTOU) and F-PO-46-4-24 (stall-detection blind spots) from the same QA round — three robustness edges of the supervise daemon that each need a designed fix plus its own test scenario, not a point patch. **Original scope note (CR-21):** the per-incident retry bound does not survive a daemon crash: supervisor-watch.sh hard-initializes the incident counters and supervisor-attach.sh always writes `incident{attempt:0}`, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert-dedup state. The state file already persists the counters precisely so they could be restored. **Disposition rationale:** each fix is substantial (state-restore contract on reclaim; holder-identity-aware lock reclaim; stall-clock design for no-assistant/empty-transcript windows) and the risks are bounded and rare — deferred out of #46's QA round rather than grown into it. This issue was deferred out of the parent feature's scope; it carries no PREQ yet. Run `/dev:requirements --issue={new-number}` to flesh it out before planning.
Author
Owner
{"status":"active","from_issue":"46","finding_ref":"F-PO-46-4-22","decision":"D-PO-46-4-20","category":"in-scope-deferrable","summary":"sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.","original_scope_note":"Hygiene while the file is already under edit; delete it.","disposition_rationale":"Folded into #255: same supervise-daemon robustness family as CR-21; needs holder-identity-aware lock reclaim with its own test."}
<!-- folded-finding:v1 issue=255 from_issue=46 finding_ref=F-PO-46-4-22 status=active decision=D-PO-46-4-20 --> ```json {"status":"active","from_issue":"46","finding_ref":"F-PO-46-4-22","decision":"D-PO-46-4-20","category":"in-scope-deferrable","summary":"sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.","original_scope_note":"Hygiene while the file is already under edit; delete it.","disposition_rationale":"Folded into #255: same supervise-daemon robustness family as CR-21; needs holder-identity-aware lock reclaim with its own test."} ```
Author
Owner
{"status":"active","from_issue":"46","finding_ref":"F-PO-46-4-24","decision":"D-PO-46-4-22","category":"in-scope-deferrable","summary":"Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.","original_scope_note":"Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.","disposition_rationale":"Folded into #255: stall-window sizing and empty/no-assistant transcript handling need a designed answer alongside the other daemon robustness edges."}
<!-- folded-finding:v1 issue=255 from_issue=46 finding_ref=F-PO-46-4-24 status=active decision=D-PO-46-4-22 --> ```json {"status":"active","from_issue":"46","finding_ref":"F-PO-46-4-24","decision":"D-PO-46-4-22","category":"in-scope-deferrable","summary":"Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.","original_scope_note":"Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.","disposition_rationale":"Folded into #255: stall-window sizing and empty/no-assistant transcript handling need a designed answer alongside the other daemon robustness edges."} ```
Author
Owner
{"status":"active","from_issue":"46","finding_ref":"F-PO-46-6-3","decision":"D-PO-46-6-2","category":"in-scope-deferrable","summary":"A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.","original_scope_note":"No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.","disposition_rationale":"Folded into #255: incident-lifecycle bound design (abort-re-aim churn) belongs with the other supervise daemon robustness edges."}
<!-- folded-finding:v1 issue=255 from_issue=46 finding_ref=F-PO-46-6-3 status=active decision=D-PO-46-6-2 --> ```json {"status":"active","from_issue":"46","finding_ref":"F-PO-46-6-3","decision":"D-PO-46-6-2","category":"in-scope-deferrable","summary":"A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.","original_scope_note":"No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.","disposition_rationale":"Folded into #255: incident-lifecycle bound design (abort-re-aim churn) belongs with the other supervise daemon robustness edges."} ```
Sign in to join this conversation.
No description provided.