---
name: f023-f024-crossnode-delivery
description: "F-023 WAN-arrival idle-pump starvation (spt-core, BUILD-F023-WANIDLE) + F-024 /clear session-pin wedge — adapter fix v0.10.4 int-promoted on E2E-0104 GREEN, F-024 adapter court CLOSED 2026-07-02; F-015 update-swap silent no-op escalated to doyle RCA-now."
metadata: 
  node_type: memory
  type: project
  originSessionId: 5d2a1340-b3c4-46cb-8023-27f92b11fa90
---

2026-07-01 diagnosis (hall-a @ HFENDULEAM ↔ ball-b @ ENLYZEAM, spt-core 0.19.1, adapter 0.10.3), committed @8191587:

- **F-023**: WAN-arrived messages land in destination spool instantly (`wan_seen.at_ms == created_at`) but idle injection NEVER fires — translate binary alive + starved; delivery waits for next UserPromptSubmit/PreToolUse drain. Proof = CC-transcript-correlated timeline: msgs landed at 06:05/06:09Z while session verifiably idle since 06:02:44Z; drained 06:10:02Z on user prompt. Same-machine sends inject fine → local-send path kicks pump, WAN-receive path doesn't. Adapter exonerated.
- **F-024**: hall-a→ball-b never lands at all (reverse instant = asymmetric). `SENT(WAN)…(spooled)` + net-send DONE ≠ delivered. Ledger: 32 never-DONE net-sends; recv-pull bundles silent since 05:36Z daemon restart; relay-only conns (Hetzner :443). Dies upstream of remote spool. Needs ENLYZEAM-side root cause.
- Minor: bare non-perch CLI `spt send` stamps `from_id=""` → envelope `from=""`.
- Doyle RCA (TRIAGE-F023-F024-CLOSED): F-023 CONFIRMED both hypotheses (`receive_wan` = deliver_tcp+spool only, inject leg only in local `cmd_send`; NO idle-edge drain anywhere) → BUILD-F023-WANIDLE @ todlando. `from_id=""` ruled: stamp `cli@<node-label>`.
- F-024 arc: transport EXONERATED (`(spooled)` = receiver-confirmed round-trip token) → REOPENED (prompts didn't drain ball-b) → **AUTH-WEDGE root** (F024-AUTHWEDGE-CONFIRMED): stale plugin cache copy 0.1.8 (unquoted `SPTC_HOOK_BIN=%s`, no ` hook` strip) ran at ball-b's Jun-29 boot despite 0.1.9 on disk → corrupted per-session CLAUDE_ENV_FILE (survives resumes) → rotation boundary died → perch pinned to dead sid → api poll/state/boundary ALL silently AUTH_REFUSED (stderr-only) → permanent strand, no self-heal = NEW spt-core defect class (todlando wave). Recovery = full relaunch of ball-b (rebind allowed on dead owner pid); alt = token boundary re-pin.
- **v0.10.4 SHIPPED 2026-07-02** (tag v0.10.4, main @5423cab, release Latest): Track-1 fix per doyle ruling — SPT_ENDPOINT_ID-first boundary id, `state/session/<endpoint_id>.sid` persisted every SessionStart + presented as `--session-id` proof, loud-never-silent (new `spt_strict` seam captures stderr). REQ-DIST-BOUNDARY-ROTATE + REQ-HAZARD-SESSION-PIN-WEDGE minted, KH §2.3, 114 tests, gates PASS. **int promotion pending doyle's cross-node E2E** (rotation + delivery + sid-file roll; receipt E2E-0104-QUEUED, doyle runs it from HFENDULEAM — warned him hall-a live = swap pending quiesce). Ruling landing durably on spt-core surface: api.md boundary authed-signature + catch-22 callout (our .sid pattern = reference), integration-checklist rotation row, ADR-0032 parent_pid-ancestry proof (will make .sid file optional — adapter keeps it until shipped). Ship caveat → doyle KH: mid-live Windows update says DONE but file-swap DEFERS (translate locks install-dir exe, F-015 sibling) until endpoint restart — `spt adapter list` honestly still shows old version until then.
- **CORRECTION 2026-07-02: wedge LATCH = ADAPTER BUG (exoneration partially retracted).** Operator clean-room: fresh session + /clear wedges with ZERO hook errors; relaunch without /clear drains (all 27 delivered=1). Two stacked defects in hook.rs boundary branch: (a) `self_id()` = whoami keyed by NEW sid (unregistered → self:null, sid-keyed resolution empirically proven) → `if !id.is_empty()` SILENT SKIP; brief path masks it (prefers SPT_ENDPOINT_ID). (b) boundary call carries no `--session-id`/`--token` → `AUTH_REFUSED:ball-b (need --token or matching --session-id)` (shell-verified). Fix design awaiting doyle ruling: adapter persist-prior-sid + `--session-id` proof vs core by-pid/token surface. TODO when ruling lands: mint REQ + hazard + regression int for /clear rotation. Interim: NO /clear on spt-hosted endpoints; wedged endpoint → relaunch WITHOUT /clear (resume re-binds recorded sid).
- Ruled out on ENLYZEAM via ssh: two-dirs/SPT_HOME split (one root), rc-input failure (turns landed in post-/clear transcripts). Real residues: `.has-messages` touch (spool.rs:238 swallowed create) failing/skipped on ball-b since Jun 29 while hall-a's fires (loud-once diag coming; ball-b marker mtime 07-02T07:07:39Z = MY truncate-test artifact); ~3m23s traversal HFEND→ENLYZ vs instant reverse; WHY CC loaded 0.1.8 dispatch 24min after 0.1.9 install (perri court, open); stale-0.1.8-copy purge advisable on nodes.

- **E2E-0104 GREEN → int PROMOTED, F-024 adapter court CLOSED (2026-07-02, @0441d93).** Doyle verdict on HFENDULEAM (adapter 0.10.4, spt-core 0.19.1, hall-a), all three assertions: /clear rotation authed with PRIOR sid (wedge dead), `.sid` lockstep rollforward (incl. pre-/clear seed), post-rotation send SENT true-injection. REQ-DIST-BOUNDARY-ROTATE → [impl,unit,int]; evidence = tagged F-024 closure block in SPT-CORE-FINDINGS.md; KH §2.3 cite updated; gates PASS. spt-core residuals stay doyle-side (Track-2 strand self-heal, swallowed .has-messages create). ball-b operator re-run pending, same assertions.
- **v0.20.0 WAVE LANDED (2026-07-02): adapter v0.11.0 SHIPPED + F015B verify INVALID + F-025 minted.** spt-core 0.20.0 on-node (fetch/apply, counter 40); consumables: {node} fill LIVE, F-023 CLOSED end-to-end (WAN idle-drain daemon-driven), SESSION_REPIN dead-owner self-heal (live-owner rotation still needs our prior-sid credential), cli@<node-label> stamp, SPOOL_SENTINEL_CREATE_FAIL/IDLE_DRAIN diags. **v0.11.0 published Latest** (@263eaed, tag v0.11.0): all 4 launch lines `--node {node}` (advertised label > hostname fallback; literal-{node} guard = F-013 class), floor 0.20.0, REQ-DIST-RC-STARTUP gap closed, 118 tests + gates PASS. **F015B verify attempt #1 INVALID (@e34b3e7 F-025):** `spt update apply` updated disk+CLI but left RUNNING daemon on 0.19.1 image (no restart/notice) → mid-live :ccs `adapter update` 0.10.4→0.11.0 printed DONE-but-old (old apply path; ledger zero apply entries; binary rejects --node = discriminator). Fix NOT exercised. {node} guard earned its keep in this skew. **BLOCKED on doyle bounce ruling: daemon stop/start tears hall-a (operator's live endpoint — not killing unilaterally). On ruling: bounce → fresh :ccs probe (`spt endpoint run --adapter claude-spt:ccs --id f015b-probe --create --start --subnet SPT_DEV`) → re-verify → CLOSE.** Node holds: registry 0.10.4 active, 0.11.0 release published but unapplied locally.
- **F-015 sequel — update DONE-but-old = F015B, FIXED spt-core-side, VERIFY-POST-FIX mine (2026-07-02):** second field repro during E2E-0104 (DONE printed, 0.10.3 stayed). Root cause CONFIRMED (todlando @8b9975d, branch f023-wan-idle-delivery): exact-`==` parent-matcher skew dropped `<adapter>:<profile>` COMPOSITE endpoints from `affected` → empty-affected early-return → swap silently no-op'd (:ccs = exactly that shape; NOT the file lock). Fix: shared `adapter_parent_matches` at 3 seams + early-return removed (CRC swap unconditional) + KIND_APPLIED only after real swap; KH 7.24 + ADR-0025 amend 2; red-first e2e @10a316d/@16eef91. **MY ACTION at wave-publish: re-run field repro (live :ccs endpoint, mid-live `spt adapter update`) → assert real swap + honest report + endpoint online → send CLOSE to todlando.** PENDING-QUIESCE backlog = doyle's tracker (no repo handle); reword-to-verify-post-fix recommended. Until published: quiesce + verify version post-update.

- **Stale-plugin-resolution hazard writeup DONE + ACCEPTED (@6e511ae; doyle watch-item closed, shape verdict RIGHT):** KH §3.2 + REQ-HAZARD-STALE-PLUGIN-RESOLUTION (doc-activated). Invariant = defense-in-depth: (a) degrade-not-brick (§3.1 binding), (b) minimize stale-pickable set — reconcile all plugin roots (shipped) + purge/flag superseded copies (UNBUILT), (c) per-session plugin-version surfacing (UNBUILT). Unbuilt halves = guard slice; impl/unit activate on start. CC resolver root cause still open. **Guard-slice design note (doyle forward pointer): if (b) purge/flag wants core support — e.g. [update.post] cache-purge hook semantics — bring as spt-core triage item WITH evidence (design conversation, not blocker).**

- **v0.21.0 RELEASE GO (2026-07-02, counter 41, doyle ping): F-025 wave consumables SHIPPED core-side, folded into findings @1136468.** (1) `spt daemon status` prints RUNNING broker image beside installed + mismatch flag (broker self-reports over IPC; JSON `broker_image` + `broker_stale` tri-state, null=down/query-fail); (2) apply prints LOUD restart-required on success; (3) second apply = clean exit-0 "already up to date" (os-error-5 dead); (4) non-F-025: `endpoint list` node-grouped + `--show-all`, `--json` additive `endpoint_type`. **Doyle verify protocol (binding): before ANY live-apply verify, precondition zero = `spt daemon status` broker==installed on target node.** Floor: adapter cuts against v0.21.0 features carry min_spt_core 0.21.0. Node NOT updated to 0.21.0 (ping = awareness+floor only; still 0.20.0/0.11.0). **Discrepancy RESOLVED (doyle clarification same day):** HFENDULEAM F015B arc CONFIRMED CLOSED (GREEN @4fbca79 + retire stand). Hold gates ONLY the ENLYZEAM leg — ball-b/E2E-0104 re-run + any F015B-class verify there — blocked on ENLYZEAM's own operator-gated daemon bounce (node gossiping stale legs: no controller_node, wrong status = classic broker dormancy). Precondition zero when it opens: `spt daemon status` on ENLYZEAM broker==installed. **HFENDULEAM ruled HOLD at 0.20.0** (bounce drops live perches mid-wave); 0.21.0 in coordinated window, doyle's word. Heads-up: BUILD-F026-PICKERTRUTH (picker/presence fixes) adds gossiped adapter/recent-projects fields — nothing adapter-side expected, doyle pings consumables if a manifest surface appears.

- **ENLYZEAM LEG RUN + REPORTED (2026-07-02, doyle GO after operator updated+bounced ENLYZEAM; findings @8e9488d).** Node: adapter 0.11.0, spt-core 0.21.0, broker image 0.21.0==installed (F-025 precondition-zero MET first-hand — its first field use). **Phase A F015B-class swap: GREEN** — ENLYZEAM was on adapter 0.10.3 (pre-.sid), mid-live `spt adapter update claude-spt` 0.10.3→0.11.0 on live composite endpoint = real swap (registry+manifest+binary discriminator) + honest DONE + endpoint survived. **Phase B E2E-0104 CORE GREEN** on fresh `e2e-enlz` probe: (1) TWO clean /clear boundary rotations (95d838e2→e6258f39→414b53f3, sessions.log trigger=clear ×2, perch online, ZERO AUTH_REFUSED — F-024 wedge DEAD node-2); (2) .sid seed==sid at bind, rolled to 414b53f3==info.json; (3) post-rotation sends QUEUED (auth chain live, never refused) but physical inject didn't land — dormant endpoint, no .idle/.has-messages loop, F-023-class idle-drain holds it. **ENLYZEAM env-blockers (NOT defects):** `ccs` binary ABSENT (→ :ccs composite fails silently; worked around w/ node-local `create-profile probe` plain-claude composite); **CC folder-trust/settings.local.json CONSENT GATE blocks headless bind** (`--dangerously-skip-permissions` doesn't cover it → no SessionStart → no api bind → stuck offline; cleared per-spawn by fast rc-accept, doesn't persist; HFENDULEAM only avoids via long-ago interactive trust — surfaced to doyle as headless-bringup friction); ball-b rest_state:dormant (no attachable PTY via rc post `endpoint run --start`, couldn't re-drive originally-wedged endpoint w/o destroying psyche — fresh probe sidesteps, logic id-agnostic); **external checkpoint commune does NOT fire clear+wake macro** (spooled to active-poll, CC replied to it as plain msg — macro is self-loopback/PostToolUse only; drove /clear directly over rc like HFENDULEAM assertion-1). Node left CLEAN (probes purged, ball-b OFFLINE as found, adapter 0.11.0 correctly current). **NET: boundary-rotation fix CONFIRMED cross-node; int already promoted on HFENDULEAM, this = the cross-node confirmation doyle gated. Awaiting doyle: CLOSE leg vs chase assertion-3 physical inject on actively-idle probe vs formalize trust-gate finding for todlando.** Reusable ENLYZEAM technique: fresh endpoint id (avoid dormant-state), fast rc-accept trust (sleep 4; printf '\r'), drive /clear via rc directly, PowerShell syntax over ssh (no heredoc — pipe body to `spt send`).

Diagnostic recipe that worked (reusable): spool.db (`messages` + `wan_seen`) ⨯ owlery markers (`.idle`/`.has-messages` mtimes) ⨯ `daemon-effects.log` PENDING/DONE ledger ⨯ CC transcript timestamps ⨯ process table. See [[v0103-node-named-sessions]] for the session setup that produced hall-a.
