# Delivery liveness plan (issue #10)

## Scope

Issue #10: on adapter 0.3.19 the daemon-restart autostart replay path spawns sessions whose
bring-up looks healthy (bind, token, listener) but whose inbound deliveries never start an agent
turn — the #9 defect-B pattern, resurfacing on a spawn path the adapter cannot distinguish from
any other daemon-driven spawn (no marker in the published launch contract). Any daemon death
(OOM, update, crash) funnels through this path, silently re-deafening endpoints.

The adapter-side root gap: the extension *trusts* that `pi.sendUserMessage` on an idle session
atomically starts a turn and has no verification that a delivered message ever produced one. A
deaf session is indistinguishable from a healthy idle one on every observable the extension
currently tracks — exactly the "dead communication path looks healthy" hazard, one rail deeper.

## Decisions

- **Path-independent invariant, not path detection.** The daemon replay spawn is not
  distinguishable from the manifest side, so cover it (and every current and future deaf mode)
  with one invariant: *an accepted listener delivery on an idle session either enters a turn
  within the liveness deadline, or the endpoint visibly self-heals and, failing that, closes*
  (ADR-0010 doctrine: native delivery self-heals or closes).
- **Watchdog condition**: `pendingListener` non-empty while OMP reports idle. Any real turn —
  peer-triggered or operator-typed — consumes pending envelopes through the existing context
  hook, so a session that stays pending+idle across a full deadline has demonstrably lost
  receivability. Busy sessions never count toward the deadline.
- **Escalation ladder** on deadline expiry (deadline injectable, default 120s):
  1. First expiry: force-resubmit pending items (per-item submission epoch invalidates a hung
     or stale in-flight submission so the guard flag cannot wedge recovery).
  2. Second expiry: resubmit again and surface the existing warning-styled
     ` · comms recovering...` health rail (component `delivery`).
  3. Third expiry: fail closed — release pending custody with failure outcomes, end the SPT
     session, shut down the hosted TUI. A deaf-but-ONLINE endpoint becomes visibly offline;
     daemon-side lifecycle (or the operator) brings up a fresh, working session, which is the
     operationally verified recovery (#9/#10: suspend/wake).
- **Turn liveness resets** the ladder: `agent_start` clears the attempt counter and timer.
- Stale `endpointState` cache invalidation on listener death: a restarted daemon may hold
  persisted state that no longer matches the extension's cache; after a listener death the next
  publication must not be skipped by the cache.
- Daemon-side aspects are findings, not workarounds (public-surface-only constraint):
  - F-033: autostart replay yields a session whose live deliveries never kick turns while
    `spt send` reports plain `SENT(WAN)` — needs daemon-side root-cause; adapter now closes
    deaf sessions instead of presenting them healthy.
  - The 1.4G daemon RSS / OOM ask in issue #10 is spt-core territory — recorded in the same
    finding for doyle.

## Non-goals

- No bring-up probe turn (spends tokens on every healthy spawn; watchdog only acts when real
  custody is at stake).
- No daemon-side replay change (not our repo; finding filed).
- No second durable spool, receipts, or acknowledgment above spt-core custody.

## Tasks

1. Requirement `REQ-HAZARD-DELIVERY-TURN-LIVENESS` (doc/impl/unit) + KNOWN-HAZARDS entry +
   harness-contract failure-behavior wording.
2. Extension: liveness watchdog state, arm/disarm sites (accept, submit, resubmit, agent_start,
   context consumption, shutdown), escalation ladder, submission-epoch resubmit hardening,
   endpointState cache invalidation on listener death.
3. Focused tests: deadline expiry resubmits; hung submission cannot block recovery; second
   expiry shows degraded health; third expiry fails closed with failure outcomes; agent_start
   resets the ladder; busy sessions never expire; watchdog disarms when context consumes items.
4. Findings ledger F-033; CHANGELOG; version bump 0.3.20 across manifest/package/Cargo/docs
   (version-consistency gate is authoritative).
5. Gates: `node --test tests/omp-extension.mjs`, `sh ci/run-gates.sh`, `traceable-reqs check`.

## Gate

Extension tests, deterministic gates, and traceability all pass; the plan's invariant has a
focused failing-then-passing test for each ladder rung.
