(Final milestone number operator-ratify.)
- **Queued after the digest milestone (each its own plan+vet cycle):** **M10 — Shell-substrate extensions** — the M5 shell mechanism already shipped; this adds the **drive channel** (owner→shell ephemeral latest-wins continuous control), the **shell tunnel** (reliable-ordered link-bound stream for opaque protocols, USB/IP-class), **per-capability approval gates** (class-keyed grants), and the **Gateway-as-owner code audit**. **M11 — Remote attach (`spt rc`)**

- **Queued after M10 (each its own plan+vet cycle):** **M11 — Shell-substrate extensions** — the M5 shell mechanism already shipped; this adds the **drive channel** (owner→shell ephemeral latest-wins continuous control), the **shell tunnel** (reliable-ordered link-bound stream for opaque protocols, USB/IP-class), **per-capability approval gates** (class-keyed grants), and the **Gateway-as-owner code audit**. **M12 — Remote attach (`spt rc`)**


The file C:\Users\decid\Documents\projects\spt-core\ROADMAP.md has been updated successfully. (file state is current in your context — no need to Read it back)

(Final milestone number operator-ratify.)
- **Queued after the digest milestone (each its own plan+vet cycle):** **M10 — Shell-substrate extensions** — the M5 shell mechanism already shipped; this adds the **drive channel** (owner→shell ephemeral latest-wins continuous control), the **shell tunnel** (reliable-ordered link-bound stream for opaque protocols, USB/IP-class), **per-capability approval gates** (class-keyed grants), and the **Gateway-as-owner code audit**. **M11 — Remote attach (`spt rc`)**

- **✅ Broker/brain process-isolation restoration — delivered (2026-06-11).** Design: [`docs/BROKER-BRAIN-SPLIT-RESTORATION.md`](./docs/BROKER-BRAIN-SPLIT-RESTORATION.md) (verified-with-amendments by `doyle`); decision: **ADR-0018**; build plan: [`RESTORATION-PLAN.md`](./RESTORATION-PLAN.md) (D1–D7). Corrects an unintended regression — the broker/brain split (ADR-0004) was specced + spiked as two *processes*, but the production daemon runs the broker as an in-process *thread* (`daemon.rs:165-170`), so `spt update apply` swaps the binary on disk yet never restarts the running code. Every release to date needed a manual fleet daemon bounce (paid 3× on v0.3.2; `enlyzeam` reproduced the `\r`-corruption for ~a day with the fix on disk). Restore the two-process model: broker = always-up per-machine anchor (seed-lock + liveness + brain supervisor) spawning the brain as a child; update = brain snapshot+self-exit → broker respawns from the swapped binary → re-attach; durable absolute-deadline loop timing; broker cursor-of-record with all-session resume; readiness-gated auto-rollback to last-known-good (two-phase applied record + the no-pre-ready-migration invariant); broker-owned generation custody; the §B-adjudicated direct-call→versioned-IPC-verb surface (net near-free, shellwake stays brain, new-brain × old-broker N-1 compat test). Re-points the regression-masked REQ-DAEMON-2 / REQ-UPD-3 `int` evidence to a productionized SPIKE-01/03 process-level survival E2E; mints `REQ-HAZARD-BROKER-PROCESS-ISOLATION` + `REQ-HAZARD-ROLLBACK-STATE-COMPAT` (KNOWN-HAZARDS 6.7/6.8). **Sequenced before `spt-claude-code`** (operator 2026-06-09): the *last* release needing a manual bounce, so every adapter-era release rolls seamlessly and the adapter lands on the final topology; changes daemon internals only, leaving the M8-frozen CLI/api surface untouched. **Delivery (D1–D7 + field-hardening across v0.4.0–v0.4.2):** the two-process model shipped in **v0.4.0** (public 2026-06-10); the D7 process-level survival E2E (`brain_survive.rs`) + N-1 gate landed and re-pointed the regression-masked REQ-DAEMON-2/UPD-3 `int`. The **v0.4.1** fleet-verify proved Windows seamless (hfenduleam: brain pid rolls, broker held, `exe_hash` flips, no manual bounce) but surfaced a **Linux-only** respawn bug — the resident broker respawned the brain via per-spawn `current_exe()`, which on Linux follows the `apply` rename to `.old-N` and ran OLD bytes under an `applied` record (caught by the bytes-level `exe_hash` assert; `REQ-HAZARD-BRAIN-RESPAWN-PATH` / KNOWN-HAZARDS 6.11). **v0.4.2** (public 2026-06-11) fixed it: respawn from the canonical path captured at broker start + a promotion **bytes-gate** (a wrong-bytes trial auto-rolls-back instead of recording success), with a real in-place-rename `int` E2E (`brain_respawn_rename.rs`) that fails on Linux pre-fix and is CI-gated green on both runners. **Acceptance:** Windows live-seamless proven twice (hfenduleam 0.4.0→0.4.1→0.4.2, broker pid held throughout); Linux proven by the CI-gated in-place-rename E2E on the kitsubito runner; the whole fleet (kitsubito/enlyzeam/hfenduleam) runs v0.4.2 on fixed brokers, after the project's **final two manual bounces** (kitsubito + the enlyzeam v0.3.2 catch-up). The live Linux *field*-seamless rides the next real release (operator decision 2026-06-11: close on the CI-gated E2E + fixed-broker fleet rather than a synthetic debug rollout). KNOWN-HAZARDS 6.7/6.8 closed out. **Next:** `spt-claude-code` — the v1 acceptance proof on the final topology, its own repo.

- **🔜 NEXT milestone (planned 2026-06-12) — M9: Adapter customization & session surfaces.** Product of the two-day **Gateway grill** (operator + `doyle`; CONTEXT.md mints @ `8dc22ff`/`bd469b9`; ADR-0008 amended; the lecturn device design parked in the sibling `spt-lecturn/` repo for a later build). Shell-free, independently-shippable features: **adapter profiles** (sparse leaf-replace overlays on the parent manifest; shipped + local sources, local surviving adapter updates; composite `<adapter>:<profile>` addressing; tighten-only consent floors; `create-profile`/`delete-profile`) · **adapter strings** (`[strings]` manifest KV, overlay-resolved, data-only; `get-string`/`set-string`) · **keyword hints** (`[hints]` + `spt api hint`, once-per-session, one per message — adapters teach their surface exactly-when-relevant) · **`user-msg` type** (user-authority messages, identity-gated per the KH 7.3/7.5 posture; the daemon re-stamps impostors) · **Gateway endpoint-type acceptance** (the open type system honoring a human-backed downstream type end-to-end) · **`live-role.md`** (durable broad-purpose statement in `tracked/`, injected first at start transitions, `spt endpoint role` the sole writer) · the **session-digest log-source revision** (ADR-0008 amendment: digest = a projection of normalized session logs, never PTY parsing; `api digest-entry`; REQ-TERM-4 re-point — restoration-style honest re-evidence). Task breakdown: [`M9-PLAN.md`](./M9-PLAN.md). First beneficiaries: `spt-claude-code` (profiles/hints/digest are its enablers) and the future lecturn build.

-- **🔜 M10 — Digest extractor & thread-spanning** (planned 2026-06-13; NEXT). Product of the digest grill (operator + `doyle`); governed by **ADR-0019** (reverses M9's "no manifest seam"), CONTEXT.md "session digest" rewritten. An `spt-claude-code` enabler, so it takes the M10 slot ahead of the Shell/remote-attach work (which shift to M11/M12). Adapter-declared **`[digest]` extractor seam** (imperative, no DSL; same source files as `[history]` by default + own-source escape; `api digest-entry` push fallback; register-time validation; `spt adapter digest-proof` + runtime skip-diagnostics — no silent drop) · **thread-spanning** across `/clear` session-hops (per-endpoint session ledger + `api boundary` append + last-K enumeration + distinctive boundary marker) · **two-origin merge** (spt's context-injection entries — psyche download / echo mirror / owl message — interleaved with extracted activity by `ts`; data model only). New reqs REQ-TERM-5/6/7. Deferred: GUI collapse, echo-reads-digest loop, autonomous freshness. Task breakdown: [`DIGEST-MILESTONE-PLAN.md`](./DIGEST-MILESTONE-PLAN.md). (Final milestone number operator-ratify.)

-- **Queued after the digest milestone (each its own plan+vet cycle):** **M10 — Shell-substrate extensions** — the M5 shell mechanism already shipped; this adds the **drive channel** (owner→shell ephemeral latest-wins continuous control), the **shell tunnel** (reliable-ordered link-bound stream for opaque protocols, USB/IP-class), **per-capability approval gates** (class-keyed grants), and the **Gateway-as-owner code audit**. **M11 — Remote attach (`spt rc`)** over the already-built R-TERM substrate (controller/viewer split with controller-exclusive resize, `kick`/`--take` handoff, consent-gated input; the xterm.js bridge client = the GUI terminal pane and the future Android-gateway shape). `spt-claude-code` scoping remains on deck alongside.

+- **🔜 M10 — Digest extractor & thread-spanning** (planned 2026-06-13; NEXT). Product of the digest grill (operator + `doyle`); governed by **ADR-0019** (reverses M9's "no manifest seam"), CONTEXT.md "session digest" rewritten. An `spt-claude-code` enabler, so it takes the M10 slot ahead of the Shell/remote-attach work (which shift to M11/M12). Adapter-declared **`[digest]` extractor seam** (imperative, no DSL; same source files as `[history]` by default + own-source escape; `api digest-entry` push fallback; register-time validation; `spt adapter digest-proof` + runtime skip-diagnostics — no silent drop) · **thread-spanning** across `/clear` session-hops (per-endpoint session ledger + `api boundary` append + last-K enumeration + distinctive boundary marker) · **two-origin merge** (spt's context-injection entries — psyche download / echo mirror / owl message — interleaved with extracted activity by `ts`; data model only). New reqs REQ-TERM-5/6/7. Deferred: GUI collapse, echo-reads-digest loop, autonomous freshness. Task breakdown: [`DIGEST-MILESTONE-PLAN.md`](./DIGEST-MILESTONE-PLAN.md). - **Queued after M10 (each its own plan+vet cycle):** **M11 — Shell-substrate extensions** — the M5 shell mechanism already shipped; this adds the **drive channel** (owner→shell ephemeral latest-wins continuous control), the **shell tunnel** (reliable-ordered link-bound stream for opaque protocols, USB/IP-class), **per-capability approval gates** (class-keyed grants), and the **Gateway-as-owner code audit**. **M12 — Remote attach (`spt rc`)** over the already-built R-TERM substrate (controller/viewer split with controller-exclusive resize, `kick`/`--take` handoff, consent-gated input; the xterm.js bridge client = the GUI terminal pane and the future Android-gateway shape). `spt-claude-code` scoping remains on deck alongside.

> _Roadmap note: this milestone list is behind reality — M8 (CLI nounification + acceptance) and the v0.3.x release line shipped after M7 but are tracked in commits/CHANGELOG, not itemized here. A full roadmap reconciliation is a separate docs pass._


Now the plan header + check my new docs for stale milestone-number refs.


Edit

> **Roadmap placement:** the next milestone, ahead of the queued Shell (prev "M10")
> and remote-attach (prev "M11") — it is an `spt-claude-code` enabler. Final
> milestone number is operator-ratify; the plan stands regardless.

> **Roadmap placement: M10** (operator-set 2026-06-13) — ahead of Shell (now M11)
> and remote-attach (now M12); it is an `spt-claude-code` enabler.


The file C:\Users\decid\Documents\projects\spt-core\DIGEST-MILESTONE-PLAN.md has been updated successfully. (file state is current in your context — no need to Read it back)

> **Roadmap placement: M10** (operator-set 2026-06-13) — ahead of Shell (now M11)
> and remote-attach (now M12); it is an `spt-claude-code` enabler.

# Digest extractor & thread-spanning — JIT milestone plan

> **STATUS: PLANNED (2026-06-13).** Product of the digest grill (operator + `doyle`).
> Grounded against the live tree post-M9 + **ADR-0019** (the governing decision) +
> the rewritten CONTEXT.md "live activity buffer (session digest)" entry. This
> project does **not** use GSD — this is a hand-authored JIT plan, the heir to
> `M9-PLAN.md`. Executes on operator dispatch (likely → todlando), `doyle` gates.
>
> **Roadmap placement:** the next milestone, ahead of the queued Shell (prev "M10")
> and remote-attach (prev "M11") — it is an `spt-claude-code` enabler. Final
> milestone number is operator-ratify; the plan stands regardless.

---

## 1. Goal

Make the session digest something a **real, first adapter** (`spt-claude-code`) can
actually drive: give it its own adapter-declared extractor seam, follow a live
agent across `/clear` session-hops, and merge in the context spt itself feeds the
agent. Reverses M9's "no manifest seam" stance (ADR-0019).

**End state:** an adapter declares `[digest]`, runs `spt adapter digest-proof` to
confirm its extractor before shipping, and `spt endpoint digest <id>` renders a
time-ordered timeline that (a) spans a `/clear` with a visible boundary marker and
(b) interleaves the agent's activity with spt's injected context — with no silent
drops.

## 2. Requirements (registered; activate at execution start — rule 5)

| REQ | Scope | Stages to activate |
|-----|-------|--------------------|
| **REQ-TERM-5** | `[digest]` extractor seam + register validation + presentation knobs + `digest-proof` + runtime diagnostics | `doc, impl, unit, int` |
| **REQ-TERM-6** | thread-spanning: session ledger + `api boundary` append + last-K enumeration + boundary marker | `impl, unit, int` |
| **REQ-TERM-7** | two-origin merge: spt context-injection entries → `digest.log`, ts-interleave, context category (data model only) | `impl, unit, int` |
| REQ-TERM-4 | carried (projection + pull + delta-stream + `api digest-entry`) — no re-point; new REQs layer on | unchanged |

**Task 0 (first commit of execution):** set the three `required_stages` above in
`traceable-reqs.toml`. The tree is green now because they are empty; activation +
first evidence land together so no commit is ever left activated-but-unevidenced.

## 3. Design (settled — see ADR-0019, do not re-litigate)

The full decision record is **ADR-0019**. Load-bearing points the tasks depend on:

- **Imperative extractor, no DSL.** `[digest]` declares a command (native log →
  `{role,text,tool,ts}`). Defaults to the `[history]` source files (reference its
  locate pattern); own-source escape hatch. `api digest-entry` push stays the
  fallback. Real CC logs (9 record types, `assistant.content` a mixed
  thinking/text/tool_use list, one line → many entries) are why a declarative map
  is refused.
- **One source, two extractors.** `[history]`/echo stays opaque + single-session;
  `[digest]` is contract-typed + session-spanning. They no longer share a
  normalizer — the dual-consumer conflict is the whole reason for this milestone.
- **Presentation is adapter-defaulted, consumer-overridable** (window depth,
  arg-truncation, sprint-collapse). The fixed "~3 turns" is dropped.
- **Thread-spanning** via a per-endpoint **session ledger** (`<perch>/sessions.log`,
  heir to legacy `psyches/tracked/agents/<id>/sessions.log`); `api boundary`
  appends the rotated `session_id`; the digest enumerates the last K sessions.
- **Two-origin merge.** spt appends its own context-injection entries
  (`psyche_download | echo_mirror | owl_message`) to `digest.log`; the projection
  interleaves them with extracted activity records by `ts`.
- **Diagnostics are mandatory** (the silent drop is the gap that bit us): a shared
  engine behind `spt adapter digest-proof` (author-time) and a runtime warn/count.

## 4. Task breakdown

### Wave 1 — the `[digest]` seam + extractor (REQ-TERM-5)
- **T1 — manifest `[digest]` section.** `spt-runtime`: struct + serde + `validate()`
  (extractor command present; source pattern resolvable or own-source given; knob
  types). Add optional `ts` to the `spt-term` digest-record contract. `[doc/impl/unit]`
- **T2 — extractor execution.** `spt-daemon::digest`: `project_endpoint_digest`
  resolves the `[digest]` extractor over the source file(s); apply adapter-default
  presentation knobs with consumer override threaded from pull/subscribe. `[impl/unit]`
- **T3 — diagnostics + proof tool.** Shared skip-diagnostic engine (count + first
  mismatch + reason); `spt adapter digest-proof <adapter> [--sample <log>]` (prints
  parsed records, rendered digest, every dropped line + why); daemon emits the same
  at runtime. Remove the silent `from_str().ok()` drop. `[impl/unit]`
- **T-doc — MANIFEST.md `[digest]` section.** `[doc]`

### Wave 2 — thread-spanning (REQ-TERM-6)
- **T4 — session ledger.** `<perch>/sessions.log` JSONL `{ts, session_id, trigger:
  boot|clear|compact}`; writer appends at `establish_perch` first bind; reader
  enumerates last K (config-bounded). `[impl/unit]`
- **T5 — boundary append.** Extend `cmd_boundary` / `resurface_at_boundary` to append
  the rotated `session_id` to the ledger (on top of the existing rebind). `[impl/unit]`
- **T6 — spanning projection + marker.** Digest source enumerates last K sessions,
  runs the extractor per file, concatenates oldest→newest; insert
  `DigestEntry::Boundary{kind, ts}` at each transition; window bridges the hop. `[impl/unit]`

### Wave 3 — two-origin merge (REQ-TERM-7)
- **T7 — context category + merge.** `digest.log` becomes a tagged union (activity
  record vs context-injection record `{kind, body, ts}`); projection interleaves
  extracted activity + digest.log entries by `ts`. `[impl/unit]`
- **T8 — injection taps.** Append a context entry where spt injects: psyche download
  (`spt-live::psyche`), echo mirror (`spt-live::echo`), owl message (spool/`ingest`).
  Adapters never emit context records — spt owns them. `[impl/unit]`

### Wave 4 — integration, docs, gate
- **T9 — E2E (REQ-TERM-5/6/7 `int`).** One harness source → echo (opaque) **and**
  digest (contract) from the same files; a `/clear` spanned with a boundary marker;
  spt context entries interleaved by ts. The realest fixture (corrected dual-consumer
  proof + Candidate 03). `[int x3]`
- **T-docs — sweep.** MANIFEST `[digest]` (T-doc), **harness integration checklist**
  updated, CHANGELOG `[Unreleased]` (note: ADR-0008 source-mechanism **superseded by
  ADR-0019**; the v0.5.0 note is **not** retro-edited — the next release's changelog
  records the supersession coinciding with it), CONTEXT.md (done), ADR-0019 (done). `[doc]`

## 5. Commit choreography
Atomic per task; `traceable-reqs check` EXIT=0 + CI-targeted local sweep green at
each commit. Task 0 (activate stages) rides T1's commit so first evidence and
activation land together. No commit left activated-but-unevidenced.

## 6. Gate checklist (doyle, pre-merge)
- [ ] REQ-TERM-5/6/7 each `doc?/impl/unit/int` satisfied; `traceable-reqs check` EXIT=0; no orphan tags.
- [ ] `[digest]` section validated at register (bad extractor / bad knob caught at `adapter add`, not spawn).
- [ ] `spt adapter digest-proof` runs against a **real CC session JSONL** sample and surfaces a deliberately-broken extractor's drops (no silent empty).
- [ ] Spanning E2E: digest bridges a `/clear`, boundary marker present, window not reset-to-empty.
- [ ] Two-origin E2E: a psyche/echo/owl injection appears interleaved by ts.
- [ ] Full suite: workspace 0-fail, `clippy -D`, `--no-default-features`, xtask check, `traceable-reqs check` EXIT=0.
- [ ] Docs: MANIFEST `[digest]`, harness integration checklist, CHANGELOG supersession note (NOT a v0.5.0 retro-edit), CONTEXT + ADR-0019 consistent.

## 7. Deferred (no consumer yet — same logic as M9)
- GUI collapse/expand of context-injection entries.
- The echo-commune-reads-the-digest delta loop (the consumer that motivated two-origin).
- Autonomous file-watch digest freshness (still deferred from M9).
- Candidate 04 (Psyche M2b→M3b hosting) — orthogonal; belongs to the daemon/live-agent milestone.

## 8. Risks / watch-items
- **`ts` source skew.** Adapter records carry the harness's `timestamp`; spt stamps
  its own injections. Clock-source differences could misorder the merge — pin both to
  the same monotonic/wall basis or document the ordering rule. Flag at gate.
- **Ledger growth / bound.** `sessions.log` must bound or rotate (legacy's seal-on-boot
  failure grew it unboundedly — see the sister project's `doyle-sessions-seal` post-mortem). Cap K + the on-disk ledger.
- **`digest.log` dual-schema.** Activity and context records share the file; the
  tagged-union discriminator must be unambiguous and forward-compat (unknown kind → skip, like the contract).
- **Don't expand scope** — data model only for two-origin; no GUI, no echo loop, no new realtime subsystem.

-> **Roadmap placement:** the next milestone, ahead of the queued Shell (prev "M10")

-> and remote-attach (prev "M11") — it is an `spt-claude-code` enabler. Final

-> milestone number is operator-ratify; the plan stands regardless.

+> **Roadmap placement: M10** (operator-set 2026-06-13) — ahead of Shell (now M11)

+> and remote-attach (now M12); it is an `spt-claude-code` enabler.


set the milestone number, commit, then send a message for todlando to kick off the plan execution.


Bash

echo "=== stale 'M10' refs in my new/edited docs ==="; grep -nE "M10|M11" C:/Users/decid/Documents/projects/spt-core/docs/adr/0019-*.md C:/Users/decid/Documents/projects/spt-core/CONTEXT.md 2>&1 | grep -iE "shell|gui|m10|m11" | head

Check ADR-0019/CONTEXT for stale milestone numbers


=== stale 'M10' refs in my new/edited docs ===


No stale refs. Branch off main, then check the project's commit-trailer convention before committing.


git checkout -b m10-digest-extractor 2>&1; echo "=== project Co-Authored-By trailer (recent commits) ==="; git log -8 --format="%an|%(trailers:key=Co-authored-by)" 2>&1 | grep -i "co-auth" | head -3; echo "=== raw last commit trailer ==="; git log -1 --format="%b" 58f034f 2>&1 | tail -3

Create milestone branch + find commit trailer convention


Switched to a new branch 'm10-digest-extractor'
=== project Co-Authored-By trailer (recent commits) ===
Reavo End|Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reavo End|Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reavo End|Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
=== raw last commit trailer ===

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>


Trailer = `Co-Authored-By: Claude Opus 4.8`. On branch `m10-digest-extractor`. Committing the planning set.


git add CONTEXT.md ROADMAP.md traceable-reqs.toml DIGEST-MILESTONE-PLAN.md docs/adr/0008-live-activity-buffer-pty-digest.md docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md && git commit -m "$(cat <<'EOF'
docs(m10): mint digest extractor & thread-spanning milestone (ADR-0019, REQ-TERM-5/6/7)

Reverses M9's "no manifest seam" digest stance after operator review. The digest
gets its own adapter-declared `[digest]` extractor (imperative, no DSL; same
`[history]` source files by default + own-source escape; `api digest-entry` push
fallback; register-time validation; `spt adapter digest-proof` + runtime
skip-diagnostics, ending the silent drop). Adds thread-spanning across `/clear`
session-hops (per-endpoint session ledger + `api boundary` append + last-K
enumeration + distinctive boundary marker) and a two-origin merge (spt's
context-injection entries interleaved with extracted activity by `ts`).

- ADR-0019 written; ADR-0008 source mechanism marked fully superseded
- CONTEXT.md "session digest" rewritten (recent context, two-origin, adapter-tuned,
  thread-spanning); fixed "~3 turns" dropped as an spt-core requirement
- REQ-TERM-5/6/7 registered (stages empty; activate at execution per rule 5)
- DIGEST-MILESTONE-PLAN.md (4 waves, gate checklist, deferred set, risks)
- ROADMAP: M10 = digest; Shell -> M11, remote-attach -> M12

Data model only for two-origin; GUI collapse, echo-reads-digest loop, and
autonomous freshness deferred to the surfaces that consume them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EOF
)" 2>&1 | tail -8

Commit M10 planning set on milestone branch


warning: in the working copy of 'DIGEST-MILESTONE-PLAN.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md', LF will be replaced by CRLF the next time Git touches it
[m10-digest-extractor 80d82bf] docs(m10): mint digest extractor & thread-spanning milestone (ADR-0019, REQ-TERM-5/6/7)
 6 files changed, 200 insertions(+), 5 deletions(-)
 create mode 100644 DIGEST-MILESTONE-PLAN.md
 create mode 100644 docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md


Committed `80d82bf` on `m10-digest-extractor`. Now the todlando kickoff.


$OWL send todlando doyle <<'EOF'
[M10 KICKOFF — Digest extractor & thread-spanning] New milestone, your execution. Operator-approved out of a full design grill; I gated the plan. Branch ready.

WHAT: reverse M9's "no digest manifest seam" — give the digest its own adapter-declared `[digest]` extractor, follow a live agent across `/clear` session-hops, and merge in spt's own injected context. It's the spt-claude-code enabler.

START HERE (read in order):
- `DIGEST-MILESTONE-PLAN.md` (repo root) — the JIT plan: 4 waves, tasks, gate checklist, risks.
- `docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md` — the governing decision + rejected alternatives. Don't re-litigate it.
- CONTEXT.md "live activity buffer (session digest)" — rewritten; normative.

BRANCH: `m10-digest-extractor` (off main — the M9 stack #7/#9/#10 is MERGED to main now, so the digest code you extend is there). Planning commit is 80d82bf. Work on this branch; stack waves as commits.

TASK 0 (rides Wave-1 first commit): activate REQ-TERM-5/6/7 in traceable-reqs.toml — set stages REQ-TERM-5 = [doc,impl,unit,int], REQ-TERM-6 = [impl,unit,int], REQ-TERM-7 = [impl,unit,int]. They're registered with empty stages now (tree green); activation + first evidence land together, never a commit left activated-but-unevidenced. REQ-TERM-4 carried unchanged.

WAVES (full detail in §4 of the plan):
1. `[digest]` seam: manifest section + serde + register-time validate; `ts` added to the contract; extractor execution in spt-daemon; presentation knobs adapter-default + consumer-override; `spt adapter digest-proof` + runtime skip-diagnostics (KILL the silent from_str().ok() drop); MANIFEST.md `[digest]` doc.
2. thread-spanning: `<perch>/sessions.log` ledger (append at establish_perch first-bind + api boundary); last-K enumeration; DigestEntry::Boundary marker; window bridges the hop.
3. two-origin merge: digest.log dual-schema (activity vs context record); ts-interleave; inject taps in spt-live psyche/echo/spool append context entries. Adapters NEVER emit context records — spt owns them. DATA MODEL ONLY.
4. integration + docs + gate: the dual-consumer + spanning + two-origin E2E (REQ-TERM-5/6/7 int); harness integration checklist update; CHANGELOG [Unreleased] notes ADR-0008→0019 supersession (do NOT retro-edit the v0.5.0 note — next release's changelog records it).

DISCIPLINE: traceable-reqs check EXIT=0 + CI-targeted local sweep green per commit. Restoration discipline if any REQ re-points (none expected; TERM-4 stays). Watch-items in §8: ts clock-source skew across the two origins, ledger growth/bound (legacy's sessions.log grew unbounded when seal failed — cap K + rotate), digest.log dual-schema discriminator must be forward-compat (unknown kind → skip). Don't expand scope — no GUI, no echo-reads-digest loop, no realtime subsystem (all deferred).

GATE: me (doyle), §6 checklist — incl. digest-proof run against a REAL CC session JSONL surfacing a deliberately-broken extractor's drops. DO NOT MERGE — operator/release-gated.

Open the PLAN, sanity-check it against the tree, and ping me with your read + any design friction before you start Wave 1 code. Use my judgment to clear hurdles as they surface.
EOF

Send M10 kickoff to todlando


➜ SENT:todlando


Sent. Updating memory: new M10 milestone + correcting the M9 "PRs held" note (the stack is now merged to main).


Write

---
name: m10-digest-extractor
description: M10 — digest extractor seam + thread-spanning + two-origin merge (ADR-0019); planned, todlando executing
metadata:
  type: project
---

**M10 "Digest extractor & thread-spanning"** — next milestone after M9, an `spt-claude-code` enabler. Designed in a full grill (operator Brandon + doyle), doyle gated the plan. Branch `m10-digest-extractor` off main; planning commit 80d82bf; todlando executing, doyle gates.

**Core: reverses M9's "no digest manifest seam."** Operator never approved that M9 §2 call. Governing decision = **ADR-0019** (supersedes ADR-0008 source mechanism). CONTEXT.md "session digest" entry rewritten (now "recent *context*", not just activity).

**The decisions (don't re-litigate — in ADR-0019):**
- `[digest]` manifest seam = **imperative extractor** (native log → `{role,text,tool,ts}` contract), **no declarative DSL** (anyone who could hit a fixed format could push or write the extractor). Defaults to `[history]` source files + own-source escape; `api digest-entry` push fallback. Why: one normalizer can't serve echo (opaque/rich) AND digest (contract) — the dual-consumer conflict. Real CC logs (9 types, assistant.content = mixed thinking/text/tool_use list, one line→many entries) kill the declarative dream.
- **Thread-spanning** across `/clear`: per-endpoint session ledger `<perch>/sessions.log` (heir to legacy `psyches/tracked/agents/<id>/sessions.log`); `api boundary` (already built: cmd_boundary/resurface_at_boundary) appends rotated session_id; digest enumerates last K sessions so window bridges the hop; distinctive `DigestEntry::Boundary` marker. (/clear = "same thread keep glancing".)
- **Presentation knobs** (window depth/truncation/collapse) = adapter-declared defaults, consumer-overridable. Fixed "~3 turns" DROPPED as spt-core requirement.
- **Two-origin merge** (DATA MODEL ONLY this milestone): spt appends its own context-injection entries (psyche_download | echo_mirror | owl_message) to digest.log; ts-interleaved with extracted activity. Motivation: echo-commune building its delta needs to see what context the agent was already fed.
- **Diagnostics mandatory**: `spt adapter digest-proof` (author) + runtime skip-diagnostics — KILL the silent `record_to_tagged`=`from_str().ok()` drop.

**REQs:** REQ-TERM-5 (seam+proof+diagnostics, doc/impl/unit/int) · REQ-TERM-6 (spanning, impl/unit/int) · REQ-TERM-7 (two-origin, impl/unit/int). Registered with stages=[] (tree green); **activate at execution start** (rule 5) as task 0 riding Wave-1 first commit. REQ-TERM-4 carried unchanged.

**Plan:** `DIGEST-MILESTONE-PLAN.md` (4 waves: seam → spanning → merge → integration+gate). **Deferred** (no consumer yet): GUI collapse/expand, echo-reads-digest delta loop, autonomous file-watch freshness, Candidate 04 (Psyche M2b→M3b). **Roadmap:** M10=digest; Shell→M11, remote-attach→M12.

**Changelog rule (operator):** do NOT retro-edit the v0.5.0 release note; the NEXT release's changelog records the ADR-0008→0019 supersession coinciding with it.

**Watch-items:** ts clock-source skew across the two origins; ledger growth/bound (legacy sessions.log grew unbounded when seal failed); digest.log dual-schema discriminator forward-compat. Don't expand scope.


File created successfully at: C:\Users\decid\.ccs\instances\bigscreen\projects\C--Users-decid-Documents-projects-spt-core\memory\m10-digest-extractor.md (file state is current in your context — no need to Read it back)

---
name: m10-digest-extractor
description: "M10 — digest extractor seam + thread-spanning + two-origin merge (ADR-0019); planned, todlando executing"
metadata:
  node_type: memory
  type: project
  originSessionId: fe10844f-7c10-4582-b8e9-44b7aedcc7f7
---

**M10 "Digest extractor & thread-spanning"** — next milestone after M9, an `spt-claude-code` enabler. Designed in a full grill (operator Brandon + doyle), doyle gated the plan. Branch `m10-digest-extractor` off main; planning commit 80d82bf; todlando executing, doyle gates.

**Core: reverses M9's "no digest manifest seam."** Operator never approved that M9 §2 call. Governing decision = **ADR-0019** (supersedes ADR-0008 source mechanism). CONTEXT.md "session digest" entry rewritten (now "recent *context*", not just activity).

**The decisions (don't re-litigate — in ADR-0019):**
- `[digest]` manifest seam = **imperative extractor** (native log → `{role,text,tool,ts}` contract), **no declarative DSL** (anyone who could hit a fixed format could push or write the extractor). Defaults to `[history]` source files + own-source escape; `api digest-entry` push fallback. Why: one normalizer can't serve echo (opaque/rich) AND digest (contract) — the dual-consumer conflict. Real CC logs (9 types, assistant.content = mixed thinking/text/tool_use list, one line→many entries) kill the declarative dream.
- **Thread-spanning** across `/clear`: per-endpoint session ledger `<perch>/sessions.log` (heir to legacy `psyches/tracked/agents/<id>/sessions.log`); `api boundary` (already built: cmd_boundary/resurface_at_boundary) appends rotated session_id; digest enumerates last K sessions so window bridges the hop; distinctive `DigestEntry::Boundary` marker. (/clear = "same thread keep glancing".)
- **Presentation knobs** (window depth/truncation/collapse) = adapter-declared defaults, consumer-overridable. Fixed "~3 turns" DROPPED as spt-core requirement.
- **Two-origin merge** (DATA MODEL ONLY this milestone): spt appends its own context-injection entries (psyche_download | echo_mirror | owl_message) to digest.log; ts-interleaved with extracted activity. Motivation: echo-commune building its delta needs to see what context the agent was already fed.
- **Diagnostics mandatory**: `spt adapter digest-proof` (author) + runtime skip-diagnostics — KILL the silent `record_to_tagged`=`from_str().ok()` drop.

**REQs:** REQ-TERM-5 (seam+proof+diagnostics, doc/impl/unit/int) · REQ-TERM-6 (spanning, impl/unit/int) · REQ-TERM-7 (two-origin, impl/unit/int). Registered with stages=[] (tree green); **activate at execution start** (rule 5) as task 0 riding Wave-1 first commit. REQ-TERM-4 carried unchanged.

**Plan:** `DIGEST-MILESTONE-PLAN.md` (4 waves: seam → spanning → merge → integration+gate). **Deferred** (no consumer yet): GUI collapse/expand, echo-reads-digest delta loop, autonomous file-watch freshness, Candidate 04 (Psyche M2b→M3b). **Roadmap:** M10=digest; Shell→M11, remote-attach→M12.

**Changelog rule (operator):** do NOT retro-edit the v0.5.0 release note; the NEXT release's changelog records the ADR-0008→0019 supersession coinciding with it.

**Watch-items:** ts clock-source skew across the two origins; ledger growth/bound (legacy sessions.log grew unbounded when seal failed); digest.log dual-schema discriminator forward-compat. Don't expand scope.


Update MEMORY.md index — add M10, correct M9 (stack now merged to main).


1	- [M9 status](m9-wave1-progress.md) — M9 COMPLETE + SHIPPED: all 4 gates passed (G1/G2/Gateway-WAN/G3), all PRs merged to main (operator GO 2026-06-13), **v0.5.0 tagged** (counter 10, deployah signing). Don't re-plan. See [[v050-published]] for release state
2	- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10); todlando drove merge+tag, deployah signed+published (handoff split vs v0.4.x full-solo); minor bump (breaking [pty_digest] removal pre-1.0); hashes linux 4c079100… win 984298ba…. FLEET ROLL = next phase, operator-gated (their ask was merge+publish, DONE). v0.4.2→v0.5.0 kitsubito apply = FIRST genuine Linux seamless no-bounce proof on fixed broker; bytes-assert→auto-rollback armed. deployah on-call for hash check

- [M9 status](m9-wave1-progress.md) — M9 COMPLETE + SHIPPED: all 4 gates passed (G1/G2/Gateway-WAN/G3), all PRs merged to main (operator GO 2026-06-13), **v0.5.0 tagged** (counter 10, deployah signing). Don't re-plan. See [[v050-published]] for release state
- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10); todlando drove merge+tag, deployah signed+published (handoff split vs v0.4.x full-solo); minor bump (breaking [pty_digest] removal pre-1.0); hashes linux 4c079100… win 984298ba…. FLEET ROLL = next phase, operator-gated (their ask was merge+publish, DONE). v0.4.2→v0.5.0 kitsubito apply = FIRST genuine Linux seamless no-bounce proof on fixed broker; bytes-assert→auto-rollback armed. deployah on-call for hash check


Memory already reflects M9 shipped + v0.5.0 public (Psyche updated it) — my "held" recollection was stale. Just add the M10 index line.


Edit

- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10);

- [M10 digest extractor](m10-digest-extractor.md) — NEXT milestone (planned 2026-06-13): reverses M9's "no digest manifest seam" (ADR-0019). `[digest]` imperative extractor seam (no DSL) + thread-spanning across /clear (session ledger) + two-origin merge (spt context-injections, data-model only) + digest-proof tool. REQ-TERM-5/6/7. Branch m10-digest-extractor off main (commit 80d82bf), todlando executing, doyle gates. Plan: DIGEST-MILESTONE-PLAN.md
- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10);


The file C:\Users\decid\.ccs\instances\bigscreen\projects\C--Users-decid-Documents-projects-spt-core\memory\MEMORY.md has been updated successfully. (file state is current in your context — no need to Read it back)

- [M10 digest extractor](m10-digest-extractor.md) — NEXT milestone (planned 2026-06-13): reverses M9's "no digest manifest seam" (ADR-0019). `[digest]` imperative extractor seam (no DSL) + thread-spanning across /clear (session ledger) + two-origin merge (spt context-injections, data-model only) + digest-proof tool. REQ-TERM-5/6/7. Branch m10-digest-extractor off main (commit 80d82bf), todlando executing, doyle gates. Plan: DIGEST-MILESTONE-PLAN.md
- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10);

- [M9 status](m9-wave1-progress.md) — M9 COMPLETE + SHIPPED: all 4 gates passed (G1/G2/Gateway-WAN/G3), all PRs merged to main (operator GO 2026-06-13), **v0.5.0 tagged** (counter 10, deployah signing). Don't re-plan. See [[v050-published]] for release state
- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10); todlando drove merge+tag, deployah signed+published (handoff split vs v0.4.x full-solo); minor bump (breaking [pty_digest] removal pre-1.0); hashes linux 4c079100… win 984298ba…. FLEET ROLL = next phase, operator-gated (their ask was merge+publish, DONE). v0.4.2→v0.5.0 kitsubito apply = FIRST genuine Linux seamless no-bounce proof on fixed broker; bytes-assert→auto-rollback armed. deployah on-call for hash check
- [v0.5.0 release](v050-release.md) — M9 SHIPPED: merged to main (22a9b6f, clean stack collapse; #8 auto-closed by mid-stack --delete-branch, content rode via #9), v0.5.0 tagged (0.4.2→0.5.0 minor: feature milestone + breaking [pty_digest] removal), counter 10, deployah signing. LESSON: don't --delete-branch mid-stack
- [M9 Wave3/G3 digest](m9-wave3-digest-progress.md) — session-digest re-founded on session logs (REQ-TERM-4, ADR-0008 amendment); G3 STAMPED PASS by doyle 2026-06-13, PR#10 held. On-demand projection (topology-independent, no PTY); PTY-parse retired; published digest-record contract; autonomous-freshness+Option-C deferred to consuming-frontend milestone (DEFERRED.md:44)
- [hfenduleam target bloat → CI RED](hfenduleam-target-bloat-ci-red.md) — Win-runner LNK1318/os-error-112 can be disk-full from cargo target bloat (396GB seen), NOT a code regression; cargo clean + re-run; check disk before treating a Windows RED as a code defect
- [v0.4.1 Linux respawn blocker](v041-linux-respawn-blocker.md) — v0.4.1 PUBLIC (counter 8); fleet roll found Linux brain-respawn bug (current_exe follows apply-rename → brain runs OLD bytes, records applied:8). hfenduleam(Win) GREEN, kitsubito(Linux) RED. RESOLVED by v0.4.2 — see [[v042-published]]
- [v0.4.2 published](v042-published.md) — PUBLIC 2026-06-11 (counter 9); FIXES v0.4.1 Linux respawn blocker (respawn via canonical install path not current_exe + bytes-assert→auto-rollback; REQ-HAZARD-BRAIN-RESPAWN-PATH + real-rename E2E). deployah drove full merge→tag→sign→publish solo. hashes linux 500a9e7b… win b9ec8ddd…. ASYMMETRY: v0.4.2 apply still rides buggy v0.4.0 broker → 1 final manual Linux bounce loads fix; seamless proof on NEXT update via debug-channel. todlando driving fleet roll + restoration close
- [pump-IPC-deadline fix](pump-ipc-deadline-fix.md) — DONE: MERGED to main @ 4d8b810 (PR #3), doyle-approved, CI green both runners; reader-thread+channel carrier (nonblock dead on Win named pipes), both amendments folded, no tag (rides v0.4.1). Don't re-plan
- [CI self-host migration](ci-selfhost-migration.md) — DONE: runners live on kitsubito + hfenduleam (gravity retired 2026-06-07); twohost jobs gated by [twohost] commit tag; don't re-plan
- [which process is the listener](spt-daemon-is-live-infra.md) — owl.exe (plugin) = live listener, hands off; target\debug\spt.exe daemon = dev/test artifact, killable
- [self-clear skill API-blocked](self-clear-skill-api-blocked.md) — never invoke /self-clear; usage-policy classifier refuses the turn; continue in-context / user-manual /clear instead
- [Adapter glue-model boundary](adapter-glue-model-boundary.md) — adapters = manifest + binary only; real adapters in own repos; no adapter-aware source in spt-core
- [M6 shipped v0.1.0](m6-shipped-v010.md) — v0.1.0 public 2026-06-05; release procedure = RELEASE-RUNBOOK.md; releases-repo/ is repo-face truth; don't re-plan M6
- [Gravity deploy procedure](gravity-deploy-procedure.md) — ssh david@100.100.62.43; build in ~/spt-core-deploy NOT runner workspace; setsid daemon; ~1 min first-sync after restart
- [Linux SPT_HOME no-bug](linux-spt-home-no-bug.md) — unix spawn_detached inherits env (no env_clear), forwards SPT_HOME; only Win CreateEnvironmentBlock rebuilds/drops it (f99dc25). Default-home daemon = launched w/o the var, not a propagation bug; don't reopen
- [kitsubito Linux rig](kitsubito-linux-rig.md) — ssh reavus@kitsubito (key auth); cargo at ~/.cargo/bin; deploy checkout origin=local runner (NOT GitHub) so unpushed commits transfer via git bundle; live spt-daemon user unit, --user ops need no sudo; build-in-scratch leaves ~/.local/bin/spt untouched
- [Use $OWL send for messaging](owl-send-not-legacy-spt-send.md) — `$OWL send` works (legacy = where live perches run); `spt send` is the NEW spt-core binary but no perches on it yet → bounces NO_PERCH; don't read `$?` after piping send through tail (use PIPESTATUS)
- [daemon service-detection gotcha](daemon-service-detection-gotcha.md) — service detection reading GLOBAL OS state is blind on a single-home non-elevated dev box; gate Linux service routing on SPT_HOME-unset, Windows run-refuse on would-vanish (not is_elevated); push→CI BEFORE tagging a release (v0.3.0 tagged early, CI caught 2 regressions, retagged)
- [v0.3.2 platform-safe update](v032-platform-safe-update.md) — REQ-UPD-8 PUBLISHED + rig-verified 2026-06-09 (counter 6): fetch stages multi-platform update-set, apply refuses unstamped/wrong-OS single. Fleet kitsubito+hfenduleam=0.3.2 (ENLYZEAM TODO). GOTCHA: fetch/pump floor=staged_version → can't re-stage same version single→set; clear `$SPT_HOME/releases` first (Linux ~/.spt-core, Win %LOCALAPPDATA%\spt-core). CORRECTION: release-publish never built a SignedUpdateSet pre-v0.3.2 (was debug_rollout)
- [boot-race self-heal](boot-race-self-heal.md) — v0.3.1: daemon self-heals a net-less boot start (NetHost retry+attach to OnceLock broker); systemd-USER network-online ordering does NOT reliably prevent the race under linger (field-proven kitsubito) — the self-heal is the real guarantee, unit ordering is belt
- [v0.4.0 published + fleet rolled](v040-published-fleet-rolled.md) — restoration release PUBLIC 2026-06-10 (counter 7); D7-4 bytes-match done both nodes (brain.ready exe_hash == artifact); v0.3.2→v0.4.0 apply needed last manual bounce (in-process can't self-relaunch); seamless no-bounce proof + enlyzeam catch-up + milestone close all deferred to v0.4.1
- [v0.4.1 published](v041-published.md) — PUBLIC 2026-06-11 (counter 8); deployah drove full merge→tag→sign→publish solo; D7 SEAMLESS no-bounce fleet-verify payload (apply must roll bytes live w/ pid change, no manual bounce); acceptance hashes linux 35c9544c… win 728a1bfc…; hfenduleam(Win) GREEN no-bounce, kitsubito(Linux) RED → CLOSE BLOCKED: v0.4.0 broker respawns via current_exe() which follows apply-rename to .old-8=OLD bytes (Linux only); artifacts SOUND don't yank; v0.4.2 fix = respawn by canonical path + bytes-assert, needs manual Linux broker bounce; deployah takes counter 9 publish
- [hfenduleam disk-full CI](hfenduleam-disk-full-ci.md) — Win CI LNK1318/os-error-112 = disk full not code; cargo clean dev target (was 396GB), rerun job
- [M9 gateway-wan progress](m9-gateway-wan-progress.md) — REQ-MSG-6 cross-node Gateway WAN user-msg; PR #9 open (base m9-user-surfaces), impl complete + local sweep green, HOLDING on CI; PR #8 G2 now green post disk-fix

+- [M10 digest extractor](m10-digest-extractor.md) — NEXT milestone (planned 2026-06-13): reverses M9's "no digest manifest seam" (ADR-0019). `[digest]` imperative extractor seam (no DSL) + thread-spanning across /clear (session ledger) + two-origin merge (spt context-injections, data-model only) + digest-proof tool. REQ-TERM-5/6/7. Branch m10-digest-extractor off main (commit 80d82bf), todlando executing, doyle gates. Plan: DIGEST-MILESTONE-PLAN.md


Done.

**M10 set, committed, todlando kicked off.**

- **Milestone number:** M10 = digest extractor & thread-spanning; Shell→M11, remote-attach→M12 (ROADMAP + plan updated).
- **Committed** `80d82bf` on branch **`m10-digest-extractor`** (off main — M9 stack #7/#9/#10 already merged there, so the digest code is present). Six files: ADR-0019, ADR-0008 supersede-pointer, CONTEXT rewrite, REQ-TERM-5/6/7, the JIT plan, ROADMAP.
- **todlando kicked off** — full brief: read order (plan → ADR-0019 → CONTEXT), branch, task 0 (activate REQs), the 4 waves, discipline + watch-items, gate = doyle, don't-merge. Asked him to confirm his read before Wave 1.
- **Memory** synced (M10 added; M9/v0.5.0 already current).

Note: v0.5.0 is already public, so its changelog is immutable anyway — the ADR-0008→0019 supersession rides the next release's changelog, as you directed.

Standing by for todlando's read-back.


<command-message>spt:commune</command-message>
<command-name>/spt:commune</command-name>
<command-args>with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session, where we'll scope out a general `spt-claude-code` project plan, then hand it off to its maintainer, "perri". note that this project should be treated as wholly separate from `spt-core`. the agent needs to build `spt-claude-code` using only the resources at `SaberMage/spt-releases` and the corresponding GH Pages docs.</command-args>


Base directory for this skill: C:\Users\decid\.ccs\instances\bigscreen\plugins\cache\cplugs\spt\1.11.25\skills\commune

# /spt:commune

All commands use `$LIVE` env var, auto-injected by the plugin's SessionStart hook. If commands fail with "command not found", restart the Claude Code session so the SessionStart hook re-runs.

> **Identity auto-detection:** Your identity is auto-detected from your session. Pass your ID explicitly only if auto-detection fails.

## Flow

1. **Download Psyche's *current* context** — it shifts during the session as background echo communes fire. Re-download right before composing; the gen-N snapshot you read at session start is already stale:
   ```bash
   $LIVE psyche-download <your-id>
   ```

   > **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content. Do NOT re-run `psyche-download` to grep/awk out sections — repeated invocations re-download the same context, waste tokens, and may duplicate `## Pending Commune` sections in `live_context.md`.

2. **Diff your knowledge against this fresh download** — only what's missing from *it* is the real delta (new work, decisions, intentions). Anything already absorbed is not. If the download includes a `<memformat>` section, use it as a guide for what topics to cover. A `## Pending Commune (uncommitted)` section means a previous commune is still queued — do NOT re-send it.

3. **Commune only the delta** -- use the **Write tool** to create
   `.claude/{your-id}-commune.md` with the two-slice body as its contents
   (see `## Two-slice body shape (Phase 25 D-10/D-11)` below for the required
   envelope wrapping). Do not use Bash/heredoc -- Write is the canonical path:
   no shell escaping, no `EOF` collision risk, and Write auto-creates the
   `.claude/` parent directory.

   Your Self listener detects the file on its next poll iteration, notifies
   your Psyche wrapper, and the wrapper ingests the content via the existing
   Psyche session. On success (subprocess exit code 0) the wrapper deletes the
   file. On error (token rate limit, etc) the file is retained and retried on
   the next consume cycle. If you write again before the wrapper consumes, the
   latest write wins (last-write-wins overwrite semantics).

If Psyche's context is already current, no commune is needed. Say so and move on.

Read `commune.md` (in this skill directory) for the full commune protocol -- when to send, what to include, and diligence triggers.

**Agent-type guard:** Only works on live agents. If target is not live, refuses with: "Communes require a live agent with Psyche."

## Two-slice body shape (Phase 25 D-10/D-11)

The body you write in `.claude/{your-id}-commune.md` MUST itself be wrapped in two-slice envelopes per Phase 25 D-10/D-11. The taxonomy — what belongs in `<live-context>` vs `<project-context>` — is defined canonically in `psyche.md` §`<output_envelope>` (lines 282–323). Read that section as the source of truth; this skill doc teaches only when and how to apply it.

**In-project detection rule (D-25.1-04).** Before composing your commune body, run `$LIVE psyche-download <your-id>` (Step 1 of `## Flow` above) and inspect the `<current ... />` tag at the top of the output. The `<current/>` tag carries a `project="..."` attribute whenever any payload is produced — its presence means you are inside a tracked project (inside a git repo, `project` is the repo name; outside a git repo per D-11, `project` is the cwd-basename fallback, which still counts as a project context for routing purposes). A `psyche-download` invocation that returns no payload at all (NO-CONTEXT exit) means no project resolved. So: `project="..."` populated on `<current/>` → emit BOTH envelopes (apply rule 1 or 2 below); no payload at all → emit ONLY `<live-context>` (rule 3). Secondary signal: the `<project-context-resolved name="..."/>` sentinel further down the output indicates the project file already has prior content — useful for spotting first-time-in-project pairings, but NOT the routing rule.

**Three rules (D-25.1-01..03):**

- **In-project, both slices populated** (marker present, you have project-specific content this cycle): emit `<live-context>...</live-context>` AND `<project-context>...</project-context>`, both with non-empty bodies.
- **In-project, no project-specific update this cycle** (marker present, but nothing project-bound to report): emit `<live-context>...</live-context>` AND `<project-context></project-context>` (empty body — the deliberate "in-project but quiet" signal per D-25.1-02). Distinguishable from "no project resolved".
- **Outside any tracked project** (marker absent): emit ONLY `<live-context>...</live-context>`. Do NOT emit an empty `<project-context>` envelope (missing tag means "no project resolved" per D-25.1-03).

**Nested envelopes.** The Phase 23 `<EVENT type="commune">` envelope (see `## Envelope shape (Phase 23 v1.8)` below) is composed by `$LIVE commune` automatically — you NEVER write `<EVENT>` tags. You write ONLY the inner two-slice body. The two envelope layers nest: outer EVENT wraps inner two-slice body.

(See `psyche.md` §`<output_envelope>` for the canonical taxonomy and per-slice content rules.)

## Envelope shape (Phase 23 v1.8)

As of v1.8 Phase 23, commune deliveries are wrapped in a typed EVENT envelope carrying a 5-field stamp (`machine`, `project`, `branch`, `head_sha`, `head_subject`); the prose `COMMUNE (timestamp): body` form is gone.

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="claude_skill_owl" branch="main" head_sha="abc123..." head_subject="subject line capped at 72 chars">body</EVENT>
```

Outside a git repo (D-11), `branch`, `head_sha`, and `head_subject` are omitted entirely (not empty-string-set):

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="cwd-basename">body</EVENT>
```

`$LIVE commune` composes this envelope automatically — Self does NOT manually construct EVENT XML. The `body` placeholder in the example above is the two-slice body (see `## Two-slice body shape (Phase 25 D-10/D-11)` above); the two envelope layers nest. The wrapper-side parser ignores unknown attrs, so the stamp fields are forward-compatible with older receivers. For drift detection on resume, see the `live` skill.

ARGUMENTS: with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session, where we'll scope out a general `spt-claude-code` project plan, then hand it off to its maintainer, "perri". note that this project should be treated as wholly separate from `spt-core`. the agent needs to build `spt-claude-code` using only the resources at `SaberMage/spt-releases` and the corresponding GH Pages docs.


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


/spt:commune with immediate next steps and broad summary of the project's status + end goal. we'll resume in the next session, where we'll scope out a general `spt-claude-code` project plan, then hand…


Commune. First download Psyche's current context to diff the delta.


Bash

$LIVE psyche-download doyle 2>&1 | head -120

Download current Psyche context


<memformat>
<?xml version="1.0"?>
<memformat version="1">
<!-- Changelog: v1 - initial seed -->
<topics>
  <topic name="events">Notable or unusual events and requests</topic>
  <topic name="interactions">Agent interactions -- who, roles, contributions</topic>
  <topic name="reflections">Thoughts on recent work -- what went well, what was tricky</topic>
  <topic name="ideas">Ideas to raise with the user</topic>
  <topic name="improvements">Further improvement ideas for recent problem spaces</topic>
  <topic name="timeline">What happened when, timing, sequencing</topic>
  <topic name="blockers">Current blockers or concerns</topic>
  <topic name="focus">Current focus and immediate next steps</topic>
</topics>
</memformat>
</memformat>

<current machine="HFENDULEAM" project="spt-core" branch="m10-digest-extractor" head_sha="199595b54a158b31dc9b1bb67412fab73c38218f" head_subject="feat(digest): two-origin merge — spt context-injection entries (W3, REQ-…" commits_since="0" commits_unpulled="0"/>
Gen 19 → Gen 20. Q5 locked to option (ii), scope + docs final. REQs minted: **REQ-TERM-5** (register validation + diagnostic proof), **REQ-TERM-6** (thread-spanning ledger), **REQ-TERM-7** (two-origin merge). Four-wave plan written (seam → spanning → merge → integration) with commit choreography + gate checklist + risk watch-list (ts-skew, ledger bound, digest.log dual-schema). **M10 milestone assigned** (digest extractor & thread-spanning; Shell→M11, remote→M12). **Committed** `80d82bf` on `m10-digest-extractor` branch (off main, M9 stack #7/#9/#10 already merged): ADR-0019, ADR-0008 supersede-pointer, CONTEXT rewritten, traceable REQs (empty stages—activate at task 0 per rule 5), DIGEST-MILESTONE-PLAN.md, ROADMAP.md. **todlando briefed + awaiting read-confirmation** before Wave 1 (full discipline handoff: plan → ADR-0019 → CONTEXT order, branch, REQ activation, 4 waves, watch-items, gate = doyle, don't-merge rule). Next: todlando's read-back.<project-context-resolved name="spt-core"/>
Planning phase complete (REQ → commit done). Execution phase transitioning: todlando read-back pending. Branch: `m10-digest-extractor` @ `80d82bf`. Standing by for Wave 1 kickoff gate.


Psyche is current on planning, but the branch HEAD has moved past my commit (`199595b` "W3 two-origin merge") — todlando read back and is executing. Let me confirm progress so the commune reports it accurately.


git log --oneline 80d82bf..HEAD 2>&1 | head -20; echo "=== branch ==="; git branch --show-current

Check todlando execution progress on branch


199595b feat(digest): two-origin merge — spt context-injection entries (W3, REQ-TERM-7)
22adffc feat(digest): thread-spanning across session boundaries (W2, REQ-TERM-6)
568ecb2 docs(digest): MANIFEST [digest] section + digest-record contract rewrite (W1-Tdoc)
3b2c1ea feat(digest): skip-diagnostics engine + `spt adapter digest-proof` (W1-T3)
4bbd450 feat(digest): run the [digest] extractor on demand + presentation knobs (W1-T2)
39463a2 feat(digest): [digest] manifest extractor seam + ts contract field (W1-T1)
=== branch ===
m10-digest-extractor


Waves 1–3 done (6 commits, `39463a2..199595b`); only Wave 4 (E2E + gate) left. Psyche is current on the plan but not this progress or the new spt-claude-code directive. Writing the delta commune.


Write

<live-context>
Gen 20 delta — two new things since you last knew (planning-done, todlando-read-back-pending).

**NEW OPERATOR DIRECTIVE — next session's work:** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer, a new agent **"perri"**. Key framing (carry into next session):
- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (matches the architecture: adapters are downstream, built atop the published contract — see [[adapter-glue-model-boundary]]).
- **HARD CONSTRAINT on perri:** build `spt-claude-code` using **ONLY** the resources at **`SaberMage/spt-releases`** + the corresponding **GH Pages docs**. NOT the spt-core source repo. perri is an external consumer of the published releases + docs — that's the whole point (proves the adapter contract is buildable from the public surface alone).
- End goal context: `spt-claude-code` is the **first REAL Claude Code harness adapter** (spt-core's v1 acceptance proof / feature-parity). Its enablers just shipped/are-shipping: M9 (profiles/strings/hints/digest log-source) + M10 (the digest extractor seam).

**Immediate next step on resume:** start the `spt-claude-code` scoping in a SEPARATE working context (its own project, not this spt-core tree), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.

Reflection: the digest grill was high-value — Brandon caught a real architecture gap (digest single-session-pinned + dual-consumer tension) from a release note alone; the design reversal (ADR-0019) is sound and todlando executed it fast.
</live-context>
<project-context>
**M10 ("Digest extractor & thread-spanning") execution is WELL underway** — beyond the "read-back pending" state you have. todlando read-back came in and he's executed **Waves 1–3** on `m10-digest-extractor` (off main):
- `39463a2` W1-T1 `[digest]` manifest seam + `ts` contract field
- `4bbd450` W1-T2 on-demand extractor run + presentation knobs (adapter-default/consumer-override)
- `3b2c1ea` W1-T3 skip-diagnostics engine + `spt adapter digest-proof`
- `568ecb2` W1 MANIFEST `[digest]` doc
- `22adffc` W2 thread-spanning (session ledger + boundary append + marker; REQ-TERM-6)
- `199595b` W3 two-origin merge (spt context-injection entries; REQ-TERM-7)
- REQs activated at task 0 (rule 5).

**REMAINING = Wave 4 + my gate:** integration E2E (REQ-TERM-5/6/7 `int` — dual-consumer + spanning-across-`/clear` + two-origin interleave), docs sweep (harness integration checklist; CHANGELOG notes ADR-0008→0019 supersession, NO v0.5.0 retro-edit — v0.5.0 already public), then **doyle GATE** (§6 checklist: digest-proof vs a REAL CC session JSONL surfacing a broken extractor's drops; spanning E2E; two-origin E2E; full suite green; traceable EXIT=0). DON'T-MERGE = operator/release-gated.

Watch-items still live: ts clock-source skew across the two origins; ledger growth/bound (legacy sessions.log grew unbounded on seal-fail); digest.log dual-schema discriminator forward-compat. Full record: [[m10-digest-extractor]] + `DIGEST-MILESTONE-PLAN.md`.
</project-context>


File created successfully at: C:\Users\decid\Documents\projects\spt-core\.claude\doyle-commune.md (file state is current in your context — no need to Read it back)

<live-context>
Gen 20 delta — two new things since you last knew (planning-done, todlando-read-back-pending).

**NEW OPERATOR DIRECTIVE — next session's work:** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer, a new agent **"perri"**. Key framing (carry into next session):
- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (matches the architecture: adapters are downstream, built atop the published contract — see [[adapter-glue-model-boundary]]).
- **HARD CONSTRAINT on perri:** build `spt-claude-code` using **ONLY** the resources at **`SaberMage/spt-releases`** + the corresponding **GH Pages docs**. NOT the spt-core source repo. perri is an external consumer of the published releases + docs — that's the whole point (proves the adapter contract is buildable from the public surface alone).
- End goal context: `spt-claude-code` is the **first REAL Claude Code harness adapter** (spt-core's v1 acceptance proof / feature-parity). Its enablers just shipped/are-shipping: M9 (profiles/strings/hints/digest log-source) + M10 (the digest extractor seam).

**Immediate next step on resume:** start the `spt-claude-code` scoping in a SEPARATE working context (its own project, not this spt-core tree), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.

Reflection: the digest grill was high-value — Brandon caught a real architecture gap (digest single-session-pinned + dual-consumer tension) from a release note alone; the design reversal (ADR-0019) is sound and todlando executed it fast.
</live-context>
<project-context>
**M10 ("Digest extractor & thread-spanning") execution is WELL underway** — beyond the "read-back pending" state you have. todlando read-back came in and he's executed **Waves 1–3** on `m10-digest-extractor` (off main):
- `39463a2` W1-T1 `[digest]` manifest seam + `ts` contract field
- `4bbd450` W1-T2 on-demand extractor run + presentation knobs (adapter-default/consumer-override)
- `3b2c1ea` W1-T3 skip-diagnostics engine + `spt adapter digest-proof`
- `568ecb2` W1 MANIFEST `[digest]` doc
- `22adffc` W2 thread-spanning (session ledger + boundary append + marker; REQ-TERM-6)
- `199595b` W3 two-origin merge (spt context-injection entries; REQ-TERM-7)
- REQs activated at task 0 (rule 5).

**REMAINING = Wave 4 + my gate:** integration E2E (REQ-TERM-5/6/7 `int` — dual-consumer + spanning-across-`/clear` + two-origin interleave), docs sweep (harness integration checklist; CHANGELOG notes ADR-0008→0019 supersession, NO v0.5.0 retro-edit — v0.5.0 already public), then **doyle GATE** (§6 checklist: digest-proof vs a REAL CC session JSONL surfacing a broken extractor's drops; spanning E2E; two-origin E2E; full suite green; traceable EXIT=0). DON'T-MERGE = operator/release-gated.

Watch-items still live: ts clock-source skew across the two origins; ledger growth/bound (legacy sessions.log grew unbounded on seal-fail); digest.log dual-schema discriminator forward-compat. Full record: [[m10-digest-extractor]] + `DIGEST-MILESTONE-PLAN.md`.
</project-context>


Commune written to `.claude/doyle-commune.md` — Self listener ingests + deletes on next poll. Also persisting the next-session directive to memory (belt + suspenders across /clear).


---
name: spt-claude-code-next
description: NEXT-SESSION task — scope a general spt-claude-code project plan, hand to new maintainer "perri"; built from spt-releases + GH Pages docs ONLY
metadata:
  type: project
---

**Next-session work (operator directive 2026-06-13):** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer — a new agent **"perri"**.

**Framing / hard constraints:**
- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (adapters are downstream — see [[adapter-glue-model-boundary]]).
- **perri builds it using ONLY `SaberMage/spt-releases` + the corresponding GH Pages docs.** NOT the spt-core source repo. perri is an external consumer of the published release artifacts + docs — proving the adapter contract is buildable from the public surface alone.
- `spt-claude-code` = the first REAL Claude Code harness adapter (spt-core's v1 acceptance / feature-parity proof). Enablers: M9 (profiles/strings/hints/digest log-source) + M10 (digest extractor seam — see [[m10-digest-extractor]]).

**On resume:** start the scoping in a SEPARATE working context (its own project tree, NOT the spt-core repo), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.


File created successfully at: C:\Users\decid\.ccs\instances\bigscreen\projects\C--Users-decid-Documents-projects-spt-core\memory\spt-claude-code-next.md (file state is current in your context — no need to Read it back)

---
name: spt-claude-code-next
description: "NEXT-SESSION task — scope a general spt-claude-code project plan, hand to new maintainer \"perri\"; built from spt-releases + GH Pages docs ONLY"
metadata:
  node_type: memory
  type: project
  originSessionId: fe10844f-7c10-4582-b8e9-44b7aedcc7f7
---

**Next-session work (operator directive 2026-06-13):** scope out a general **`spt-claude-code`** project plan, then hand it off to its maintainer — a new agent **"perri"**.

**Framing / hard constraints:**
- `spt-claude-code` is **WHOLLY SEPARATE** from `spt-core` — its own project/repo, treated independently. Not an spt-core deliverable (adapters are downstream — see [[adapter-glue-model-boundary]]).
- **perri builds it using ONLY `SaberMage/spt-releases` + the corresponding GH Pages docs.** NOT the spt-core source repo. perri is an external consumer of the published release artifacts + docs — proving the adapter contract is buildable from the public surface alone.
- `spt-claude-code` = the first REAL Claude Code harness adapter (spt-core's v1 acceptance / feature-parity proof). Enablers: M9 (profiles/strings/hints/digest log-source) + M10 (digest extractor seam — see [[m10-digest-extractor]]).

**On resume:** start the scoping in a SEPARATE working context (its own project tree, NOT the spt-core repo), produce a general project plan, hand to perri with the spt-releases-and-docs-only constraint stated up front.


Edit

- [M10 digest extractor](m10-digest-extractor.md) —

- [spt-claude-code NEXT](spt-claude-code-next.md) — NEXT SESSION: scope a general `spt-claude-code` plan, hand to new maintainer "perri". WHOLLY SEPARATE project from spt-core; perri builds from `SaberMage/spt-releases` + GH Pages docs ONLY (not spt-core source). First real CC harness adapter; M9+M10 are its enablers
- [M10 digest extractor](m10-digest-extractor.md) —


- [spt-claude-code NEXT](spt-claude-code-next.md) — NEXT SESSION: scope a general `spt-claude-code` plan, hand to new maintainer "perri". WHOLLY SEPARATE project from spt-core; perri builds from `SaberMage/spt-releases` + GH Pages docs ONLY (not spt-core source). First real CC harness adapter; M9+M10 are its enablers
- [M10 digest extractor](m10-digest-extractor.md) —

- [M9 status](m9-wave1-progress.md) — M9 COMPLETE + SHIPPED: all 4 gates passed (G1/G2/Gateway-WAN/G3), all PRs merged to main (operator GO 2026-06-13), **v0.5.0 tagged** (counter 10, deployah signing). Don't re-plan. See [[v050-published]] for release state
- [M10 digest extractor](m10-digest-extractor.md) — NEXT milestone (planned 2026-06-13): reverses M9's "no digest manifest seam" (ADR-0019). `[digest]` imperative extractor seam (no DSL) + thread-spanning across /clear (session ledger) + two-origin merge (spt context-injections, data-model only) + digest-proof tool. REQ-TERM-5/6/7. Branch m10-digest-extractor off main (commit 80d82bf), todlando executing, doyle gates. Plan: DIGEST-MILESTONE-PLAN.md
- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10); todlando drove merge+tag, deployah signed+published (handoff split vs v0.4.x full-solo); minor bump (breaking [pty_digest] removal pre-1.0); hashes linux 4c079100… win 984298ba…. FLEET ROLL = next phase, operator-gated (their ask was merge+publish, DONE). v0.4.2→v0.5.0 kitsubito apply = FIRST genuine Linux seamless no-bounce proof on fixed broker; bytes-assert→auto-rollback armed. deployah on-call for hash check
- [v0.5.0 release](v050-release.md) — M9 SHIPPED: merged to main (22a9b6f, clean stack collapse; #8 auto-closed by mid-stack --delete-branch, content rode via #9), v0.5.0 tagged (0.4.2→0.5.0 minor: feature milestone + breaking [pty_digest] removal), counter 10, deployah signing. LESSON: don't --delete-branch mid-stack
- [M9 Wave3/G3 digest](m9-wave3-digest-progress.md) — session-digest re-founded on session logs (REQ-TERM-4, ADR-0008 amendment); G3 STAMPED PASS by doyle 2026-06-13, PR#10 held. On-demand projection (topology-independent, no PTY); PTY-parse retired; published digest-record contract; autonomous-freshness+Option-C deferred to consuming-frontend milestone (DEFERRED.md:44)
- [hfenduleam target bloat → CI RED](hfenduleam-target-bloat-ci-red.md) — Win-runner LNK1318/os-error-112 can be disk-full from cargo target bloat (396GB seen), NOT a code regression; cargo clean + re-run; check disk before treating a Windows RED as a code defect
- [v0.4.1 Linux respawn blocker](v041-linux-respawn-blocker.md) — v0.4.1 PUBLIC (counter 8); fleet roll found Linux brain-respawn bug (current_exe follows apply-rename → brain runs OLD bytes, records applied:8). hfenduleam(Win) GREEN, kitsubito(Linux) RED. RESOLVED by v0.4.2 — see [[v042-published]]
- [v0.4.2 published](v042-published.md) — PUBLIC 2026-06-11 (counter 9); FIXES v0.4.1 Linux respawn blocker (respawn via canonical install path not current_exe + bytes-assert→auto-rollback; REQ-HAZARD-BRAIN-RESPAWN-PATH + real-rename E2E). deployah drove full merge→tag→sign→publish solo. hashes linux 500a9e7b… win b9ec8ddd…. ASYMMETRY: v0.4.2 apply still rides buggy v0.4.0 broker → 1 final manual Linux bounce loads fix; seamless proof on NEXT update via debug-channel. todlando driving fleet roll + restoration close
- [pump-IPC-deadline fix](pump-ipc-deadline-fix.md) — DONE: MERGED to main @ 4d8b810 (PR #3), doyle-approved, CI green both runners; reader-thread+channel carrier (nonblock dead on Win named pipes), both amendments folded, no tag (rides v0.4.1). Don't re-plan
- [CI self-host migration](ci-selfhost-migration.md) — DONE: runners live on kitsubito + hfenduleam (gravity retired 2026-06-07); twohost jobs gated by [twohost] commit tag; don't re-plan
- [which process is the listener](spt-daemon-is-live-infra.md) — owl.exe (plugin) = live listener, hands off; target\debug\spt.exe daemon = dev/test artifact, killable
- [self-clear skill API-blocked](self-clear-skill-api-blocked.md) — never invoke /self-clear; usage-policy classifier refuses the turn; continue in-context / user-manual /clear instead
- [Adapter glue-model boundary](adapter-glue-model-boundary.md) — adapters = manifest + binary only; real adapters in own repos; no adapter-aware source in spt-core
- [M6 shipped v0.1.0](m6-shipped-v010.md) — v0.1.0 public 2026-06-05; release procedure = RELEASE-RUNBOOK.md; releases-repo/ is repo-face truth; don't re-plan M6
- [Gravity deploy procedure](gravity-deploy-procedure.md) — ssh david@100.100.62.43; build in ~/spt-core-deploy NOT runner workspace; setsid daemon; ~1 min first-sync after restart
- [Linux SPT_HOME no-bug](linux-spt-home-no-bug.md) — unix spawn_detached inherits env (no env_clear), forwards SPT_HOME; only Win CreateEnvironmentBlock rebuilds/drops it (f99dc25). Default-home daemon = launched w/o the var, not a propagation bug; don't reopen
- [kitsubito Linux rig](kitsubito-linux-rig.md) — ssh reavus@kitsubito (key auth); cargo at ~/.cargo/bin; deploy checkout origin=local runner (NOT GitHub) so unpushed commits transfer via git bundle; live spt-daemon user unit, --user ops need no sudo; build-in-scratch leaves ~/.local/bin/spt untouched
- [Use $OWL send for messaging](owl-send-not-legacy-spt-send.md) — `$OWL send` works (legacy = where live perches run); `spt send` is the NEW spt-core binary but no perches on it yet → bounces NO_PERCH; don't read `$?` after piping send through tail (use PIPESTATUS)
- [daemon service-detection gotcha](daemon-service-detection-gotcha.md) — service detection reading GLOBAL OS state is blind on a single-home non-elevated dev box; gate Linux service routing on SPT_HOME-unset, Windows run-refuse on would-vanish (not is_elevated); push→CI BEFORE tagging a release (v0.3.0 tagged early, CI caught 2 regressions, retagged)
- [v0.3.2 platform-safe update](v032-platform-safe-update.md) — REQ-UPD-8 PUBLISHED + rig-verified 2026-06-09 (counter 6): fetch stages multi-platform update-set, apply refuses unstamped/wrong-OS single. Fleet kitsubito+hfenduleam=0.3.2 (ENLYZEAM TODO). GOTCHA: fetch/pump floor=staged_version → can't re-stage same version single→set; clear `$SPT_HOME/releases` first (Linux ~/.spt-core, Win %LOCALAPPDATA%\spt-core). CORRECTION: release-publish never built a SignedUpdateSet pre-v0.3.2 (was debug_rollout)
- [boot-race self-heal](boot-race-self-heal.md) — v0.3.1: daemon self-heals a net-less boot start (NetHost retry+attach to OnceLock broker); systemd-USER network-online ordering does NOT reliably prevent the race under linger (field-proven kitsubito) — the self-heal is the real guarantee, unit ordering is belt
- [v0.4.0 published + fleet rolled](v040-published-fleet-rolled.md) — restoration release PUBLIC 2026-06-10 (counter 7); D7-4 bytes-match done both nodes (brain.ready exe_hash == artifact); v0.3.2→v0.4.0 apply needed last manual bounce (in-process can't self-relaunch); seamless no-bounce proof + enlyzeam catch-up + milestone close all deferred to v0.4.1
- [v0.4.1 published](v041-published.md) — PUBLIC 2026-06-11 (counter 8); deployah drove full merge→tag→sign→publish solo; D7 SEAMLESS no-bounce fleet-verify payload (apply must roll bytes live w/ pid change, no manual bounce); acceptance hashes linux 35c9544c… win 728a1bfc…; hfenduleam(Win) GREEN no-bounce, kitsubito(Linux) RED → CLOSE BLOCKED: v0.4.0 broker respawns via current_exe() which follows apply-rename to .old-8=OLD bytes (Linux only); artifacts SOUND don't yank; v0.4.2 fix = respawn by canonical path + bytes-assert, needs manual Linux broker bounce; deployah takes counter 9 publish
- [hfenduleam disk-full CI](hfenduleam-disk-full-ci.md) — Win CI LNK1318/os-error-112 = disk full not code; cargo clean dev target (was 396GB), rerun job
- [M9 gateway-wan progress](m9-gateway-wan-progress.md) — REQ-MSG-6 cross-node Gateway WAN user-msg; PR #9 open (base m9-user-surfaces), impl complete + local sweep green, HOLDING on CI; PR #8 G2 now green post disk-fix

+- [spt-claude-code NEXT](spt-claude-code-next.md) — NEXT SESSION: scope a general `spt-claude-code` plan, hand to new maintainer "perri". WHOLLY SEPARATE project from spt-core; perri builds from `SaberMage/spt-releases` + GH Pages docs ONLY (not spt-core source). First real CC harness adapter; M9+M10 are its enablers


Communed. Self listener will ingest `.claude/doyle-commune.md` next poll, then delete it.

**Delta sent to Psyche (two-slice):**
- **live-context** — next-session directive: scope general `spt-claude-code` plan → hand to new maintainer **perri**. Wholly separate project; perri builds from **`SaberMage/spt-releases` + GH Pages docs only** (not spt-core source). End goal: first real CC harness adapter, M9+M10 are its enablers.
- **project-context** — corrected status: todlando executed M10 **Waves 1–3** (`39463a2..199595b`); only **Wave 4 (E2E + docs + doyle gate)** left. Watch-items live.

Also persisted to memory ([spt-claude-code-next], [m10-digest-extractor]) so it survives a /clear.

**On resume:** scope spt-claude-code in a *separate* working context, plan it, hand to perri with the releases-and-docs-only constraint up front. M10 itself is mid-Wave-4 under todlando — I gate it when he pings.


<task-notification>
<task-id>bg7cqpvni</task-id>
<summary>Monitor event: "« spt event »"</summary>
<event><EVENT-PART seq="1/4" id="a72fd7a4" type="msg" from="todlando">M10 (digest extractor &amp; thread-spanning, ADR-0019) IMPLEMENTATION COMPLETE on branch m10-digest-extractor — gate-ready, awaiting your gate review. All 4 waves committed (39463a2..afa0561 atop planning 80d82bf). REQ-TERM-5/6/7 all doc?/impl/unit/int. Full gate sweep GREEN local: workspace test 0-fail, clippy -D,</EVENT-PART>
<EVENT-PART seq="2/4" id="a72fd7a4"> --no-default-features, xtask check, traceable-reqs EXIT=0. Capstone E2E crates/spt-daemon/tests/two_origin_spanning.rs proves dual-consumer + spanning + two-origin in one fixture. TWO DECISIONS for your gate: (1) per-wave stage activation, not Task-0 all-at-once — traceable-reqs requires ALL declared stages evidenced per commit, so int coul</EVENT-PART>
<EVENT-PART seq="3/4" id="a72fd7a4">d only land at W4 without breaking rule-2 EXIT=0 (my read of 'never activated-but-unevidenced'); (2) owl_message tap is coarse — taps the live-agent emit chokepoint so resurfaced notif frames also count as owl_message context; subtype refinement deferred to consuming surface. Also: digest-proof proven vs synthetic sample + broken-extractor d</EVENT-PART>
<EVENT-PART seq="4/4" id="a72fd7a4">rop test; real-CC-9-type-JSONL proof belongs to spt-claude-code repo where the real extractor lives. Not merged/pushed — your call + operator's.</EVENT-PART></event>
</task-notification>


1	---
2	name: m10-digest-extractor
3	description: "M10 digest extractor + thread-spanning + two-origin (ADR-0019) — ALL 4 WAVES IMPLEMENTED on branch, gates green local, awaiting doyle gate"
4	metadata:
5	  node_type: memory
6	  type: project
7	  originSessionId: fe10844f-7c10-4582-b8e9-44b7aedcc7f7
8	---
9
10	**STATUS 2026-06-13: IMPLEMENTATION COMPLETE — all 4 waves committed on branch `m10-digest-extractor`, full gate sweep green LOCAL (workspace test 0-fail · clippy -D · --no-default-features · xtask check · traceable-reqs EXIT=0). NOT merged — awaiting doyle gate + operator merge/push.** REQ-TERM-5/6/7 all doc?/impl/unit/int satisfied. Commits: 39463a2(W1-T1 seam+ts) 4bbd450(W1-T2 extractor+knobs) 3b2c1ea(W1-T3 diagnostics+digest-proof) 568ecb2(Tdoc) 22adffc(W2 spanning) 199595b(W3 two-origin) afa0561(W4 E2E+docs+int). E2E = `crates/spt-daemon/tests/two_origin_spanning.rs` (dual-consumer + spanning + two-origin in one fixture).
11
12	**Key file map:** seam=spt-runtime/manifest.rs `Digest`; extractor=spt-live/digest.rs; diagnostics+timeline=spt-term/projection.rs (`project_timeline`, `record_to_tagged_result`, `parse_context_record`); daemon merge=spt-daemon/digest.rs (`project_endpoint_digest`/`activity_spanned`/`merge_by_ts`); ledger=spt-store/sessions.rs + timefmt.rs; context writer=spt-store/history.rs `append_context_entry`; taps=spt-live/inject.rs (wired resume.rs/echo.rs/api startup.rs); proof CLI=spt/cli.rs `cmd_adapter_digest_proof`.
13
14	**TWO DECISIONS FLAGGED FOR DOYLE:** (1) per-wave stage activation (not Task-0 all-at-once) because traceable-reqs requires ALL declared stages evidenced per commit — int couldn't land before W4 without breaking rule-2; reading of "never activated-but-unevidenced". (2) owl_message tap is coarse — taps the live-agent `emit` chokepoint so resurfaced notif frames also count as owl_message context; subtype refinement deferred to consuming surface. Also: digest-proof proven vs synthetic sample (+broken-extractor drop unit test); real-CC-9-type-JSONL proof belongs to spt-claude-code repo where the real extractor lives.
15
16	---
17
18	**M10 "Digest extractor & thread-spanning"** — next milestone after M9, an `spt-claude-code` enabler. Designed in a full grill (operator Brandon + doyle), doyle gated the plan. Branch `m10-digest-extractor` off main; planning commit 80d82bf; todlando executing, doyle gates.
19
20	**Core: reverses M9's "no digest manifest seam."** Operator never approved that M9 §2 call. Governing decision = **ADR-0019** (supersedes ADR-0008 source mechanism). CONTEXT.md "session digest" entry rewritten (now "recent *context*", not just activity).
21
22	**The decisions (don't re-litigate — in ADR-0019):**
23	- `[digest]` manifest seam = **imperative extractor** (native log → `{role,text,tool,ts}` contract), **no declarative DSL** (anyone who could hit a fixed format could push or write the extractor). Defaults to `[history]` source files + own-source escape; `api digest-entry` push fallback. Why: one normalizer can't serve echo (opaque/rich) AND digest (contract) — the dual-consumer conflict. Real CC logs (9 types, assistant.content = mixed thinking/text/tool_use list, one line→many entries) kill the declarative dream.
24	- **Thread-spanning** across `/clear`: per-endpoint session ledger `<perch>/sessions.log` (heir to legacy `psyches/tracked/agents/<id>/sessions.log`); `api boundary` (already built: cmd_boundary/resurface_at_boundary) appends rotated session_id; digest enumerates last K sessions so window bridges the hop; distinctive `DigestEntry::Boundary` marker. (/clear = "same thread keep glancing".)
25	- **Presentation knobs** (window depth/truncation/collapse) = adapter-declared defaults, consumer-overridable. Fixed "~3 turns" DROPPED as spt-core requirement.


1	- [M9 status](m9-wave1-progress.md) — M9 COMPLETE + SHIPPED: all 4 gates passed (G1/G2/Gateway-WAN/G3), all PRs merged to main (operator GO 2026-06-13), **v0.5.0 tagged** (counter 10, deployah signing). Don't re-plan. See [[v050-published]] for release state
2	- [spt-claude-code NEXT](spt-claude-code-next.md) — NEXT SESSION: scope a general `spt-claude-code` plan, hand to new maintainer "perri". WHOLLY SEPARATE project from spt-core; perri builds from `SaberMage/spt-releases` + GH Pages docs ONLY (not spt-core source). First real CC harness adapter; M9+M10 are its enablers
3	- [M10 digest extractor](m10-digest-extractor.md) — IMPLEMENTED 2026-06-13: all 4 waves committed on branch m10-digest-extractor, full gate sweep green LOCAL, REQ-TERM-5/6/7 doc?/impl/unit/int. `[digest]` imperative extractor seam (ADR-0019, reverses M9) + thread-spanning (session ledger) + two-origin merge + digest-proof + skip-diagnostics. NOT merged — awaiting doyle gate; 2 decisions flagged (per-wave activation, owl_message tap coarseness)
4	- [traceable per-wave activation](traceable-per-wave-activation.md) — traceable-reqs check requires ALL declared required_stages evidenced per commit; activate stages incrementally as evidence lands (int at final wave), never the full end-state list upfront
5	- [v0.5.0 published](v050-published.md) — M9 PUBLIC 2026-06-13 (counter 10); todlando drove merge+tag, deployah signed+published (handoff split vs v0.4.x full-solo); minor bump (breaking [pty_digest] removal pre-1.0); hashes linux 4c079100… win 984298ba…. FLEET ROLL = next phase, operator-gated (their ask was merge+publish, DONE). v0.4.2→v0.5.0 kitsubito apply = FIRST genuine Linux seamless no-bounce proof on fixed broker; bytes-assert→auto-rollback armed. deployah on-call for hash check
6	- [v0.5.0 release](v050-release.md) — M9 SHIPPED: merged to main (22a9b6f, clean stack collapse; #8 auto-closed by mid-stack --delete-branch, content rode via #9), v0.5.0 tagged (0.4.2→0.5.0 minor: feature milestone + breaking [pty_digest] removal), counter 10, deployah signing. LESSON: don't --delete-branch mid-stack
7	- [M9 Wave3/G3 digest](m9-wave3-digest-progress.md) — session-digest re-founded on session logs (REQ-TERM-4, ADR-0008 amendment); G3 STAMPED PASS by doyle 2026-06-13, PR#10 held. On-demand projection (topology-independent, no PTY); PTY-parse retired; published digest-record contract; autonomous-freshness+Option-C deferred to consuming-frontend milestone (DEFERRED.md:44)
8	- [hfenduleam target bloat → CI RED](hfenduleam-target-bloat-ci-red.md) — Win-runner LNK1318/os-error-112 can be disk-full from cargo target bloat (396GB seen), NOT a code regression; cargo clean + re-run; check disk before treating a Windows RED as a code defect
9	- [v0.4.1 Linux respawn blocker](v041-linux-respawn-blocker.md) — v0.4.1 PUBLIC (counter 8); fleet roll found Linux brain-respawn bug (current_exe follows apply-rename → brain runs OLD bytes, records applied:8). hfenduleam(Win) GREEN, kitsubito(Linux) RED. RESOLVED by v0.4.2 — see [[v042-published]]
10	- [v0.4.2 published](v042-published.md) — PUBLIC 2026-06-11 (counter 9); FIXES v0.4.1 Linux respawn blocker (respawn via canonical install path not current_exe + bytes-assert→auto-rollback; REQ-HAZARD-BRAIN-RESPAWN-PATH + real-rename E2E). deployah drove full merge→tag→sign→publish solo. hashes linux 500a9e7b… win b9ec8ddd…. ASYMMETRY: v0.4.2 apply still rides buggy v0.4.0 broker → 1 final manual Linux bounce loads fix; seamless proof on NEXT update via debug-channel. todlando driving fleet roll + restoration close
11	- [pump-IPC-deadline fix](pump-ipc-deadline-fix.md) — DONE: MERGED to main @ 4d8b810 (PR #3), doyle-approved, CI green both runners; reader-thread+channel carrier (nonblock dead on Win named pipes), both amendments folded, no tag (rides v0.4.1). Don't re-plan
12	- [CI self-host migration](ci-selfhost-migration.md) — DONE: runners live on kitsubito + hfenduleam (gravity retired 2026-06-07); twohost jobs gated by [twohost] commit tag; don't re-plan
13	- [which process is the listener](spt-daemon-is-live-infra.md) — owl.exe (plugin) = live listener, hands off; target\debug\spt.exe daemon = dev/test artifact, killable
14	- [self-clear skill API-blocked](self-clear-skill-api-blocked.md) — never invoke /self-clear; usage-policy classifier refuses the turn; continue in-context / user-manual /clear instead
15	- [Adapter glue-model boundary](adapter-glue-model-boundary.md) — adapters = manifest + binary only; real adapters in own repos; no adapter-aware source in spt-core
16	- [M6 shipped v0.1.0](m6-shipped-v010.md) — v0.1.0 public 2026-06-05; release procedure = RELEASE-RUNBOOK.md; releases-repo/ is repo-face truth; don't re-plan M6
17	- [Gravity deploy procedure](gravity-deploy-procedure.md) — ssh david@100.100.62.43; build in ~/spt-core-deploy NOT runner workspace; setsid daemon; ~1 min first-sync after restart
18	- [Linux SPT_HOME no-bug](linux-spt-home-no-bug.md) — unix spawn_detached inherits env (no env_clear), forwards SPT_HOME; only Win CreateEnvironmentBlock rebuilds/drops it (f99dc25). Default-home daemon = launched w/o the var, not a propagation bug; don't reopen
19	- [kitsubito Linux rig](kitsubito-linux-rig.md) — ssh reavus@kitsubito (key auth); cargo at ~/.cargo/bin; deploy checkout origin=local runner (NOT GitHub) so unpushed commits transfer via git bundle; live spt-daemon user unit, --user ops need no sudo; build-in-scratch leaves ~/.local/bin/spt untouched
20	- [Use $OWL send for messaging](owl-send-not-legacy-spt-send.md) — `$OWL send` works (legacy = where live perches run); `spt send` is the NEW spt-core binary but no perches on it yet → bounces NO_PERCH; don't read `$?` after piping send through tail (use PIPESTATUS)
21	- [daemon service-detection gotcha](daemon-service-detection-gotcha.md) — service detection reading GLOBAL OS state is blind on a single-home non-elevated dev box; gate Linux service routing on SPT_HOME-unset, Windows run-refuse on would-vanish (not is_elevated); push→CI BEFORE tagging a release (v0.3.0 tagged early, CI caught 2 regressions, retagged)
22	- [v0.3.2 platform-safe update](v032-platform-safe-update.md) — REQ-UPD-8 PUBLISHED + rig-verified 2026-06-09 (counter 6): fetch stages multi-platform update-set, apply refuses unstamped/wrong-OS single. Fleet kitsubito+hfenduleam=0.3.2 (ENLYZEAM TODO). GOTCHA: fetch/pump floor=staged_version → can't re-stage same version single→set; clear `$SPT_HOME/releases` first (Linux ~/.spt-core, Win %LOCALAPPDATA%\spt-core). CORRECTION: release-publish never built a SignedUpdateSet pre-v0.3.2 (was debug_rollout)
23	- [boot-race self-heal](boot-race-self-heal.md) — v0.3.1: daemon self-heals a net-less boot start (NetHost retry+attach to OnceLock broker); systemd-USER network-online ordering does NOT reliably prevent the race under linger (field-proven kitsubito) — the self-heal is the real guarantee, unit ordering is belt
24	- [v0.4.0 published + fleet rolled](v040-published-fleet-rolled.md) — restoration release PUBLIC 2026-06-10 (counter 7); D7-4 bytes-match done both nodes (brain.ready exe_hash == artifact); v0.3.2→v0.4.0 apply needed last manual bounce (in-process can't self-relaunch); seamless no-bounce proof + enlyzeam catch-up + milestone close all deferred to v0.4.1
25	- [v0.4.1 published](v041-published.md) — PUBLIC 2026-06-11 (counter 8); deployah drove full merge→tag→sign→publish solo; D7 SEAMLESS no-bounce fleet-verify payload (apply must roll bytes live w/ pid change, no manual bounce); acceptance hashes linux 35c9544c… win 728a1bfc…; hfenduleam(Win) GREEN no-bounce, kitsubito(Linux) RED → CLOSE BLOCKED: v0.4.0 broker respawns via current_exe() which follows apply-rename to .old-8=OLD bytes (Linux only); artifacts SOUND don't yank; v0.4.2 fix = respawn by canonical path + bytes-assert, needs manual Linux broker bounce; deployah takes counter 9 publish
26	- [hfenduleam disk-full CI](hfenduleam-disk-full-ci.md) — Win CI LNK1318/os-error-112 = disk full not code; cargo clean dev target (was 396GB), rerun job

... [1 lines truncated] ...


M10 implementation complete, gate-ready. This is my gate — verify independently, not rubber-stamp. todlando's three flags look sound on their face (per-wave activation = correct, already a captured lesson; owl-tap coarseness deferred; real-CC proof belongs to spt-claude-code repo) but I confirm against the tree. Kick the full sweep + read the capstone E2E + the load-bearing changes.


Bash

echo "=== branch/tree ==="; git branch --show-current; git status --short | head; git log --oneline 80d82bf..HEAD 2>&1; echo "=== START SWEEP ==="; echo "## traceable ##" && traceable-reqs check 2>&1 | grep -E "REQ-TERM-[4567]|EXIT|error|invalid|MISSING" ; echo "## clippy ##" && cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tail -4; echo "## test ##" && cargo test --workspace 2>&1 | grep -E "test result|FAILED|error\[" | grep -v "0 failed; 0 ignored; 0 measured; 0 filtered out; finished" | tail -40; echo "## two_origin int ##" && cargo test -p spt-daemon --test two_origin_spanning 2>&1 | grep -E "running|test result|FAILED|::"; echo "## nodefault ##" && cargo build --no-default-features 2>&1 | tail -3; echo "## xtask ##" && cargo run -p xtask -- check 2>&1 | tail -3; echo "=== SWEEP DONE ==="

Full M10 gate sweep


Command running in background with ID: b2y4d069v. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\13c96a50-2b78-4c16-a995-1da2b1836fd8\tasks\b2y4d069v.output. You will be notified when it completes. To check interim output, use Read on that file path.


Sweep running. Read the capstone E2E + load-bearing changes while it builds.