# LIFECYCLE-TRUTH W5 — dispatch + design ruling (doyle, 2026-07-07)

**GO todlando.** W5 = delivery integrity. Three REQs. Spec = `docs/NEXT-MILESTONE-LIFECYCLETRUTH-TRIAGE.md` §W5 (roots pinned). Suggested order: **SPOOL-TAKE-AUDIT first** (observability substrate that instruments the other two's RED-first rigs) → **IDLE-PARKED-DELIVERY** → **INJECT-MULTILINE-INTEGRITY** (the hard one). Activate each in its work-start commit. Signal wave head; I gate both legs + the delivery seam sweep (inject/translation/spool/chunk).

---

## Ruling A — REQ-INJECT-MULTILINE-INTEGRITY (the crux)

The fork was "settle-before-type **vs** bracketed-paste **vs** chunked-write-echo-verify." **They are not alternatives — they are LAYERS.** The root is a *pre-settle typed-stream race* (head bytes typed before the TUI's input reader is attached/settled → swallowed mid-stream). Whatever we send FIRST is at risk — the head bytes, OR a bracketed-paste `ESC[200~` opener, OR chunk 1. So a readiness gate is upstream of all three.

**Ruling — build it in three layers, MUST/MUST/SHOULD:**

1. **MUST — settle-gate before ANY bytes (the load-bearing fix).** Do not write into a PTY that is not ready. Detect readiness with a **positive signal**, not a blind timer: write a benign no-op / cursor-position query and confirm its echo before sending payload (or an equivalent readiness probe on the broker PTY). The operator-observed non-determinism (1854B once landed intact, ~1150B usually swallowed) is precisely the fingerprint of *no settle gate* — same class as the adapter's 0.13.2/0.13.3 checkpoint-settle fix. This kills the root.

2. **MUST — post-inject echo-verify → re-drive once → LOUD spool fallback (the safety property).** A live-SENT inject leaves **no spool copy**, so a swallow today is silent AND unrecoverable. After writing, verify the head echoed (compare a prefix of what we sent against the PTY echo). On mismatch: re-drive once; on a second miss, fall back to a **LOUD spool** (`delivered=false` + a `<sptc_frame_integrity>`-class marker) so the message is recoverable and the failure is visible — never a silent truncation. This converts the worst property (silent, unrecoverable) into (recoverable, loud) even when the settle heuristic occasionally misses.

3. **SHOULD (this wave if the seam is clean) — bracketed-paste as the DELIVERY MODE where the harness declares it.** Wrap the payload `ESC[200~ … ESC[201~` + a submit (enter after paste-settle) so the TUI's paste handler reads it **atomically** — no per-keystroke submit-storm, no mid-stream cut. Reuse the v0.13.0 RC-PASTE mechanism (CC sets `ESC[?2004h`); adapter declares a `bracketed_paste` capability. This is the strongest delivery where available, but it is **layered on top of the settle-gate** (its opener still needs the terminal ready) — not a substitute. Where the harness does **not** declare bracketed-paste, the fallback delivery is **chunked write** (per `EVENT-PART`, paced), still under the settle-gate + echo-verify.

**Unblocking ruling on the open slot-math question:** the settle+verify design is **readiness-gated and echo-verified, NOT byte-count-gated** — so it does **not** depend on pinning the exact wire slot math (the ~20B first-part attr discrepancy). Do **not** block the fix on capturing the exact swallow-window bytes. (Keep the raw relay-log capture as a nice-to-have for a future byte-threshold optimization, not a gate on this wave.)

**Int (binding, RED-first):** repeated large multi-line injects into a REAL PTY session arrive **byte-complete** — **LOOP N times** (the race is timing-dependent; a single green is not proof). Assert head-intact across the loop. Pre-fix: head-loss recurs within the loop.

**Interim protocol stays binding UNTIL this REQ gates:** sub-400B sends OR file transport for anything larger. We drop the workaround only on W5 gate.

---

## Ruling B — REQ-IDLE-PARKED-DELIVERY

Fix direction is clear; the only fork is send-time-inject vs pulse-sweep. **Ruling: BOTH (primary + belt).**
- **Primary — send-time inject fires for an already-idle target.** The activity sense says idle ⇒ inject NOW, don't spool. Today the idle-edge drain (F-023 leg 2) fires only on the ACTIVE→IDLE *transition*; a send to an already-parked-idle session never gets an edge. Make the send-time path treat "already idle" the same as "just went idle."
- **Belt — bounded spool re-offer on the pulse tick.** Piggyback the existing pulse tick (no new loop): sweep pending `delivered=0` rows for an idle spt-hosted endpoint and re-offer. Catches anything that still parks (e.g. a send that raced the idle edge).

**Int:** send to a session idle for N minutes → delivered with **no operator poke**. (Live-confirmed wake trigger already exists — parked rows flush on inbound activity — so this is "make send-time fire for already-idle" + "sweep on pulse," not a new wake mechanism.)

---

## Ruling C — REQ-SPOOL-TAKE-AUDIT

No design fork — **build as specified**, and sequence it **first** (it instruments A's and B's rigs). Additive column on the spool row: **taker leg** (enum: relay-backlog / hook-poll / idle-inject / psyche) + **sid/pid** + **taken_at ms**; surfaced by a `--json` debug read. No schema break (delivered rows already retained). This is the audit that turned the seed-#8 outage RCA into an hour of "who took delivered=1 rows" — it pays for itself the next incident.

---

## Not in W5 (separate/deferred)
- The daemon-revival psyche-currency + resumed-echo-commune + revival-notice design (operator grill in progress) → `REQ-UPDATE-FINISH-COMMUNE-FLUSH` neighborhood, **deferred post-milestone** by operator ruling; do not fold here.
- W6 (docs wave) is last.
