---
status: diagnosed
trigger: "Defect F: Psyche LLM (haiku) receives <project-context> envelope in stdin but never writes projects/<resolved_project>/<self_id>.md via the Write tool. Phase 25.3-02 absorption rules in psyche.md were supposed to teach this; they aren't sufficient."
created: 2026-05-22T22:30:00-07:00
updated: 2026-05-22T22:30:00-07:00
---

## Current Focus

hypothesis: CONFIRMED — psyche.md does NOT teach the LLM to Write `projects/<X>/<self_id>.md`. The architecture explicitly assigns that filesystem write to the Rust wrapper (`route_inbound_commune_body` / `route_two_slice_with_precedence`). The defect symptom ("LLM never writes projects/…/todlando.md") is misframed: nothing in the system asks the LLM to write that file. The reason the file did not materialize in the gen-28/gen-29 daemon.log is that those generations ran on **v1.11.4**, which predates the `route_inbound_commune_body` wiring (`feat(25.3-04)` commit `3c974ef`, plugin v1.11.5+).
test: source-text inspection of psyche.md + version-stamp grep on daemon.log + git log on `process_file_drop` callers
expecting: zero `Write` instructions for `projects/…/<self_id>.md` in psyche.md; v1.11.4 stderr stamp on the offending log; route_inbound_commune_body absent from v1.11.4 source
next_action: return diagnosis (root cause only — do not write code)

## Symptoms

expected: gen 29 echo-commune fire (or any of three preceding inbound communes) materializes `%LOCALAPPDATA%\spt\psyches\tracked\projects\claude_skill_owl\todlando.md` with the inbound `<project-context>` body
actual: project directory empty (Read-tool confirmed `tracked/projects/claude_skill_owl/` exists but contains zero files); no companion commit in seed worktree; LLM stdout each turn is a one-line ack
errors: none (silent miss — wrapper sees `exit=0` and proceeds)
reproduction: revive a Psyche under v1.11.4 binary while a `.claude/<id>-commune.md` is present that contains `<project-context>` — observe daemon.log shows `[FILE-DROP] consumed kind=commune … (deleted)` but NO `[FILE-DROP] route_inbound_commune_body …` line; tracked project dir stays empty
started: pre-existing since Phase 25 envelope teaching landed (`ff1d935` Plan 04 D-10/D-11) — the LLM-side teaching was always emit-only, with the disk write delegated to a wrapper helper that did not yet exist on the inbound path

## Required investigation targets — answered

### 1. psyche.md `<absorption>` section: does it instruct Write or just emit?

**Answer: emit only. The LLM is explicitly told it does NOT write the project file.**

`psyche.md:325-343` — `<absorption>` rules 1–6 (Phase 25.3-02). Each rule speaks to **merging** inbound deltas into in-memory context and **re-emitting** on the next cadence fire. The only filesystem write rule appears in rule 4 (line 337-338):

```
4. **SPT routes; you emit.** When you emit a `<project-context>...</project-context>` envelope,
   SPT (the Rust runtime) writes the body to `projects/<resolved_project>/{{self_id}}.md` and
   resolves `<resolved_project>` via Self's perch `info.json` `cwd` field (25.3-01 Defect B2 fix).
   You do NOT name the project; you do NOT know the filesystem path; the envelope shape is
   no-name throughout.
```

This is **the opposite** of teaching the LLM to call Write on the project file. It tells the LLM the runtime owns that destination.

The `<context_save>` section (`psyche.md:345-374`) instructs the LLM to Write only ONE file: `agents/{{self_id}}/live_context.md`. That file is supposed to hold BOTH envelopes (live + project) inside its body; downstream parsers (route_two_slice on echo_commune fire; route_inbound_commune_body on inbound) split the slices.

The asymmetry is intentional per Phase 25 D-10/D-11 contract:
- **LLM responsibility**: emit a two-slice envelope inside `live_context.md` (single Write).
- **Runtime responsibility**: split slices on emit AND on inbound; resolve project name via Self info.json; write `projects/<X>/<self_id>.md`.

There is no path through psyche.md where the LLM is asked to materialize the project file directly. The user expectation (Defect F framing) does not match the design.

### 2. Init session vs resume session: does init pass the pending-commune block to stdin?

**Answer: NO. `init_session` sends a fixed identity-only msg with no commune content.**

`src/live/wrapper/claude.rs:42-78` builds `init_cmd` and `init_msg`:

```rust
let init_msg = format!(
    "You are now active. Begin monitoring for {}. {}. Generation: {}.",
    self.self_id, pulse_phrase, self.gen
);
```

That string is fed verbatim to the init subprocess's stdin (line 112: `stdin.write_all(init_msg.as_bytes())`). The init prompt does NOT include:
- `[Current time: ...]` header (only `resume_session_with_exit:256` adds that)
- Any `CURRENT_LIVE_CONTEXT` / `CURRENT_PROJECT_CONTEXT` blocks
- Any inbound commune body
- Any `compose_passive_context()` blocks (only `resume_session_with_exit:255` calls that helper)

By contrast, `resume_session_with_exit:229-347` IS where inbound payloads flow. The wrapper routes the file_drop body through `compose_llm_prompt_from_envelope(msg)` (line 250) — that helper (`src/live/wrapper/mod.rs:557-625`) parses `<EVENT>` framing, decodes the body, and returns the decoded payload prefixed with a natural-language header. THIS is the stdin the LLM sees when a commune arrives. It contains the literal `<live-context>` / `<project-context>` tags as decoded body content.

But — and this is critical — the LLM is asked to **absorb** these tags (psyche.md rule 1 + 2), not to materialize them. The runtime is the writer.

**Init's role:** establish session UUID + register the psyche agent prompt. Nothing more. The session UUID is then used by every subsequent `--resume` call. The pending-commune file is NOT injected at init; it arrives later via the inner-poll file_drop pathway.

`append_pending_sections` (`src/live/context.rs:558-643`) IS the helper that reads `.claude/<id>-commune.md` and folds it into `live_context.md` (with destructive consume — see resolved debug `file-drop-file-gone-todlando.md`). But this helper is invoked from `download_payload` (CLI `psyche-download` + SessionStart hook injector), NOT from `init_session`. The wrapper itself never calls `append_pending_sections`.

### 3. Project-name resolution at LLM-write time. Where would a relative `projects/.../...md` land?

**Answer: the LLM is told there is no such write to perform; if it tried, it would resolve relative to `psyche_dir()` = `%LOCALAPPDATA%\spt\psyches\tracked\`.**

`src/live/wrapper/claude.rs:264` sets `resume_cmd.current_dir(owlery::psyche_dir())`. `psyche_dir()` returns `$SPT_HOME/psyches/tracked/` (`src/common/owlery.rs`, root-of-perches helper). So any relative Write the LLM did issue would land under `tracked/`.

Per psyche.md `<first_invocation>` (line 117) and `<context_save>` (line 346), the only Write the LLM is asked to do is to the relative path `agents/{{self_id}}/live_context.md`. With cwd = `tracked/`, that resolves to `tracked/agents/<self_id>/live_context.md` — exactly the per-agent worktree the runtime expects. This is confirmed working by the gen-28 file_drop run (daemon.log line 22: `auto-commit: git_commit_context after resume_session_with_exit`, paired with the seed worktree commit `d82baae commune: todlando live_context — <live-context>` that touched ONLY live_context.md).

psyche.md never mentions the path `projects/<resolved_project>/{{self_id}}.md` as a Write target. Rule 4 of `<absorption>` explicitly says "you do NOT know the filesystem path." If the LLM independently invented a Write to `projects/claude_skill_owl/todlando.md`, it would create `tracked/projects/claude_skill_owl/todlando.md` (correct absolute location by coincidence with cwd) — but the haiku has no way to know `claude_skill_owl` is the right project name, because the prompt's project-block header is informational only (`CURRENT_PROJECT_CONTEXT (name=X):`) and rule 4 says "DO NOT echo it back as a name= attr."

So the LLM does have enough information in the prompt to construct the path IF it chose to ignore psyche.md, but it has been explicitly instructed not to.

### 4. Outbound `<project-context>` route on echo_commune / context-save. Does the haiku emit it?

**Answer: empirically NO during the gen-29 echo-commune fire — the haiku output contained only `<live-context>` and omitted `<project-context>`.**

Evidence from `tracked/seed/worktrees/todlando` HEAD `d82baae commune: todlando live_context — <live-context>` at 2026-05-22 17:01:37 (gen 29 echo-commune fire): the commit subject's `commune: todlando live_context — <live-context>` shape is produced by `compose_commit_subject` (`src/common/tracked.rs`) when the route_two_slice ran but only the live slice had content. There is no companion `commune: todlando project_context — …` commit at the same timestamp, which is the signature of an omitted project slice.

This omission was previously diagnosed as **Defect B / B2** in `.planning/debug/todlando-project-context-not-persisted.md`:
- B1 — haiku LLM ignored the "block-with-literal = in-project" rule;
- B2 — `derive_current_repo_names()` returned `"tracked"` (D-06 false positive) when called from `psyche_dir()` cwd, so the haiku's prompt either keyed the project block on the wrong name or didn't see a real project context.

B2 was structurally fixed by 25.3-01 (`resolve_self_project_name_via_info_cwd` via Self info.json `cwd` field) — but that fix shipped in v1.11.5+ AFTER the gen-29 capture. So under v1.11.4, the gen-29 haiku saw a malformed `CURRENT_PROJECT_CONTEXT (name=tracked):` (or no block at all) and chose to omit the project envelope from its [COMMUNE] body.

`build_current_context_blocks` at `src/owl/echo_commune.rs:891-934` is the prompt-builder; at v1.11.4 head (`30951b8`) it still relied on the old derive_current_repo_names resolver. At v1.11.5 head (`a4ad971` + `b2a579e` 260522-9zk fixes plus 25.3-01 Defect B2 fix), it switched to the info.json-cwd resolver — see lines 906-918 above (the `or_else` chain). The version captured by daemon.log is unambiguously v1.11.4 (stderr stamp on line 12: `[36m✓ READY:todlando-psyche (spt v1.11.4)[0m`).

### 5. `build_current_context_blocks` chicken-and-egg with first-commune literal

**Resolved at the source level by 260522-9zk (commit `b2a579e`).** The literal `(none — first commune in project)` is emitted whenever `projects/<X>/<self_id>.md` is missing AND a project resolves — explicitly to PREVENT the chicken-and-egg miss psyche.md `<output_envelope>` rule 2 + rule 3 then require the LLM to emit BOTH envelopes even with first-commune body. But under v1.11.4 the resolver returned `"tracked"`, and the haiku rejected the block as nonsensical. Compound bug.

After 25.3-01: resolver returns `"claude_skill_owl"` correctly, block renders, haiku emits both envelopes, route_two_slice writes BOTH files. Verified by `build_current_context_blocks_first_commune_literal_when_project_file_missing` test (`src/owl/echo_commune.rs:2507`) and `build_current_context_blocks_and_resolve_self_project_stamp_agree` symmetry test (`:2541`).

### 6. Symmetry diff: live_context.md success path vs project file failure path

**Live path** (LLM writes it):
- psyche.md teaches: Write `agents/{{self_id}}/live_context.md` after each batch (`<context_save>`) and at signoff (`<init_signoff>`).
- The body is wrapped in BOTH `<live-context>` and `<project-context>` envelopes.
- Runtime side: route_two_slice_with_precedence parses the body and splits to `agents/X/live_context.md` AND `projects/Y/<id>.md`. **Both** files are downstream products of the LLM's single Write to live_context.md.

**Project path** (runtime owns it):
- psyche.md says: "SPT routes; you emit." LLM never Writes the project file.
- Runtime side: route_two_slice* extracts the `<project-context>` slice from EITHER (a) the LLM's just-written `live_context.md` (echo_commune fire path) OR (b) the inbound commune body BEFORE the LLM sees it (Phase 25.3-04 `route_inbound_commune_body` at `src/live/wrapper/mod.rs:1481`). In both cases the LLM is bypassed for the disk write.

The asymmetry vs the user expectation: the user expects the LLM to be the writer for both files. The runtime owns one of them. There is no "LLM writes project file" code path that is failing — the path simply doesn't exist by design.

### 7. Init session prompt composition (one more time, with file:line proof)

`src/live/wrapper/claude.rs:42-148` `init_session`:
- Builds `init_msg` (line 50–53): fixed identity string. No commune content. No live_context. No project_context.
- Spawns `claude -p ... --agent owl-psyche --name ...` (line 58–78).
- Writes `init_msg` to child stdin (line 112).
- Captures the session_uuid from stdout (line 142), stores it in `self.session_uuid`.
- Does **NOT** call `compose_passive_context`, `compose_llm_prompt_from_envelope`, or `append_pending_sections`. None of those functions appear anywhere in `init_session`.

There is no version (v1.11.4, v1.11.5, v1.11.6, HEAD) where `init_session` consumes pending-commune content. Init is purely identity + session bootstrap. All inbound payload routing happens via `resume_session_with_exit` (or `final_session` for signoff), which only fires from the inner-poll loop AFTER init completes.

## Why Phase 25.3-02 tests didn't catch this

`tests/file_drop_integration.rs` and `src/live/wrapper/mod.rs:2222-2225` (the in-module Test 1 for inbound two-slice persistence) verify that **`route_inbound_commune_body` writes both files when given a body string with both envelopes**. They confirm the runtime side of the contract.

What is NOT tested:
1. **psyche.md absorption rules are tested STATICALLY** by `tests/native_psyche_md_static_invariants.rs` (the Plan 25.3-02 contract grep tests). These assert the rule text exists; they do NOT exercise an LLM reading the text and behaving as expected. The LLM-side behavior is unverifiable in unit/integration tests.
2. **End-to-end: write `.claude/<id>-commune.md` → boot wrapper on v1.11.4 → assert projects/.../id.md materializes**. No such test exists. v1.11.5+ would pass (route_inbound_commune_body fires synchronously); v1.11.4 fails silently.
3. **The defect framing itself** — "LLM writes the project file" — is not a behavior the test surface tracks because it is not a designed behavior. There is no assertion of the form "the LLM emits a Write tool call to `projects/.../<id>.md`" because the contract says the LLM does not do this.

Test coverage gap = expectation gap. The contract docs and tests are consistent with each other; the user mental model (LLM-as-writer) doesn't match the code's runtime-as-writer architecture.

## Compounding with Defect E (file-drop-file-gone-todlando.md)

The user noted these defects compound. Concretely:

- **Defect E (resolved, diagnosed):** `psyche-download` destructively consumes `.claude/<id>-commune.md` BEFORE the wrapper's file_drop pathway drains the spool. The wrapper hits ENOENT and logs `(file gone)`, returns `FileDropOutcome::Continue` without firing `route_inbound_commune_body`. Even on v1.11.6 with the synchronous route wired, if Defect E fires, route never runs.
- **Defect F (this debug — diagnosed):** Under v1.11.4 binary, even when the file IS present and the wrapper successfully read it, `route_inbound_commune_body` did not exist in the code path. The LLM was the only consumer; the LLM only wrote `live_context.md` (not the project file); the project file never materialized.

Combined timeline for an operator running v1.11.4 AND triggering psyche-download before wrapper drain:
1. Operator writes `.claude/todlando-commune.md` with `<project-context>`.
2. Operator runs `psyche-download todlando` → `append_pending_sections` consumes + deletes file (Defect E precondition).
3. Operator runs `$LIVE revive todlando` → wrapper boots.
4. Inner-poll drains stale spool envelope; `process_file_drop` reads → ENOENT → `(file gone)` log; route never fires (Defect E completes).
5. Even if step 4 had read the file successfully, v1.11.4's `process_file_drop` body does not contain the `route_inbound_commune_body` call (Defect F: the synchronous route wiring is post-v1.11.4).
6. The LLM gets the envelope via `resume_session_with_exit`, absorbs it per psyche.md rules, and writes ONLY `live_context.md`. Project file never created.
7. Eventually echo-commune fires (gen N→N+1). The haiku prompt's `CURRENT_PROJECT_CONTEXT` block was build_current_context_blocks-resolved to `"tracked"` (D-06 false positive under v1.11.4). Haiku declines to emit `<project-context>` (Defect B/B2 from todlando-project-context-not-persisted.md, also pre-25.3-01).
8. route_two_slice on echo_commune fire sees only the live slice; project slice absent; project file still not created.

Net: under v1.11.4 + psyche-download timing, three independent paths each independently fail to materialize the project file. Under v1.11.5+: 25.3-01 fixes the resolver (path 7→8 produces a project envelope); 25.3-04 fixes the inbound wrapper route (path 4→5 produces a synchronous direct write). Defect E (psyche-download destructive consume) is the only remaining gap on the inbound side; it's diagnosed in `file-drop-file-gone-todlando.md` and a fix is sketched there (Option D: single-writer contract).

## Confidence: HIGH

Reasons:
- **psyche.md text is unambiguous.** Rule 4 explicitly assigns the project file write to the runtime ("SPT routes; you emit"). Read sites at `psyche.md:337-338`. No competing instruction anywhere.
- **`init_session` source is unambiguous.** No code path in `src/live/wrapper/claude.rs:42-194` references pending-commune content, append_pending_sections, or commune bodies. Identity bootstrap only.
- **Version stamp in daemon.log is unambiguous.** `(spt v1.11.4)` on line 12; the commit graph (`30951b8` head before `3c974ef` Plan 25.3-04 landing) confirms route_inbound_commune_body did not exist on this binary.
- **Empty `projects/claude_skill_owl/` directory observed today** (May 22 22:00 mtime, 0 files inside). Confirms no write site (LLM nor runtime) has materialized the file on this perch yet. The mtime suggests `ensure_project_worktree` was called recently — likely from a later post-v1.11.4 run that started the route but didn't get past Defect E.
- **Two prior debug docs converge.** `todlando-project-context-not-persisted.md` (compound Defect A+B+B2) and `file-drop-file-gone-todlando.md` (Defect E) both identified failure paths that prevent project file materialization. This debug (Defect F) is the SAME issue viewed from the "LLM is the wrong writer" angle. Three independent diagnoses, one underlying architectural shape: LLM-as-writer model conflicts with runtime-as-writer design.

## Suggested fix sketch — pick one or layer

The defect framing rests on a misaligned expectation. Three fix shapes, ordered by surface area:

### Fix 1 — Tighten psyche.md teaching (smallest)

Add a one-liner to `<absorption>` rule 4 reinforcing the boundary, plus one defensive Write-tool-restriction in `<tool_access>`:

```
<absorption> rule 4 addition:
   Do NOT issue Write tool calls to `projects/...` paths. Those files are wholly
   runtime-managed. Your only Write target is `agents/{{self_id}}/live_context.md`.
```

This codifies what is already implied. It does NOT fix the v1.11.4 backlog (LLM following the rule still produces no project file under v1.11.4), but it removes the "LLM should be writing it" ambiguity for future readers / model rev changes.

**Trade-off:** Zero effect on actual file materialization. Pure clarity / future-proof.

### Fix 2 — Wrapper-side fabrication of empty project file at first absorption (small)

Inside `route_inbound_commune_body` (post-25.3-04 wiring), if `<project-context>` is absent in the inbound body but a project resolves via `resolve_self_project_name_via_info_cwd`, write a stub file:

```
projects/<resolved>/<self_id>.md:
(first inbound commune absorbed; awaiting project-context emit on next cadence)
```

This ensures the directory + file exist after the first commune even when the inbound body lacks the project slice. Echo-commune's `build_current_context_blocks` then sees the existing file (instead of falling back to first-commune literal) and the haiku has prior content to merge.

**Trade-off:** Creates non-content stubs that may confuse the haiku's "merge prior" semantics on the very next echo. The first-commune literal already exists for exactly this case; this fix duplicates the semantic at a different layer.

### Fix 3 — Fold absorption into the inbound `route_inbound_commune_body` path so wrapper writes regardless of LLM behavior (already done as of 25.3-04; verify shipping)

This is what 25.3-04 commit `3c974ef` already did. The wrapper synchronously writes BOTH slices on inbound, BEFORE the LLM sees the envelope. The LLM's absorption + later re-emit is no longer the only path to disk.

**Action required:** confirm the operator-visible defect was observed on a binary that PREDATES `3c974ef`. The daemon.log stamp (`v1.11.4`) confirms this. Once the operator's `$LIVE` shell binding points to v1.11.6 (or whichever cache slot holds the 25.3-04 wiring) AND Defect E is independently mitigated, this defect's symptom should self-resolve.

**Verification step (no code change):** After confirming v1.11.6 binary is active, write a fresh `.claude/<id>-commune.md` with `<project-context>` body, boot wrapper WITHOUT pre-running `psyche-download` (sidestep Defect E), and assert `projects/<resolved>/<id>.md` materializes via the daemon.log `[FILE-DROP] route_inbound_commune_body for <id>` line.

### Recommended: Fix 1 + verify Fix 3 already-shipped

Fix 1 is cheap clarity insurance; Fix 3 is the architectural fix and already exists in code. Fix 2 is not recommended — it introduces a "wrapper creates empty file" semantic that complicates the haiku-merge contract for no clear gain over Fix 3's direct write of the actual inbound slice.

The root cause is not "psyche.md doesn't teach enough"; it's that the gen-28/gen-29 daemon.log was captured on a binary version that lacked the wrapper-side route. The teaching is already correct (LLM emits; runtime writes). Once the runtime side ships (v1.11.6 wiring + Defect E mitigation), the file materializes.

## Files Involved (file:line)

- `psyche.md:325-343` — `<absorption>` rules 1–6 (Phase 25.3-02 teaching).
- `psyche.md:337-338` — rule 4: "SPT routes; you emit" (the assignment of project-write responsibility to runtime).
- `psyche.md:108-131` — `<first_invocation>`: only Write target is `agents/.../live_context.md`.
- `psyche.md:345-374` — `<context_save>`: only Write target is `agents/.../live_context.md`.
- `psyche.md:238-273` — `<init_signoff>`: only Write target is `agents/.../live_context.md`.
- `src/live/wrapper/claude.rs:42-194` — `init_session` (fixed identity-only stdin; no commune content).
- `src/live/wrapper/claude.rs:50-53` — exact init_msg construction.
- `src/live/wrapper/claude.rs:229-347` — `resume_session_with_exit` (where inbound envelopes DO reach the LLM).
- `src/live/wrapper/claude.rs:250` — `compose_llm_prompt_from_envelope(msg)` decode site.
- `src/live/wrapper/mod.rs:503-521` — `route_inbound_commune_body` (Phase 25.3-04 synchronous direct route).
- `src/live/wrapper/mod.rs:1430-1498` — `process_file_drop` body, including line 1481 call into `route_inbound_commune_body` (added in `3c974ef`).
- `src/live/wrapper/mod.rs:557-625` — `compose_llm_prompt_from_envelope` (DECODE site at LLM stdin boundary).
- `src/owl/echo_commune.rs:541-617` — `route_two_slice_with_precedence` (project-slot resolver + Write site).
- `src/owl/echo_commune.rs:891-934` — `build_current_context_blocks` (Phase 25.3-01 layered resolver via info.json cwd).
- `src/owl/echo_commune.rs:920-931` — exact `CURRENT_PROJECT_CONTEXT (name=…)` render (informational header, not echoed by LLM).
- `src/live/context.rs:558-643` — `append_pending_sections` (destructive consume site invoked from `download_payload`, NOT from `init_session`).
- `C:/Users/decid/AppData/Local/spt/psyches/tracked/agents/todlando/daemon.log` — captured under v1.11.4 stderr stamp (line 12).
- `C:/Users/decid/AppData/Local/spt/psyches/tracked/projects/claude_skill_owl/` — present but empty (0 files).
- `.planning/debug/todlando-project-context-not-persisted.md` — sibling diagnosis (Defects A + B + B2).
- `.planning/debug/file-drop-file-gone-todlando.md` — sibling diagnosis (Defect E — psyche-download destructive consume race).

## Resolution

root_cause: psyche.md does not — and never has — instructed the Psyche LLM to Write `projects/<resolved_project>/<self_id>.md`. The contract assigns that filesystem write to the SPT runtime (`route_inbound_commune_body` on inbound, `route_two_slice_with_precedence` on outbound). The user-observed "LLM doesn't materialize the project file" is a misframed symptom; the LLM was never the designated writer. The actual file-non-materialization in the gen-29 daemon.log run is fully explained by three pre-existing diagnosed defects compounding on v1.11.4: (B) haiku omitted `<project-context>` from its echo-commune fire because the v1.11.4 resolver returned `"tracked"` instead of `"claude_skill_owl"`; (E) operator-side `psyche-download` destructively consumed `.claude/todlando-commune.md` before the wrapper's file_drop drain, causing the inbound route to ENOENT silently; (F, this) the wrapper-side `route_inbound_commune_body` synchronous route did not yet exist in v1.11.4 (commit `3c974ef` landed in v1.11.5+). Defect F is the architectural shape; B and E are the immediate triggers under v1.11.4.

fix: pending user choice — see "Suggested fix sketch" above. Recommended: psyche.md clarification (Fix 1, ~3 lines) + verify v1.11.6 binary materializes the file end-to-end (Fix 3, no new code — operator UAT) + close Defect E per its own debug doc's Option D (single-writer contract, ~10 line patch in `src/live/context.rs`).

verification: (pending — root-cause-only mode per task instructions)

files_changed: []

### Specialist Hint

rust
