---
name: v0173-send-stderr-noperch
description: "2026-07-08 v0.17.3 SHIPPED+applied+live-proven — hook tag-send NO_PERCH was a stdout/stderr mixup, NOT flapping peer/env; spt send status token is on STDERR. Also folded doyle two-slice fix."
metadata: 
  node_type: memory
  type: project
  originSessionId: 0841835d-f331-4ec7-abcd-af2ba0217cd0
---

**v0.17.3 SHIPPED + node-applied + LIVE-PROVEN 2026-07-08 (GH release, adapter update 0.17.2→0.17.3).**
Fixes the tag-send NO_PERCH bug + folds doyle's two-slice commune fix.

**ROOT CAUSE (operator RCA directive was right — NOT flapping peer, NOT env):** `spt send` writes its
result token (`SENT:<id>`/`QUEUED:<id>`/`DEFERRED:<id>`/`NO_PERCH:<reason>`) to **STDERR**, stdout is
EMPTY. The hook's stdout-only `HookEnv::spt` helper (`stderr(Stdio::null())`) saw `""` → `send_landed("")`
false → confirm-back reported `NO PERCH (not delivered)` for EVERY `@<peer …@>` send though it DELIVERED.
Self-send confirm-back was unaffected (it ignores its own result — so "self works, peer NO_PERCH" was the
tell, not proof of daemon reachability). v0170 memory's "NO_PERCH = flapping peer" conclusion was WRONG;
superseded here.

**DIAGNOSTIC METHOD (reusable):** the CC **Bash tool subprocess ≈ the hook subprocess** (both CC
children) — but my Bash `spt send` used `2>&1` so it SHOWED the stderr token (QUEUED) and looked fine.
Decisive repro = an **isolated hook-binary rig**: copy the installed `claude-spt.exe` to scratch (own
`state/digest/<id>.pos` cursor dir — no interference w/ live session), craft `transcript.jsonl` with a
real `@<lia …@>` assistant line, seed cursor `0`, feed a `{"hook_event_name":"Stop",...}` payload, run
`claude-spt.exe hook Stop`. The confirm-back it fires to my own perch STATES the verdict. TRAP: dispatch
matches `Stop` (capital) — CLI arg `stop` (lowercase) → `_ => {}` no-op (my first rig run bailed silently
on this). Instrumented build (`env.log` the raw `spt()` return) showed `raw=Some("")` = the smoking gun.
Then `printf x | spt send --from perri lia 2>/dev/null` (stdout) = empty vs `2>&1 1>/dev/null` (stderr) =
`SENT:lia` → confirmed the stream.

**FIX:** new `HookEnv::spt_send(args, stdin)` captures stdout+stderr MERGED (token found wherever core
emits it); `scan_and_dispatch` peer-send classifies through it (NOT `spt`). Do NOT globally merge stderr
into `spt` — `whoami --json`/get-string parse clean stdout, merging would corrupt them. `spt_strict`
already pipes stderr but returns stdout-only on exit-0 → no help. REQ-HAZARD-SEND-STATUS-STDERR
([impl,unit]). Regression test: Recorder `with_send_responder` (distinct stdout-vs-merged responder) +
`stdin_for` (confirm-body capture) — models empty-stdout+stderr-token, asserts confirm says
`delivered → lia`; FAILS on old stdout-only path. Filed **F-031** to doyle (SENT): doc the stream or
mirror token to stdout for `$()` capture.

**Two-slice fix folded (doyle finding, REQ-COMMUNE-CONTEXT-TIER-SLICING [impl,unit]):** both commune
prompts now teach the `<project-context>…</project-context>` vs `<live-context>…</live-context>`
envelope so core routes context per-agent-per-project (untagged → all lands in live tier). Sites:
`adapter/strings/briefs/live-ops.md` (agent-authored commune) + `echo_commune.rs::compose_prompt`
(no-signoff summarizer). `<project-context-resolved name/>` sentinel = core OUTPUT only, never
agent-authored. Contract per CHECKPOINT-COMMUNE-PLAN §STDOUT (same tiers psyche-download re-emits).

**FIELD FACTS:** hook tag-send fix rides the binary (hooks resolve fresh per-event from install dir) →
`spt adapter update` activates it with NO session bounce. Live-verified: post-update rig fired a real
lia tag, confirm-back landed `[tag-send] delivered → lia` (pre-fix: `NO PERCH → lia`). 226 tests, gate
PASS. Cross-build: zig at `~/.sptc-zig/zig-x86_64-windows-0.14.1` on PATH + `cargo-zigbuild build
--release --target x86_64-unknown-linux-gnu`; then `ci/publish/package-adapter.sh --apply` → dist/
adapter.spt; `gh release create v0.17.3 --repo SaberMage/claude-spt "dist/adapter.spt#adapter.spt"`.

**NEXT:** NEXT-WORKLOAD-PLAN Items 3 (`/sptc:role` edit round-trip), 4 (update-nudge), 5 (commune-poll
wording), each to a published GH release. See [[v0170-tag-messaging]] [[stuck-active-idle-blackhole]].
