# ECHO-COMMUNE / AUTHORED-COMMUNE DROP COLLISION

**Status: RESOLVED UPSTREAM 2026-09-09 — spt-core 0.68.0.** The upstream core Request tracking this
collision is closed (completed). Core's echo-commune host no longer writes `<id>-commune.md`: it routes its brief
straight into the durable context tiers and publishes the `COMMUNE` io-event, so the drop path is a
single-writer channel owned by the agent again. The published contract
(`harness-contract/echo-commune.md`) now states it as an invariant — *"The echo routes; it does not
file… there is no window in which the brief sits as a file — for anything else to overwrite, or to
be overwritten by"* — and names `commune_dir` as the agent's channel, which core filed to only
*until v0.67.x*.

Adapter consequences, shipped in **claude-spt v0.40.0** (`REQ-ECHO-DROP-RACE-RETIRED`):
the recharge timing workaround this collision forced into the live brief is retired, the two
statements 0.68.0 made false are corrected rather than deleted, and `min_spt_core_version` moves to
`0.68.0` because that floor is what makes the new brief text true. The `Source: echo-commune`
authorship refusal (`REQ-COMMUNE-ECHO-NOT-AUTHORED`) is UNCHANGED and still required — core kept the
provenance header deliberately for that consumer, and the echo still publishes COMMUNE frames.

*Everything below is the original 2026-09-06 record, left intact.*

**Status (original):** root-caused 2026-09-06 by direct observation. The defect is CORE-side.
claude-spt v0.38.2 is NOT implicated and needs no patch release.

## The record this corrects

The 07:48Z across-commune carried a wake directive asserting that v0.38.2's quotation mask
(`mask_quoted`, REQ-WAKE-MARKER-QUOTED) had regressed and told the next session to ship 0.38.3 and
reopen alchemy #28. **That directive was wrong**, and it was wrong the way a verdict is wrong when
it asserts more than it measured: an A/B was run (a commune with backticks did not arm, one without
did), the difference was attributed to the only code that had changed that day, and the payload the
mask actually ran on was never read.

`mask_quoted` is correct. Replayed against the exact failing commune body, byte for byte:

```
has_wake_marker(masked) = TRUE   (pair = the authored directive, sliced correctly)
```

The mask never had a chance to be the cause, because **the adapter never saw that body at all**.

## What actually happened

`spt api io-events perri --after <seq>` replays the funnel *without* writing the session cursor —
a non-destructive instrument for exactly this question. The COMMUNE frames around the failure:

| seq | time (UTC) | payload | `!!wake!!` raw → masked |
|-----|-----------|---------|------------------------|
| 305 | 07:42:38 | `Source: echo-commune` + psyche summary | 2 → **0** (both quoted) |
| 318 | 07:49:02 | my verbatim authored drop | 2 → **2** |

The authored commune written at 07:42:27 produced **no COMMUNE frame at any seq**. The frame that
arrived 11s later was an unrelated *echo-commune* — the psyche's own summarization — whose two
marker mentions are both inside backticks. The mask masked them, `has_wake_marker` returned false,
and the adapter correctly declined to arm a boundary on a body that never asked for one.

So the boundary did not fail to fire on my commune. **My commune ceased to exist**, and the adapter
armed nothing because there was nothing to arm from.

### Who destroyed it — observed, not inferred

A watcher polling `.claude/perri-commune.md` every 500 ms, while this session wrote nothing:

```
[07:58:05] PRESENT  head1=Source: echo-commune|<project-context>|## spt-claude-code — 0.38.1 …
[07:58:09] absent
```

and the matching frame:

```
343  07:58:09  COMMUNE  ECHO  len 4149
```

**Core's echo-commune host writes the agent's own authored drop path**, then core's watcher ingests
and deletes it 4s later. The drop file has two writers and no arbitration. An authored across-commune
still waiting for ingest is overwritten by an echo-commune that happens to fire in the same window —
last writer wins, silently, at both ends.

### The correlation, across the whole funnel history (342 events)

Five authored drops, five outcomes, no exceptions:

| authored drop | nearest echo-commune | authored frame emitted? |
|---|---|---|
| 07:06:02 | none nearby | yes (seq 236) |
| 07:09–07:10 | none nearby | yes (seq 244–248) |
| 07:28:45 | 07:28:48 (**+3s**) | **no** — only the echo (seq 288) |
| 07:42:27 | 07:42:38 (**+11s**) | **no** — only the echo (seq 305) |
| 07:48:56 | 07:50:18 (+82s) | yes (seq 318) |

Every authored commune lost had an echo land inside the ingest window. Every one that survived did
not. The 07:28 loss went unnoticed at the time because the file leg happened to read the drop before
the echo overwrote it, so the boundary fired — off a body that was then destroyed anyway.

## Why no adapter leg can cover this

The two legs are complementary by construction and both are defeated by the same event:

- **File leg** — reads the drop while it is on disk. Loses the race when the echo overwrites first.
- **Frame leg** — reads what core ingested. Reads the *echo's* body, because that is what core
  ingested. REQ-COMMUNE-FRAME-BACKSTOP's premise, "the COMMUNE frame carries the drop's bytes
  VERBATIM", holds only for the bytes of whichever writer won. It is a true statement about the
  file and a false one about the *author*.

There is no third surface. Once the echo has overwritten the drop, the authored body exists nowhere:
not on disk, not in the funnel, not in the digest (an ingested commune writes no digest entry), and
not in the mind — the mind received the echo's summary instead.

**This is the half the adapter cannot fix.** Even a leg fast enough to always arm the boundary would
carry the agent across a reset into a psyche that never received the context delta it authored. The
agent wakes re-briefed on a summary of what it did *before* the work it just communed about.

## Timing: why the turn's-final-act commune is the exposed one

Core's ingest floor is 2.8–5.8s (measured, v0.38.0). Against that:

- **PostToolUse** fires ~1s after the writing tool returns — comfortably inside the floor. But its
  matcher is `Write` only, so a Bash/`cat`-written drop gets no PostToolUse at all.
- **PreToolUse** fires on the next tool call — covers a commune written mid-work.
- **Stop** fires only after CC finishes generating the turn's closing assistant text. Measured on the
  07:42 turn: commune written 07:42:27, Stop's payload published 07:42:37 — **~10s**, of which the
  900 ms settle is a small part. The rest is model generation time, which the adapter does not
  control.

So a commune written as a turn's **final** tool call is unread for ~10s — twice the ingest floor and
wide open to the echo. That is the shape both losses took.

## Actions

1. **CORE (doyle):** the echo-commune host and agent-authored across-communes share one drop path
   with no arbitration. Needs a core-side answer — a separate path for echo output, or a refusal to
   overwrite an unread drop, or a merge. Filed with the evidence above.
2. **ADAPTER (mine), gated on 1:** widening the PostToolUse matcher from `Write` to `*` would put a
   read ~1s after any tool-written drop, inside the ingest floor. REQ-COMMUNE-DROP-DETECT explicitly
   **rejected** this (a plugin republish, plus a second hook spawn on every tool call), and that cost
   is real and fleet-wide. It also only recovers the boundary half, never the content half. Hold it
   until core answers: if the collision is arbitrated core-side, the existing legs are sufficient and
   the fleet pays nothing.
3. **alchemy #28:** stays `done`. Correct the record on it — the mask shipped correct.

## Method note, kept because the outcome hides it

Three sessions in a row treated "the thing that changed today" as the thing that broke. The
falsifier cost one command: replay the funnel with `--after` (non-destructive) and read the payload
the predicate actually ran on. It answered in one poll what two A/B experiments and a code re-read
could not, because both of those were interrogating a body that was never the input.

## Addendum 2026-09-06 — the second defect, and a scope correction

The collision above is core's. It had a sibling that was mine, found hours later when the operator
reported a live agent being `/clear`ed repeatedly: **both arming legs asked whether a commune
existed and neither asked who wrote it.** The pre-v0.37.0 detector keyed on the agent's own `Write`
tool call and so answered authorship as a side effect; moving the trigger to the drop file, and then
to the ingested frame, deleted that property without anyone naming it. Core's echo host writes to
the same path, so an echo whose summary carried a bare marker read as a handoff request.
Fixed in v0.38.3 (`REQ-COMMUNE-ECHO-NOT-AUTHORED`): both legs refuse any commune carrying a
`Source: ` provenance header. Field-verified on the shipped binary in both directions.

v0.38.2's quotation mask had been masking this bug's symptom for hours — it held only while an
echo's marker mentions happened to be backticked, which is a property of the summarized text rather
than of the rule. That accidental shield is also what sent the whole investigation at the top of
this document down the wrong path.

**Scope correction.** I reported the affected endpoint as taking four unrequested clears. That came
from four arm lines in the hook trace, which say an arm happened and nothing about who asked for it.
Measured on that endpoint's own funnel, three were its own authored communes; only the 07:24Z arm is
this class. The exposure was real and fleet-wide (four echo frames on my funnel at raw 2 / masked 0)
— the observed frequency was not. Same failure as the mask verdict, in the same day: asserting more
than was measured.

**Core ruling since:** the echo must never write `<id>-commune.md` at all — its brief routes
straight into the tiers, no file — which dissolves the collision at its source. The `Source: `
refusal stays as defence in depth, and the echo io-event keeps that exact head so it keeps working.

## Addendum 2026-09-06 (later) — the same defect's second face: stale wakes (v0.38.5)

The operator reported that every time the affected endpoint "communed across", its new session
opened on a stale wake ("v0.66.0 era, already shipped"). A full non-destructive replay of that
endpoint's funnel (`io-events --after 0`) settled the premise before the mechanism: **seven
`clear` events that day and zero authored, marker-bearing COMMUNE frames.** The endpoint never
communed across. Each clear was armed off an echo frame (pre-0.38.3) or a replayed week-old
frame (pre-0.38.4), and the wake it woke on was that frame's directive — the arm and the stale
text were one event, not two bugs. 0.38.4 has held since 08:41Z: five polls, ~50 replayed marker
frames in their windows, zero arms.

What remained ours: the loop armed on the FIRST eligible frame in log order and returned. A
replayed block lists ahead of the live tail, so even a genuine across-commune would have parked
the replayed frame's directive whenever the age guard admitted one. v0.38.5 arms from the NEWEST
eligible frame (highest `at_ms`) — a replayed frame is older than a fresh commune by construction,
so a requested boundary now wakes on the right text independently of what the age guard admits.
`REQ-COMMUNE-FRAME-NEWEST`, two window-order tests, mutation-checked.

Lesson, same shape as the scope correction above: two people reported two bugs ("unrequested
clear", "stale wake") that were one defect, and the second report's premise ("he communed across")
was false. Replay the funnel before believing the premise of a report, including the operator's.

## Addendum 2026-09-06 09:07Z — v0.38.5 frame leg field-verified on a clean across-commune

Two attempts. The first (09:00Z) armed on the DROP leg, not the frame leg: the PostToolUse hook
of the `Write` call that produced the drop saw the file 888ms after the write, and ingest takes
2.8-5.8s, so the drop was still on disk. "Write it as the turn's last act" avoids the hooks AFTER
the write; it does not avoid the PostToolUse OF the write. Datum `FRAME-LEG-0385-FIELD-CHECK`,
funnel seq 82.

The second (clean) attempt had a detached background process write the drop 3s after its Bash
tool had returned, so no hook could see the file. Datum `FRAME-LEG-0385-CLEAN-TEST`. Observed in
`hook-trace.log` and on the funnel (`io-events perri --after 0`, non-destructive):

- The COMMUNE frame landed at seq 102, `at_ms` 09:05:23.998Z, 1878 bytes, payload starting
  with my bytes (`!!wake!! FRAME-LEG-0385-CLEAN-TEST`). Core's echo ingested as its OWN frame
  later (seq 117, `Source: echo-commune`) — it did not overwrite the delta this time.
- No `drop detected` line for perri anywhere in the session window (session stamp 08:59:39Z).
- The arm came from the Stop hook (pid 49552) at 09:07:14Z: "across-commune detected in an
  ingested COMMUNE frame for perri at seq 102". The poll window listed 22 COMMUNE seqs; the 21
  replayed ones (seq 120..343, `at_ms` 2026-08-30 .. 09:05Z-minus) were each refused by the
  0.38.4 age guard, and seq 102 — listed LAST and carrying the LOWEST seq, because the funnel's
  numbering restarted below the old block — won as the newest by `at_ms`. That is exactly the
  0.38.5 newest-wins rule doing the work the first-listed rule could not.
- SessionStart(clear) released the latch at 09:07:16Z; the new session opened on the datum text.

Frame-to-arm latency was 111s, the remainder of the authoring turn: Notification(idle_prompt)
at 09:05:24Z runs no funnel poll, and no PreToolUse fired between the write and Stop. Not a
defect — the boundary fires at turn end regardless — but it is the number to remember when a
detached writer is used: the arm waits for the next polling hook, not for ingest.

Verdict: 0.38.5 frame leg field-verified, newest-frame wake correct, on a commune the drop leg
could not have seen. The instrument that settled it was the same one as every finding in this
document: replay the funnel and read the payload the predicate ran on.
