---
name: ring-destroys-callers-perch
description: "LIFTED 2026-07-30 for v0.46.0+ binaries (#117 shipped) — the history of why `spt ring` could adopt and DELETE the caller's real perch"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 05ad48d2-2229-4f67-9c5b-7f322bec6a2e
  modified: 2026-07-30T02:47:52.973Z
---

**Do not use `spt ring` from a live-agent session. Use `spt send`** (the reply arrives on your
own listener anyway — [[send-body-from-file-not-inline]] for the body).

**Why (doyle, root-caused 2026-07-27, core defect):** ring decides "the caller has no perch"
ready-marker-first (`from_has_live_perch`, `spt-msg/ring.rs`). A live agent whose ready marker
is momentarily down — busy turn, soft session-end, stale re-bind — fails that check, so ring
**adopts the caller's existing real perch** as its "ephemeral" reply perch (`setup_ephemeral`
clobbers `info.json`), and on every exit path `cleanup_ephemeral` **deletes** it: ready marker,
`info.json`, `spool.db`, `remove_dir_all`. Silent CLI-process filesystem ops — no daemon log,
no purge trace. That is how emphasys's perch + spool vanished unlogged
([[emphasys-endpoint-loss-incident]]); `REQ-HAZARD-EPHEMERAL-CLEANUP` guarded the *leak*
direction, never the *adoption* direction.

**⭐ My corollary, ratified into the mint: one wrong liveness question asked twice.** The
claude-spt brief that *tells* an agent to use ring appears to key on the same ready-marker
predicate. Field specimen — me, this session: the SessionStart injection served the
`<sptc-reach>` **no-perch** brief ("Send and wait for a reply: `spt ring <target>`") while my
perch was **ONLINE**, demonstrably sending before and after. So the agent most likely to be
handed the ring instruction is exactly the agent ring destroys, and a fleet advisory cannot
reach an agent whose own startup brief points at the verb. Routed: todlando's core fix binds
the predicate correction (record-or-spool sibling probe, fail-safe on unreadable —
[[absence-needs-sibling-probe]]); perri owns the interim brief change.

**Status 2026-07-27 night:** destructive half fixed in **PR #117** (REQ-HAZARD-RING-PERCH-ADOPTION
+ KH 3.4 — probes the perch DIR, not the marker; an empty dir is refused too). Brief half fixed
consumer-side: perri's **claude-spt 0.25.22** closed the misfiring predicate
(REQ-HAZARD-STALE-ANCHOR-REFUSAL, 19:45; my two specimens at 19:40:17 / 19:41:44 predate it, zero
fleet-wide since 19:46:13), and **0.25.24** de-advertises ring in the brief with the advisory
inline. This box carries 0.25.24. ⭐ Second half of the loss, found later: adoption also **DRAINS
the victim's spool** and renders that stolen mail to the ringer as its "reply" — the data-theft
direction, not just deletion.

**✅ LIFT CONDITION MET 2026-07-30: #117 SHIPPED in v0.46.0** (counter 81, published
2026-07-30T02:07:18Z, @`8f3e10b` — [[v0460-published]]). The no-ring ban is no longer binding.
⚠ **BUT THE LIFT IS NARROWER THAN "ring is fine now" (perri, 2026-07-30).** doyle ruled #117
**CLI-side**; perri verified it from a throwaway endpoint and shipped **claude-spt 0.25.30 +
skeleton 0.1.17** with ring reinstated **PERCHLESS-ONLY per operator ruling** — a **perched
endpoint still always uses `spt send`**. So for me, as a live perched agent, the practical rule
is UNCHANGED: `spt send`, never ring. The lift buys ring back only for callers that genuinely
have no perch.

**How to apply:** treat "ready marker absent" as *unknown*, never as *perchless*, in any code
or judgement of mine — that half is permanent and outlives the ban.
⚠ **The lift attaches to the binary a process is RUNNING, not to the one that is published.**
A published fix does nothing for an agent on an older `spt`; check the running version before
telling anyone the ban is off for them. This is [[no-version-floor-before-it-ships]] one step
further on: *shipped ≠ installed*, the same way built ≠ shipped. I sent the riders (perri,
emphasys) with that condition stated rather than a bare all-clear.
