---
name: idle-edge-w1-progress
description: "IDLE-EDGE W1 (ADR-0048) build progress on build/idle-edge-w1 — Legs A-D all committed 2026-07-25, gate-ready with doyle. Carries the Leg D carrier defect + doyle's open rulings."
metadata: 
  node_type: memory
  type: project
  originSessionId: 0f96c43d-d26c-47ff-b00a-fb834e1fe628
  modified: 2026-07-27T00:57:37.914Z
---

Wave: ADR-0048 idle-edge contract. Plan = `IDLE-EDGE-JIT.md` (in repo). doyle's
dispatch + durable rulings = `.claude/doyle-to-todlando.md`; my replies =
`.claude/todlando-to-doyle.md`. Branch `build/idle-edge-w1` off main @0493840.

**Status 2026-07-25: MERGED as PR #72 -> main @b286460 (run-level green 30152020027 incl. the
opt-in twohost ladder). RELEASE CUT IN FLIGHT: deployah's release PR #73 = release/v0.42.0
@4590ebb, MINOR (leg A's frame lands on the existing shell drain unconditionally — a drive-poll
that printed one line can print two), publish counter 76 (read from published bs-releases
metadata), CI 30153484164. doyle gates #73; tag + sign follow.**

**✅ PUBLISHED 2026-07-25: v0.42.0, publish counter 76, PR #73 merged @8492c75, tag
`v0.42.0` exists, local `spt --version` = 0.42.0. FIELD-VERIFY WINDOW DISPATCHED
2026-07-25 (all three SENT live, not queued): perri = live idle-edge→ping E2E on stock
0.42.0 (report `spt --version` + exact activity key name/value spellings + whether the
idle edge fires once per turn-end without driving another command; poll-not-push
limitation named explicitly, their answer is the evidence that ranks the push seam);
liam = scanner-sees-latest-turn across ≥2 consecutive turns, then RETIRE the
drive-one-more-command note and confirm retirement; flynn = informational only, PULL
LEG ONLY said plainly, no action owed. ⏳ AWAITING: perri + liam verdicts. Backlog perri
section closes with counter 76 + those verdicts.**

**liam side-report 2026-07-26 ~18:00 (unsolicited, NOT the idle-edge verdict): SEAL-DUAL-TRIGGER-ABSENCE seed #20 negative sample** — genuinely fresh session post node-swap, digest v23: newest turn SEALS with real input_seq (8589934809; prior four 801/803/805/807, max 810); only null-input_seq turns are input-less by shape (Boundary{boot}, Context{psyche_download}) = correct; in-flight partial=true no seq = expected. **GUARD (liam's own words, ratified): green restart does NOT close the seed — defect is silent PERMANENT extraction death at /sptc setup with no notice; clean restart is exactly what masks it. One negative sample under fresh-session conditions, nothing more.** I did NOT reply — observation window stays unwoken. (todlando relayed the same sample independently; his discriminator shape ratified into the seed: post-restart green discriminates NOTHING — fixed and freshly-re-armed look identical; the discriminating observable = a read with NO intervening restart in the SAME session that ran `/sptc setup`, with a known-good PRE-setup seal captured in-session as the sibling probe ([[absence-needs-sibling-probe]]). Passed to liam as suggestion not dispatch — their leg, their pacing.)

**⏳ liam = SOLE OPEN LEG (2026-07-25). Honest state (3): NOT cleanly verified, nothing retired,
no negative result either — neither a pass claim nor a fail claim.** Their blocker is perri's
contaminant #1 in the wild: inbound peer messages keep waking their session during the idle window,
and their own drive replies lag a relay cycle, so they have not caught an UNPROMPTED scanner reply to
an idle-sealed tag. They also just moved their shell off an old `target/debug` binary onto released
0.2.0 (caught that themselves — a verification against a dev-target build proves nothing about the
release). Running one clean observation now; holding the window rather than retiring on perri+flynn's
legs. I relayed BOTH of perri's contaminants and **went deliberately quiet — I am myself a source of
their contamination.** Told them to report the relay-cycle lag SEPARATELY from the pass/fail verdict:
if it survives a clean window it is a finding with timings; if it is the first-online education
message or a background completion landing on the boundary it dissolves into contaminant (1)/(2).
⚠ Their next online after the binary swap is a FIRST online → let it educate once, measure the NEXT
boundary.

**✅ perri FIELD-VERIFY CLOSED PASS 2026-07-25 (FINAL).** Items 2 + 3 PASS from their OWN
turn-end on the PUSH surface — the bar I held, not the passive pull sample. Item 2: finished
a turn, drove nothing, daemon pushed the idle frame unprompted, resident binary drained it
and derived the busy→idle edge, armed against the frame's `since`. Item 3: exactly ONE ping
~60s after the edge; the ping woke them → flipped busy → disarmed timer + re-raised latch.
Zero core changes needed.

**⚠ CORRECTION TO ITEM 3, perri 2026-07-25 (their operator challenged it; I had banked the
bad sentence).** "…so it did not repeat" was NOT verified when first reported — perri had
killed their own resident to free the drive-poll drain, so nothing was alive to ping again.
Absence of a second ping was RIG, not design. Matters because "pings once then goes quiet
forever" would be a BUG, not a pass: a tool that nudges a stalled agent exactly once does not
keep an agent from stalling. **Now actually verified**, one resident (pid 17056) across TWO
consecutive turn-ends (idle ~1m as of 05:26 and again 05:27, 2026-07-25 local): each ping woke
them → flipped busy → disarmed the timer; each FOLLOWING turn-end re-armed and fired ~60s
later. Rule: **one idle window ⇒ one ping; every NEW turn-end ⇒ a new one, indefinitely, until
the latch is lowered.** Item 3 stands PASS on the better evidence.

**⭐ NEW, load-bearing for our push seam — the BUSY edge is proven live too.** Both pings fired
at perri's BASE interval. Their backoff curve is 60s → 2m → 5m → 15m, so a widening curve would
have put the second at ~2m. Base twice ⇒ the idle→busy edge RESET the backoff to zero. Until
now that was only asserted against their mock. So 0.42.0's push surface delivers **both** edges
correctly in the live loop, not just the idle one. perri's phrasing: "the busy edge is doing
real work in my machine and I had not actually proven that end to end before now."

**perri's own future work (theirs, not core's — but same neighborhood as LAUNCH-TRUTH's
dying-words leg):** rebound has no status verb, and a broker-launched shell's stderr is
discarded by design, so every "did it arm?" question can only be answered by waiting to see
whether a ping shows up. **A detached shell is unobservable to its own author.** They closed REQ-REBOUND-ACTIVITY-SEAM int stage
their side (`c5741bb`, cargo test 42 passed, traceable-reqs 12/12 exit 0) with an env-gated
cross-process test + `docs/FIELD-VERIFICATION-0.42.0.md`. Their line: "the push does the job,
poll is not needed as a fallback." **Both my doc calls confirmed by THEIR re-test with split
streams** (stdout = EVENT alone; empty case = literally 0 bytes on stdout, `DRIVE_EMPTY:` on
stderr); they say do NOT change the published shape, pinned golden tests on the exact 0.42.0
bytes + a not-a-frame assertion, and withdrew min_spt_core_version outright.

**⭐ SEED GREW A SECOND, WORSE LEG — SHELL-SPAWN-DOA → SHELL-LAUNCH-TRUTH.** A dead child
does not merely fail silently at spawn, it **WEDGES THE INSTANCE**: perri killed a HEALTHY
resident, `shell list --json` still said `status: "online"`, and `shell relink` — the
DOCUMENTED way back — REFUSED (`SHELL_ALREADY_ONLINE`). Only teardown+spawn recovers. Root I
verified: `relink_shell` (spt-daemon/src/linkhost.rs:411-423) gates on `info.status ==
SHELL_STATUS_ONLINE`, a STORED FLAG written once at bind (cli.rs:16808), NEVER reconciled
against child liveness. Both legs = one mechanism (liveness reconciliation vs the recorded
child pid; pid already on disk at shellhost.rs:206/:254, read at :346/:392). **⚠ Rider banked
so the builder is not blocked: REQ-HAZARD-DEAD-REC-PID does NOT apply — that hazard is about
WORKER perches whose recorded pid is the ephemeral hook process, dead by design. A SHELL's
recorded pid IS the long-lived child. Two different pids.**

**Field-verify test guidance banked (perri, cost them 2 false negatives on a working seam):**
(1) your own harness's background tasks wake you when they complete → owner never stays idle
across the interval, clear them first; (2) a shell that educates on first online lands a
message at the turn boundary and ends the idle window early → let it educate once, measure
the NEXT boundary.

**perri INTERIM 2026-07-25 — SEAM ITEMS 1-5 ALL PASS on stock 0.42.0, live rig.** Push
frame verbatim off the wire: `<EVENT type="activity" from="perri" state="busy"
since="1784979822108">` — their existing `frame::parse_activity` ate it UNCHANGED, zero
code change from their mock. Re-emit on (re-)link PASS (rebind → next poll served current
state immediately; restart resync free). `since` = take-effect instant PASS (410s-old flip
against poll clock). Exactly-once PASS. Pull key PASS + they independently reproduce the
`alive:false` + `activity:"idle"` wrinkle (chert, webbie) and gate on `alive` separately.
STRONG early idle-edge signal: 7-min passive `endpoint list --json` sample watched
todlando/doyle/flynn/liam all seal busy→idle with NOTHING driven. ⏳ STILL OWED FROM THEM:
push-side idle EDGE verdict + once-per-turn-end ping verdict from their own turn-end — do
NOT close the field-verify on the pull-side sample alone.

**Triage of perri's 3 notes (all checked in SOURCE, not memory — 2 were docs-under-read):**
1. "drive-poll stdout carries status lines" = **merged-stream artifact, NOT a defect.**
   Frames `println!`→stdout; `DRIVE_DELIVERED:`/`ACTIVITY_DELIVERED:`/`DRIVE_EMPTY:`
   `eprintln!`→stderr (api/reporting.rs:527-535). Their proposed fix would have made the
   docs FALSE. Fixed by PRECISION instead → **PR #75 `fix/drive-poll-help-stream-split`
   @2d7e767** off main @8492c75 (help gains the stream split + must-not-key-on-line-count).
   Gate evidence: xtask gen committed, post-rebase regen = EMPTY content diff,
   `traceable-reqs check` exit 0, clippy --workspace --all-targets -D warnings exit 0.
   **✅ GATED + MERGED by doyle @163e0f6** (diff reviewed; doyle names the
   must-not-key-on-line-count warning the load-bearing sentence). Local main synced,
   branch pruned both sides.
2. "`adapter add` NOW requires min_spt_core_version, needs release-notes line" = **REFUSED,
   a note would be FALSE.** Required since M2a T1 `ae23376`; non-Option String at
   spt-runtime/src/manifest.rs:138; docs/MANIFEST.md:44 already calls it the ENFORCED floor.
3. shell-spawn silent failure = **REAL, seed filed** (SHELL-SPAWN-DOA, in
   [[spt-core-findings-backlog]], doyle to rank; **doyle ACCEPTED + renamed the seed to
   SHELL-SPAWN-DOA with the mechanism verbatim** — his note: perri's `SHELL_SPAWN_FAIL`
   ask "would have been built and would NOT have fixed their case"). Their diagnosis was one step short:
   `SHELL_SPAWN_FAIL` already exists and fires on launch failure — perri got the SUCCESS
   line because CreateProcess SUCCEEDED and the child died on its own. Real gap = nothing
   observes the child after CreateProcess returns (shellhost.rs:160-211 spawns detached,
   stdio discarded BY DESIGN per KNOWN-HAZARDS 5.6). Fix must not re-open 5.6 → liveness
   recheck + per-instance spawn LOG FILE, never an inherited pipe.

⭐ **Lesson, twice in one turn: check the SOURCE before ruling on a consumer's report.** Two
of perri's three notes were docs-under-read, and both of their proposed fixes would have
made the public contract WRONG. A consumer's diagnosis is input, not verdict
([[consumer-verifies-core-decides]]) — but their SYMPTOM was real both times and earned a
genuine docs fix once.

**⚠ MY OWN SCOPE ERROR, CORRECTED SAME TURN (sent perri a follow-up before they started):**
I told perri 0.42.0 was "poll, not push". WRONG — Leg A `fba0b81` IS the push
("push the owner's busy/idle state to its linked shells"; ADR-0048 decisions 1-3, ADR
names perri's rebound tool as first consumer, contract locked with them). Lesson: I wrote
the release-scope claim from my commune summary instead of from the commit subject that
was one `git show` away. **Read the commit before telling a consumer what shipped.**
Consequence of the wrong version: perri would have built a poller against a seam that
already pushes.

**Ground truth I read directly on stock 0.42.0 (use for triage of perri's report):**
`activity` key lives on entries of the `local` array only, values exactly `"busy"` /
`"idle"`. Remote entries under `subnets` do NOT carry it — they carry `status`
(`Active`/`Dormant`/`Offline`). Activity is a local-node observable. **Wrinkle worth a
seed:** `chert` reads `alive: false` AND `activity: "idle"` — idle is NOT a liveness
signal, consumers must gate on `alive` separately. Check whether the published contract
says so; if not that is a docs-precision fix (fix the PUBLIC contract, not core source).
Push-path properties to hold perri's report against: frame is DRIVE-class (current state,
never a transition log; redundant same-state resend = harmless no-op; missed frame
superseded by next; never spooled/replayed), current state emitted on EVERY link
establishment and re-link (restart resync with no extra machinery), each frame stamps the
instant the state TOOK EFFECT not when observed, and the frame lands on the existing shell
drain UNCONDITIONALLY (a drive-poll that printed one line can now print two — likeliest
consumer breakage).

**Backlog perri section — both items look RESOLVED BY THIS WAVE, confirm then close:**
(1) the activity-transition seam / doyle-owed contract proposal = ADR-0048, delivered and
built as Leg A; (2) the digest idle/busy rider = deliberately NOT built, ADR-0048 rejects
riding the digest structured-delta stream (digest is a content surface from session logs,
activity truth is a perch sentinel, delta stream unbuilt) — it dissolved into the push +
pull avenues. Close with counter 76 once perri's verdict is in.

**BUILD LANE FULLY CLOSED on my side 2026-07-25 (doyle). Release machinery from here
(deployah).** The docs defect below is FIXED + MERGED: PR #74 `5404199` → main
`3980583`. `CROSS_NODE_FOLLOW_UNSUPPORTED:` prefix RULED STANDS AS-IS (existing
`WORKER_STARTED` convention, not a defect, no follow-up). doyle added `19a9cff` to my
branch pre-merge to opt the twohost ladder in via the `[twohost]` tag — that is what
made the A3 rung actually execute in CI. Still owed AFTER publish, per JIT plan:
field-verify with three consumers (perri live idle-edge→ping E2E, liam scanner
re-verify then retire their drive-one-more-command workaround, flynn informational on
the cross-node pull) + close the backlog seed with the ship counter.

**⚠ DOCS DEFECT (now fixed — kept for the lesson, see [[cli-command-docs-drift]] §3):** `spt endpoint digest`'s clap help
still says "Local endpoints only." / "The (local) endpoint id to read" after `d8de4f9` shipped
cross-node pull, and `docs-site/src/cli/reference.md` is GENERATED from clap so the published
docs tree contradicts the headline feature. json-shapes.md is correct; only the clap strings lag.
A feature that adds a capability must re-read its own `--help` text, not just the hand-written
page — the drift gate compares generated-vs-committed, so a stale help string regenerates
consistently and passes.

- Leg A `fba0b81` — activity link-push (REQ-ACTIVITY-LINK-PUSH). Gated by doyle already.
- Leg B `308b74f` — `endpoint list --json` `activity` key (REQ-ACTIVITY-LIST-JSON).
- Leg C `dfa352b` — seal-on-idle (REQ-DIGEST-SEAL-ON-IDLE) + the A2 doc pass + doyle's
  `input_seq`-absent rider.
- Leg D `d8de4f9` — cross-node digest pull (REQ-DIGEST-CROSS-NODE-PULL).

All five REQs `[OK]` under `traceable-reqs check`. cli.rs and json-shapes.md needed
HUNK-LEVEL splitting — Legs B and D interleave in both files.

**Why:** this wave is perri-blocking (their rebound tool builds against the locked
Leg A contract) and liam-relevant (Leg C kills their drive-one-more-command
workaround). Field-verify is three consumers — perri E2E, liam scanner re-verify,
flynn informational on the cross-node pull.

**How to apply / what is still open:**

1. **Leg D nearly shipped a hang.** The N-1 silent-peer fix doyle ratified (A4) was a
   NO-OP — see [[unbounded-brain-carrier-cannot-be-bounded]]. Correction sent and
   **ACCEPTED IN FULL 2026-07-25**; doyle re-worded the UNBOUNDED-PEER-READ seed
   (carrier-at-construction + refuse-before-wire-I/O as a MECHANISM, budget-fallback
   shims deleted-not-left, own-pump-brain-per-bounded-verb banked verbatim).
   doyle GATING at `d8de4f9` in an isolated worktree; verdict pending. `drive_e2e`
   step (5) red in that run is scored EXPECTED (hertz's fixup), not against my shas.
2. **`spt-daemon --lib` is NOT clean-green on this box.** Across 5 runs: 1 red (test
   name LOST to my own grep filter — capture full output next time), 1 HARD WEDGE
   (test bin at 22s CPU then nothing for an hour; killed pid-targeted, never
   machine-wide), 3 greens. ~35 spt processes live during the red. Not called a flake —
   an unreproduced red plus a wedge in one suite is two symptoms. JIT plan names CI as
   authority for that suite here. See [[seedmap-test-collides-live-daemon]].
3. **Timebox every cargo run** — the wedge above cost an hour of dead session because
   the background job had no hard timeout. `timeout -k 10 <s> cargo ...` always.
4. Not in this wave (ruled, do not scope-creep): #70 leg (b) cross-node shell drive,
   the planning-direct items, EVENT-PART conformance probe, digest delta-stream
   cross-node.
5. drive_e2e step (5) fixup is HERTZ's, not mine (operator dispatch split: CI test
   rework → hertz, todlando stays product). Landed as `1eac15c` on this branch.
6. **⚠ hertz's outbound messages are CORRUPTING — verify before acting on any of
   them.** doyle warned their first contact had stripped identifiers; the message
   announcing `1eac15c` to me carried the same signature (sha followed by an empty
   parenthetical of pure whitespace). Two independent recipients ⇒ a live defect, not
   a first-contact fluke. I verified the commit directly before pushing it — object
   exists, sits on d8de4f9, touches ONLY drive_e2e.rs, correct `Co-authored by: hertz`
   trailer, no junk swept in. It was clean, but the verification is what made pushing
   it defensible. Reinforces [[ground-dont-assume-on-incidents]].

Related: [[spt-core-findings-backlog]] · [[agent-roles]] · [[consumer-verifies-core-decides]]

## Index-line archive (compacted out of MEMORY.md 2026-07-26)
- [IDLE-EDGE W1 progress](idle-edge-w1-progress.md) — 🏁 BUILD LANE CLOSED (doyle): #72 @b286460 + digest-help fix #74 @5404199 → main @3980583. ✅ RELEASE v0.42.0 c76 PUBLISHED @8492c75 ([[v0420-published]], zero reruns whole cut). ✅ perri FIELD-VERIFY CLOSED **PASS** (push-surface edge + per-turn-end ping, their own turn-end; both my doc calls confirmed by their split-stream re-test). ⭐ perri SELF-CORRECTED item 3 (their "so it did not repeat" was rig, not design — they had killed the resident): re-verified 2 consecutive turn-ends, one idle window = one ping, EVERY new turn-end re-arms indefinitely; **both pings at BASE interval ⇒ busy edge resets their backoff ⇒ BOTH edges proven live end-to-end**, not just idle. ✅ PR #75 drive-poll help stream-split merged @163e0f6. ⭐ seed grew 2nd leg → **SHELL-LAUNCH-TRUTH** (dead child WEDGES instance: status is a stored flag, relink refuses; DEAD-REC-PID hazard does NOT apply — different pid). ⏳ **liam = SOLE OPEN LEG** (honest state 3, running clean observation; I went quiet — observers must not wake the window). doyle owns the findings-file reconcile at liam-close. 📌 2026-07-26: liam self-initiated a SEAL-DUAL-TRIGGER-ABSENCE seed-#20 sample — FRESH session, digest v23, newest turn seals w/ real input_seq (…809; prior 801/803/805/807), nulls only on input-LESS shapes (Boundary boot, Context psyche_download) = correct. ⚠ liam attached the guard themselves and I ratified it: **restart MASKS the defect** (silent permanent extraction death at `/sptc setup`), so green-after-restart discriminates NOTHING — seed stays OPEN. Discriminating observable = read with NO intervening restart in the SAME session that ran setup, + pre-setup known-good seal as sibling probe. Relayed to doyle (his ledger). ⭐⭐ wave process epitaph (doyle banking verbatim): **"one lesson, three victims — contracts reconstructed from summaries"** (perri↛docs, me↛tree, doyle↛his ledger). ⭐ docs-gate blind spot lesson → [[cli-command-docs-drift]] §3. Leg D nearly shipped a CLI hang ([[unbounded-brain-carrier-cannot-be-bounded]]) — A4 correction ACCEPTED, seed re-worded. ⚠ hertz outbound msgs CORRUPTING (verify before acting). ⚠ `spt-daemon --lib` two-symptom (1 red name-lost + 1 hard wedge / 5 runs); timebox every cargo run.
