---
name: omp-spt-psyche-download-gap
description: "RCA 2026-07-27 — hertz resumes with no memory because omp-spt never calls `spt api psyche-download`; core docs described the pull as hook-only"
metadata: 
  node_type: memory
  type: project
  originSessionId: 05ad48d2-2229-4f67-9c5b-7f322bec6a2e
  modified: 2026-07-28T03:44:44.299Z
---

**✅ CLOSED 2026-07-27.** Adapter fix shipped as **omp-spt 0.3.32** (emphasys); core docs fix
merged as **PR #114** @e165f71. Outstanding operator action: `spt adapter update omp-spt` +
**restart** hertz's endpoint (the extension only loads at session start).

**⭐ The docs got field-verified within the hour — and the adapter's two deviations were both
right.** emphasys built 0.3.32 from the amended pages and diverged twice, so I folded both
back in: (1) **authenticate with `--token`, not `--session-id`** — a sid is also a lifecycle
lever (dead-owner rescue re-pins the perch) and a read-only pull must not write lifecycle
state; the page had listed them as equal proofs with a caveat bolted on. (2) **stdout is the
mind, stderr never is** — his runner folded the streams, which would have injected
`NO-CONTEXT:<id>` and repin lines into the model's context *as* the agent's mind; the page
never said which stream carried what. This beats a blind consumer read
([[blind-consumer-read-beats-author-checklist]]): a consumer who actually *built* against the
page found what no reviewer would.

**Root cause (proven statically, three independent probes):** `omp-spt` never calls
`spt api psyche-download <id>`. Occurrences: **0** in `omp-spt.exe`, **0** in the packaged
extension `strings/omp-spt.mjs`, **0** in `manifest.toml` (which declares no `[hooks]` at
all). The extension's actual api verb set is `endpoint-info`, `bind`, `listen`, `poll`,
`state`, `session-end`, `boundary` — Groups 1–2 of the integration checklist are complete
**except this one verb**.

**What hertz reads as his "session brief" is the repo's static `AGENTS.md`** — verbatim,
including its stale `$OWL send` / `$LIVE list` line. That is why he sounds months out of date.

**Measured cost, same node:** hertz live-context 329 B / project-context 462 B, vs doyle 4080,
todlando 3017, deployah 2443. hertz's tracked mind has **never** exceeded ~440 B across its
entire git history (`tracked/.seed.git` worktree) — nothing was lost, it never accumulated.
Self-reinforcing: blank start → the echo-commune can only synthesize a blank session → the
tier is replaced by that thin synthesis.

**⭐ Lesson — hook-shaped prose hides a contract obligation from a harness with no hooks.**
Both harness-contract pages said "fire from SessionStart, inject its stdout". `omp-spt` is
spt-hosted and extension-owned: it has no `SessionStart` to hang anything on, wired every
surface described in shape-neutral terms, and missed the single surface described only in
hook terms. Not an attention failure — a documentation failure mode. Fixed core-side in
**PR #114** (start-path obligation naming hook / post-bind extension / go-live, plus the auth
requirement the page never stated, plus the operator check: *ask a RESUMED agent what it
knows; if the answer is only the repo's static agent-instructions file, the pull is missing*).
See [[adapter-impl-question-triage]] — this was a docs-gap, not an adapter miss, and was
routed that way.

**⚠ Verify claims against shipped code, not against an old hazard note.** The first draft of
the `--session-id` warning repeated claude-spt's manifest note ("SESSION_REPINs the perch to
whatever sid is passed, unvalidated"). `crates/spt/src/api/auth.rs` has since narrowed it: with
a **live** owner a mismatched sid is refused outright; the re-pin only fires as the loud
dead-owner rescue and is refused when the sid owns another perch or is a Psyche custody sid.
Caught before publishing.

**Adapter-side tail — emphasys ACCEPTED it as his and took the fix.** Call `psyche-download`
after `api bind` with the bound sid, inject stdout as the opening context. His own evidence:
six api verbs in the extension, `psyche-download` in none of the extension / Rust helpers /
manifest; only prior trace is `CHECKPOINT-COMMUNE-PLAN.md` T3, written and never wired. He
also improved the spec — on omp-spt, `/ready`, `/live`, `/live --auto` and hosted spawn all
funnel through one `activateEndpoint` seam, so **one** post-bind insertion covers the go-live
case too (a property most harnesses lack, so the docs state it generally).

**❌ WITHDRAWN — my "second defect" was misattribution.** I flagged
`strings/briefs/live-ops.md` (drop `.claude/<id>-commune.md`) as contradicting omp-spt's
`commune_dir = ".spt"`. emphasys challenged it; he was right. Those files sit in **his live
install dir** but are dated **Jul 9 17:57** — an OLD omp-spt brief set (6× `/omps:`,
`omps_messages` — OMP-flavored, sed-adapted from claude-spt, which is where the stale
`.claude/` came from). His current payload stopped shipping briefs; the extension has **0**
references to them, so nothing serves them. Not a live defect — and **not perri's either**;
he was about to route it there and I stopped the misroute. ⭐ Lesson: **a file's directory is
not its provenance** — check mtime and flavor before judging content against the manifest
that happens to own the folder.

**Seeded to doyle (core-side, fell out of the provenance dig): `spt adapter update` leaves
orphans.** That install dir carries three generations — Jul 9 briefs + flat skills, Jul 19
skill subdirs, Jul 27 current payload — plus a foreign `claude-spt.exe` from Jul 9 sitting in
the very directory `{adapter_dir}` resolves to. Update replaces in place and never removes
what the new payload no longer ships. Latent; same `{adapter_dir}` surface
[[shell-launch-truth-seed]] already carries traps on.

**Seeded to doyle (mechanism, not just a rule):** core serves every api verb, so it can detect
this class without seeing adapter internals — warn when an adapter binds a `live_agent` whose
stored mind is non-empty and no `psyche-download` was seen on that sid. Harness-agnostic.
