---
name: registry-lifecycle-progress
description: "REGISTRY-LIFECYCLE ✅ CLOSED 2026-07-17 (hertz field PASS): 4 waves, 4 PRs, 2 releases (c64+c65), zero gate rounds, zero bad bytes — all in one day"
metadata: 
  node_type: memory
  type: project
  originSessionId: b155a5e6-a87c-416f-b029-d9cbc4ffd83e
---

**REGISTRY-LIFECYCLE — ✅ CLOSED 2026-07-17 (doyle ruling on hertz field PASS).** Final field
numbers (both nodes v0.37.1): brain CPU mean 8.39->3.48%/core (hot samples 27->7/90, ~16s
burst clusters GONE, residual 1-3s blips = accepted epoch-write seed); reads 63.91->0.269
MiB/s; broker 1.64%, 49 named threads; poisons 0; no wake loops. Record: 4 waves 4 PRs
(#22/#23/#24/#26) zero gate rounds, CI first-try x5, 2 releases (v0.37.0 c64 + v0.37.1 c65
fast-follow from hertz's CPU HOLD — field gate working as designed), 15 REQs, 1 live bug
caught by new int leg mid-build, 1 dropped rider recovered, 0 bad bytes, 0 ungrounded reds.
Seeds carried: gossip-consults-index (ADR-0037 parity), epoch-mint batching,
input_ack_deadlock watch, endpoint-key passive residual. Original milestone header below.

**REGISTRY-LIFECYCLE — ACTIVE MILESTONE** (operator fired 2026-07-17: "roll together
REGISTRY-STALL and DAEMON-LIFECYCLE into one milestone. plan and begin building + drive to
release publish"). Target **v0.37.0 counter 64**.

**Triage landed main @1b54e50** (doyle 2026-07-17): docs/REGISTRY-LIFECYCLE-TRIAGE.md (wave
plan) + ADR-0040 (bounded stream/seat lifecycle: one-way terminal at FIN, server-side
eligibility filter, transactional feed apply, bounded one-way replay, cross-family seat
release via new KIND_NET_STREAM_UNSUBSCRIBE, lease classes ConnectionBound/Durable, thread
naming) + ADR-0041 (endpoint lifecycle truth: online earned not declared, control-cleanup
split from offline classification, atomic terminal rest-normalize, validated stamp
convergence, KIND_SPAWN_FRESH typed conflict, one liveness authority) + KNOWN-HAZARDS
7.44/7.45 + 14 REQs in traceable-reqs.toml (stages flip per wave at build start —
CI gates `traceable-reqs check`, so triage lands stages=[]; builder flips in-branch).

**Waves:**
- **W1 REGISTRY-STALL — ✅ GATED + MERGED 2026-07-17 @68c3223 (PR #22).** Doyle gate:
  full-diff code review PASS, all 5 design calls ACCEPTED; CI green both runners FIRST TRY;
  isolated-worktree confirm heavy substrate 29/29 (D1/D1b + T1-T7 + mesh + registry_lifecycle
  3/3) + lib units 548/548 (2 leaky = known exe-leak class). Worktree cleaned (scoped sweep).
  Gate note: shared checkout found on the W1 branch AGAIN post-merge (2nd strike today).
  Build detail below (kept for W2 reuse — L2 leases ride W1 seat machinery). All R1-R7 landed;
  binding legs green (D1/D1b + T1-T7 + mesh-recovery). Preflight: FULL battery 1898/1898
  FIRST TRY (1 skip = twohost gate); clippy workspace 0; xtask OK; traceable exit 0 (W1
  seven flipped in commit 1 per doyle's order). 3 commits: 09f36cf R1+flips+ADR doc tags /
  d887feb R2-R6 impl+units / 6ff2446 R7 seam+HEAVY ×3 strings.
  **BUILD MECHANICS (todlando's calls, flagged in PR body for gate):**
  (a) R2 `terminal: bool` = additive field on EXISTING net-stream-retire (N-1 = plain
  retire); terminal = PHYSICAL teardown via NetHost::retire_stream_terminal.
  (b) Requester-side release beyond the two named call sites: request_sync/request_update
  wrappers unsubscribe + terminal-retire own row at pull end (the cross-family pump-carrier
  seats from hertz's correction — dispatch workers use fresh conns, swept at close; only
  requester legs on the LONG-LIVED carrier leak); gated OFF io::ErrorKind::TimedOut
  (carrier wedge → supervised restart sweeps; never compound bounded waits, KH 7.43).
  (c) Completed serves terminal-retire on the WORKER'S OWN conn — ordered behind its reply
  frames (same serial IPC handler) so the late-reply overtake race behind ADR-0038's
  eligibility-only rule can't fire; ATTACH EXCLUDED (Durable, brain-swap continuity).
  (d) one-way scope = Registry EXACTLY (Notif/WanMsg carry durable rows/replies); one-way
  Transient exhaustion ALSO terminal-retires. outcome_transition → (ClaimState, retire).
  (e) R6 verb pair KIND_NET_STREAM_UNSUBSCRIBE/_UNSUBSCRIBED mirrors retire req/ack (no
  sister format exists); seat writer JOINED via stored JoinHandle + dismiss() outside all
  locks; plain retire now dismisses seats too; threads named sub-writer-s<id>/-presence/
  broker-conn; net-status +streams_held/+stream_seats gauges (additive) = plateau
  observables. New counted valve SPT_DISPATCH_INJECT_REGISTRY_SEATBLOCKED=<n>
  (post-classification, Registry-only — the ONCE valve fires pre-classification).
  (f) R7 poison-absence asserted STRUCTURALLY (rows/seats/write-counter plateaus; in-proc
  rig can't grep own stderr) — capture leg offered if doyle wants it.
  (g) tests/dispatch.rs direction-fact test updated to new wire contract (the one
  OLD-behavior assertion the grep sweep found; all other sites filter FOR peer rows).
  R1 OnceLock realized inside current_exe_hash (write_ready's only hash entry) with the
  pre-loop write_ready as capture point.
  R1 REQ-BRAIN-HASH-ONCE · R2 REQ-ONEWAY-STREAM-TERMINAL · R3
  REQ-STREAM-INFOS-SERVER-FILTER · R4 REQ-REGISTRY-APPLY-TRANSACTIONAL (FeedAccumulator
  bound 4096 + apply_feed_batch one-lock-one-write + snapshot_write_count() observable) ·
  R5 REQ-REGISTRY-REPLAY-BOUNDED (ONEWAY_POISON_STRIKES=3) · R6 REQ-SEAT-LIFETIME-BOUNDED ·
  R7 REQ-HAZARD-REGISTRY-STALL (tests/registry_lifecycle.rs: plateau+drain+gen2-zero-replay
  5.3s, multichunk-one-write 0.2s, strike-out-then-fresh-serve 14.2s).
- **W1 GATE PASSED + MERGED @68c3223 (doyle 2026-07-17):** all 5 design calls ACCEPTED as
  built; CI green both runners first try; isolated-worktree confirm heavy 29/29 + units
  548/548. W1 branch pruned local+remote; gate-8981d81 skeleton removed.
- **W2 ENDPOINT-LIFECYCLE — ✅ BUILD COMPLETE 2026-07-17 (todlando), PR #23 @4e55065 on
  build/registry-lifecycle-w2 (base 68c3223), AWAITING doyle gate; ping SENT.**
  Commits: 9630ed7 (W2 five REQs flipped + ADR-0040/0041 doc tags) / b7debb6 (L1-L4
  impl+units) / 4e55065 (KH 7.45 int matrix + HEAVY ×3 strings + relatch-window fix).
  Preflight: FULL battery first pass 1910/1911 → REPEAT 1911/1911; the one red =
  input_ack_deadlock cold-pass, DISPOSITIONED not-diff-coupled (CB sweep runs strictly
  post-verdict + duplicates the test's own detach FIN; gate legs = pure wall-clock
  watchdogs; battery-repeat green + solo ×5 green 32.0-32.5s stable; if CI reds it →
  fresh sighting → hertz). clippy workspace 0; traceable exit 0. Matrix 4/4 green.
  **BUILD MECHANICS (todlando's calls, flag in PR body for gate):**
  (a) L1 creator gate = pure listen_online_gate(live_capable, persisted_state) —
  online iff capability AND persisted state==live_agent (mirrors cmd_bind's guard).
  (b) L1 hybrid self-heal scope EXACT: state!=live_agent && controllable==Some(false)
  && numeric pid DEAD (BUSY/absent never guessed; gateways None + daemon-hosted
  Some(true) exempt — daemon_hosted_online_survives_dead_pid liveness model preserved).
  Heals TERMINALLY (offline+suspended) CAS-guarded on observed session_id.
  (c) L1 split cleanup clears ALL THREE stamps (viewer_count added — serves decision-4
  "every no-session path clears all three") for EVERY row absent from session truth;
  OLD relay-exempt assertions in pull_liveness test updated per ADR-0041 decision 2.
  (d) L3 = spt-store terminal_normalize(perch, expected_session_id) via mutate_info
  (one sentinel-locked write; CAS Some(sid) skips a newer bind, None=unconditional for
  operator stop); wired: mark_offline (reap), cmd_stop, signoff teardown (+ address
  unregister on CAS hit). Custody gate: reconcile DEFERS normalize while resume.pid
  probes alive (bind carries rest forward by design — REQ-HAZARD-BIND-REST-STATE-CARRY
  — so normalizing mid-revival would strand the seat suspended).
  (e) L4 mechanism choice (design freedom): per-endpoint StampSlot {gen: AtomicU64,
  write: Mutex} global map in broker; reap bumps gen under write serial then clears;
  KIND_SESSIONS Phase-B snapshot captures gen, Phase-C converge validates under the
  serial (stale → STAMP_STALE_SKIP loud). Late-bind convergence unchanged.
  **BONUS PRODUCT BUG the int leg caught live: exit-waiter cleared stamps BEFORE
  sessions.remove — poll snapshot in the gap read NEW gen + occupied controller slot →
  legitimate relatch. Fixed: remove-then-bump+clear.**
  (f) L2 wire = StreamLifetime {Durable(default), ConnectionBound} kebab-case, additive
  serde field on NetStreamOpenReq (Durable omitted → N-1 byte-identical); class stored
  on StreamEntry + surfaced additive on NetStreamInfo; RC attach/view
  (request_attach_endpoint) opens ConnectionBound; broker conn loop tracks my_cb_streams,
  conn-exit sweep FINs (send_stream empty+fin) then retire_stream_terminal (W1
  machinery reused, no second mechanism); target sees plain FIN (class never crosses
  wire); late-close identity rides existing detach_if_gen (fix-6) — tagged.
  (g) L5 matrix in tests/endpoint_lifecycle.rs (4 legs); wake-leg observable =
  Refuse host_error stamp (unregistered recorded adapter) — fires on Active, absent on
  suspended, StandDown on live custody pid. HEAVY at birth ×3 strings.
- **W2 ✅ GATED + MERGED 2026-07-17 @a80ede5 (PR #23, doyle).** All 6 design calls ACCEPTED;
  bonus relatch fix verified race-sound; input_ack_deadlock 1-sighting disposition ACCEPTED
  (mechanism verified: CB sweep post-verdict; CI green both batteries + isolated confirm) —
  WATCH-ONLY, fresh sighting → hertz. CI first try; local confirm 35/35 (matrix + substrate
  + input_ack_deadlock + brain_swap). Checkout drifted to builder branch 3rd time — sweep
  habit now standing.
- **W3 SPAWN-TRUTH — ✅ BUILD COMPLETE 2026-07-17 (todlando), PR #24 @37d6a59 on
  build/registry-lifecycle-w3 (base a80ede5), AWAITING doyle gate; ping SENT.**
  Commits: 0d01057 (REQ flips + ADR-0041 decision-5/6 doc tags) / 63fa574 (S1+S2
  impl+units) / 37d6a59 (spawn_truth int 6/6 + run_no_dup B1 create-conflict update +
  HEAVY ×3). Preflight: FULL battery 1919/1919 FIRST TRY (4 leaky = known class, 1 skip =
  twohost); clippy 0; xtask check OK; traceable 0. **W3 MECHANICS (todlando's calls, flag in PR body):**
  (a) S1 wire = KIND_SPAWN_FRESH + typed KIND_SPAWN_CONFLICT {endpoint, session_id};
  ONE dispatch_spawn_policy (gate+body shared; fresh flag branches only the AlreadyLive
  arm); brain FreshSpawn {Created, Conflict}; NO KIND_SPAWN fallback on unknown-kind
  (loud per ADR); SPT_TEST_SPAWN_FRESH_UNSUPPORTED valve mirrors the T7 opener valve.
  (b) CLI create-default (bare run, no --resume) CONFLICTS over live in BOTH attach +
  headless modes (exit 1, "ENDPOINT_CREATE_CONFLICT:<id>: ... no session was created");
  Reattach/ALREADY_LIVE arms live on under RESUME intent only (product ruling: no silent
  ensure overload). run_no_dup B1 updated w/ citation; B4 unchanged.
  (c) S2 verdict = pure zombie_verdict(wrapper_alive, adapter_labeled, live_descendants,
  past_grace): dead root always zombie; adapter-labeled wrapper w/ dead client chain past
  SPT_SPAWN_CLIENT_GRACE_MS (default 30s) = the wedge shape; empty-adapter spawns exempt;
  pid None never guessed. Probe OFF-lock in the gate's AlreadyLive arm; reap = scoped
  kill_pid_tree + bounded exit-waiter wait + force-detable belt. SessionInfo additive
  pid/adapter/spawned_ms_ago → CLI preflight (has_live_session_honest) + shutdown Suspend
  (daemon_rest_event_with_liveness hint) consult the SAME verdict.
  (d) Suspend-teardown deliberately OUT of scope (no production kill-on-suspend exists);
  S2 = one answer, zombie termination rides the dup-guard reap.
  (e) Zombie rig: wrapper survives client death via childless builtin wait (cmd
  "ping & pause" / sh "sleep; read x") — the W2-surviving shape doyle ordered.
  RELEASE WAVE — deployah drives v0.37.0 counter 64 after gate.
- **W3 ✅ GATED + MERGED 2026-07-17 @2c04184 (PR #24, doyle).** All 5 design calls ACCEPTED
  (suspend-teardown out-of-scope ruling endorsed — shutdown EDGES truthfully, termination
  rides dup-guard reap; create-conflict in attach mode = no silent ensure). CI green both
  runners first try; isolated confirm 39/39 (spawn_truth 6/6 incl W2-surviving zombie rig
  + full substrate). **MILESTONE BUILD COMPLETE — 3 waves, 3 PRs, zero gate rounds, all
  14 REQs satisfied, traceable green.**
- **RELEASE — GO SENT to deployah 2026-07-17**: v0.37.0 counter 64 from main @2c04184;
  census surfaces + wire-additions note (KIND_SPAWN_FRESH/CONFLICT, KIND_NET_STREAM_
  UNSUBSCRIBE, terminal flag, StreamLifetime — all additive) in the GO msg. hertz
  field-verify closes the milestone (poison freeze / CPU noise / named census / zero
  WAKE_RESUME). doyle live for ladder-check/HOLD window.

**FIELD-VERIFY 2026-07-17 (hertz): 3/4 PASS, CPU gate FAIL -> MILESTONE HOLD (doyle
disposition SENT, hertz-requested explicit ruling):** PASS legs = zero CONN_WRITE_POISONED
across pump cadences + refresh; broker threads 2039->47-56 NAMED (broker-conn/sub-writer);
broker 2.04%/core; self-hash reads 63.91->0.29 MiB/s; single legit cold-start WAKE_RESUME,
no loops. FAIL leg = brain CPU not-noise: 90s mean 8.39%/core, p95 28.1, max 50, ~16s burst
clusters per 30s Registry round. HERTZ RCA ACCEPTED (doyle seam-verified): recent_projects_for
(registryhost.rs:988-1009) dedups on DERIVED pid after project_id_for_dir -> every
duplicate-cwd ledger row spawns git remote/rev-parse (~200 derivations/round, 12 perches);
+26 epoch atomic writes/round; timing-pinned (16.475s pre-dial phase). PRE-v0.37 path exposed
by self-hash fix. RULING: v0.37.0 bytes STAND (no bad bytes, functional gates PASS); fix =
**W4 FAST-FOLLOW** REQ-GOSSIP-PROJECT-DERIVE-ONCE (main @c2cf35e; cwd-dedup BEFORE derivation,
pid-dedup stays as second layer; unit = derivation-count==distinct-cwds + parity) -> todlando
dispatched (QUEUED) -> v0.37.1 counter 65 -> hertz re-runs 90s CPU sampling = milestone CLOSE.
Lifecycle field legs recorded PASS, do not re-run. SEEDED (not W4): gossip consults ADR-0037
materialized index (readers-never-run-git parity; staleness design change) + epoch-mint
batching — both in [[spt-core-findings-backlog]] queue. GOTCHA: doyle committed W4 REQ on
release/v0.37.0 by mistake (checkout drift #4 — printed branch but did not GATE on it);
repaired via reset + cherry-pick to main @c2cf35e. Branch-check must be a GATE not a log line.

- **W4 FAST-FOLLOW — ✅ BUILD COMPLETE 2026-07-17 (todlando), PR #26 @fe48cd3 on
  build/registry-lifecycle-w4 (base main @c2cf35e), AWAITING doyle gate; ping SENT.**
  Commits: e90a60a (REQ-GOSSIP-PROJECT-DERIVE-ONCE flip ["impl","unit"]) / fe48cd3
  (fix + units). Mechanics: body split `recent_projects_from(entries, owlery,
  derive-closure)` — production wrapper passes project_id_for_dir unchanged; raw-cwd
  HashSet dedup BEFORE derivation; pid-level dedup KEPT as output-uniqueness second
  layer; MAX_GOSSIPED_PROJECTS break still on OUTPUT length only (skipped dup cwd
  consumes no slot, no early-exhaust). Units: derive_once_per_distinct_cwd (63-row
  dup-heavy ledger, count==4 distinct non-owlery cwds + parity), cap_fires_on_
  output_length (12×2 rows → newest 8, scan stops at 8 derivations), existing
  dedups_newest_first_excludes_owlery EXTENDED same rig (real-derive work2/beta
  same-project second-spelling collapse). Preflight: units 3/3; registry_lifecycle
  3/3 + mesh_recovery + full daemon lib 564/564 (4 leaky known class); clippy
  workspace 0; traceable 525/0/0; xtask OK. Out-of-scope untouched. Gate PASS →
  deployah v0.37.1 counter 65 → hertz 90s CPU re-sample = milestone CLOSE.

**W4 ✅ GATED + MERGED 2026-07-17 @0faf173 (PR #26, doyle).** Fix as ordered: recent_projects_from
split w/ injected derive; raw-cwd dedup BEFORE derivation; pid dedup kept as output layer; cap
fires on OUTPUT length (skipped dup consumes no slot — verified in review AND unit). Units 3/3
(derive-once 63-row dup ledger count==4; cap-on-output 8-not-12/24; parity leg extended in
original rig — changed assertion is input-driven not semantics-driven, doyle-verified). CI green
both runners first try; isolated confirm 6/6. **v0.37.1 counter 65 GO SENT to deployah** (single
end-user CHANGELOG entry drafted: periodic ~30s CPU spikes on long-history nodes). hertz re-runs
90s CPU sampling on v0.37.1 = milestone CLOSE.

**v0.37.1 PUBLISHED counter 65 @c616c9f (PR #27, deployah 2026-07-17)** — W4 fast-follow live,
single end-user CHANGELOG entry, CI first try, gen clean. **hertz CPU re-verify GO SENT** (90x1s
sampling, two pump cadences; expect burst clusters gone, ~2% baseline; epoch-write blips = seeded
not gated). hertz PASS = MILESTONE CLOSED.

**Lane:** todlando builds (PR per wave to main) → doyle gates (isolated worktree, throwaway
target, nextest, clippy --workspace preflight, alarm every test run) → deployah releases
v0.37.0 counter 64 (bump-in-PR, CHANGELOG by observable surface, end-user voice per
RELEASE-RUNBOOK step-2). **hertz = standing roadblock-RCA role this milestone (operator
ruling 2026-07-17): every unexplained red/wedge routes to hertz for RCA first; nobody fixes
an ungrounded red.** hertz field-verifies release against preserved baseline
(poison-count freeze, CPU to noise, bounded+named thread census, zero WAKE_RESUME).
All three notified + todlando ACKed 2026-07-17.

**Sources:** canonical RCA .claude/reports/2026-07-17-registry-stall-rca/README.md
(hertz, doyle-verified all legs; incl. family-agnostic seat-retention correction +
dropped-W4-rider provenance). DAEMON-LIFECYCLE reports verbatim in
[[spt-core-findings-backlog]]. Field evidence hertz-preserved (log + 5.7MB snapshot,
15 poisons at snapshot).

**Gotchas so far:** CI runs `traceable-reqs check` on main → NEVER land activated stages
with triage (learned pre-push this time); builder flips stages as first build commit.
Shared checkout was left on deployah's merged PR #21 branch pre-triage — always
branch-check.

Related: [[redispatch-stall-progress]] (substrate), [[v0360-published]],
[[spt-core-findings-backlog]] (original seeds), [[dont-solo-across-role-lines]].
