---
name: v0360-io-compliance-parser-deleted
description: "2026-08-29 SHIPPED + FIELD-VERIFIED v0.36.0 — declared [io] compliance and deleted our own shortform parser; #22 actually CLOSED 2026-09-06 (this file wrongly claimed it a week early). Carries the \"moving a capability to core turns every skipped report into a skipped capability\" rule."
metadata: 
  node_type: memory
  type: project
  originSessionId: c7810e19-679a-4f30-bebf-26af403899a0
  modified: 2026-08-30T02:47:57.524Z
---

**2026-08-29 — claude-spt v0.36.0 SHIPPED.** Release B of two; see
[[v0350-midturn-spans-disjointness]] for Release A the same day.

## ⭐ I RECORDED A CLOSE I NEVER PERFORMED (corrected 2026-09-06)

This file said `claude-spt-bs#22` was **CLOSED** on 2026-08-29. It was not. On 2026-09-06 the
issue was still `OPEN`, `state: BACKLOG`, `updated_at 2026-08-29T03:49:52Z` — the timestamp of the
v0.33.0 *hold* comment. The ship happened; the tracker write never did. Nothing failed loudly:
there was no refusal to notice, because **no state verb was ever issued**. The shipping work and
the tracker close are two different acts, and finishing the first makes the second feel finished.

**A tracker state is not a belief — read it back from the consumer (`gh issue view`, `view #N`)
before writing it into memory.** Same family as `SHELL_SPOOLED` ≠ the op worked, and as the
mirror-script exit 0 that never applied: every one of them is a claim about a REMOTE state made
from LOCAL evidence.

Closed properly 2026-09-06 with a close-out comment (`5556834766`) + `state #22 done`; verified at
the consumer: `state: DONE`, GitHub `CLOSED/COMPLETED`, `closedAt 2026-09-06T04:15:46Z`.
Re-verified end-to-end on core **0.67.0** first, both shortform markers, anchored at `MAX_SEQ 159`:
`@<…@>` → seq 160 `AGENT_OUTPUT` → seq 161 `MSG_OUT` → `-> perri: delivered`; `;;…;;` →
`-> (seal): seal minted` (the seal marker had never been field-exercised through our ingest before).
Gate PASS + `traceable-reqs check` exit 0, tree clean at `9c9a508`.

Declared `[io] compliance = true` and deleted our `@<...@>` parser **in the same change** — the
published rule, so no version exists where core and adapter both parse and both send.

## FIELD-VERIFIED end-to-end, through core's own instrument

`spt api io-events perri --after 60 --json` over a self-targeted probe tag:

- `seq=62 AGENT_OUTPUT mid=True` — our span, carrying the tag
- `seq=63 MSG_OUT` — **core parsed it and committed the send**; this adapter made zero send calls
- `<DISPATCH_RESULTS> -> perri: delivered` — outcome via the single documented channel
- the probe message then arrived back as `<sptc_messages from="perri">`

## ⭐ THE RULE WORTH KEEPING: a skipped report becomes a skipped capability

Found by re-walking the early returns, NOT in the plan. The across-clear quiet window returns from
`handle_stop` before the idle report. Under our own parser that cost nothing — `scan_and_dispatch`
had already dispatched higher up, and the call site literally said *"outbound is never suppressed."*
Under compliance the dispatch is core's, and **core only sees what we report** — so that early
return silently stops dispatching every tag in the turn that arms a commune-across: the turn an
agent writes its handoff in.

**When a capability moves from adapter to core, every path that SKIPS REPORTING silently becomes a
path that SKIPS THE CAPABILITY.** An early return that was about one concern inherits every concern
that now rides the report, and the compiler cannot find them because nothing about them changed.

Fix rides the BUSY arm: `state busy --payload-stdin --mid`. The window's actual requirement is that
the endpoint stay BUSY (so inbound spools for the post-clear session); `--mid` marks busy
(idempotent), so the text reaches the parser and the window still does its job.
`REQ-HAZARD-ACROSS-CLEAR-DISPATCH-DROP`, KNOWN-HAZARDS 8.3.

## ⭐⭐ `s.index('id = "REQ-X"')` MATCHED A MENTION INSIDE ANOTHER REQUIREMENT'S TITLE

My retirement script cleared the stages of **`REQ-HAZARD-STOPFAILURE-STUCK-BUSY`** and pasted
another requirement's text into it — because these titles cross-reference each other's ids
constantly, so the first substring hit was a *citation*, not the definition. Caught only because
the gate printed the mangled entry.

**Never index into a structured file by substring.** Split on `[[requirements]]`, match the block's
OWN first line, assert each target found exactly once. Reverted with `git checkout --` and redone
block-aware. Same family as the `:(glob)` and `set -f` traps: the wrong answer looked identical to
the right one.

## ⭐⭐⭐ A MOCK THAT ANSWERS BOTH SEAMS ALIKE CANNOT FAIL WHEN THE WRONG ONE IS USED

`REQ-HAZARD-SEND-STATUS-STDERR` lost its unit evidence when I deleted the dispatch tests, but the
hazard survives with one consumer left (the compact redrive reads a send's status token). The
obvious replacement test would have been **vacuous**: the Recorder returned the same answer for
`spt` (stdout-only) and `spt_send` (stdout+stderr), so a `spt`-instead-of-`spt_send` substitution
would pass. Fixed by making the mock model the real contract — its stdout-only seam now returns `""`
for any `send`, exactly as production does. Mutation-verified: the substitution now fails that test
and only that test.

## ⭐⭐⭐⭐ Process notes

- **Let the compiler find the blast radius.** Deleting the fan-out first and following
  `never used` warnings surfaced all 8 dead items exactly, with no guessing.
- **My mutation harness refused to run** when an anchor matched twice (both legs call
  `report_midturn_span`). That refusal was the guard working — a mutation applied to the wrong site
  reads exactly like "caught".
- **Repeatedly patching a patch destroyed a script** (`mint_b.py` grew to 5000 lines of duplicated
  fragments). Rewrite from scratch after the second in-place edit.
- **Brief text ships in `adapter.spt`, not the cplugs skeleton** — I nearly claimed a plugin bump in
  the CHANGELOG. Only skill/hook/bootstrap/plugin.json changes need a republish.

## What survived the deletion, deliberately

The commune shortcut (`>>commune<<` — ours, core knows nothing of it), `assistant_texts_from_jsonl`
/ `complete_line_prefix`, the byte cursor + its first-run narrowing, and the Stop settle. `tag_scan`
went 456 -> 184 lines. 10 requirements retired onto DISPATCH_RESULTS with their reasoning preserved
in the retired titles. `shortform = false` NOT declared (it would leave no parser at all — see
[[v0330-io-funnel-hold]] for why that flag reads like an unblock and isn't).

## State

Repo clean at `63d139a`, `v0.36.0` on both remotes (mirror `de48c22`), asset verified at the
consumer, installed here. 509 tests, gate PASS, `traceable-reqs check` exit 0. Core floor 0.66.0.
`IO-COMPLIANCE-PLAN.md` closed out.
