# W2 / releases#238 — mid-turn frames: design-proposal JIT plan

**Status:** grounding done on point 3, not yet written as the artifact doyle gates.
**Deliverable:** a DESIGN PROPOSAL DOCUMENT (not a message) settling four points. doyle gates the
proposal BEFORE any build. This wave blocks perri and is the priority after W1.

W1 (#235) is LANDED at main `786d2381`, gated on both arms. Nothing owed there.

## The operator ruling this sits under

ATTRIBUTE on `AGENT_OUTPUT` (issue comment 5461768445), and shortform AND `;;` seal markers parse
ALL agent output including mid-turn.

## The four points, and where each stands

### 1. The attribute's shape + the #234 reader's tolerance — VERIFY, DO NOT ASSUME
doyle's brief names the attr-passthrough precedent and says explicitly: verify at the measured sha,
do not assume. **Not yet done.** Read the #234 reader and establish, from code at a named sha,
whether an UNKNOWN attribute on an IO frame is passed through, ignored, or refused. The precedent
being real is not evidence that this reader implements it.

Grounded so far: `crates/spt-proto/src/ioevent.rs` holds the closed kind vocabulary
(`IO_KIND_AGENT_OUTPUT`, `IO_KINDS`, `is_io_kind`) and `IO_PAYLOAD_CAP` (16KB, cut on a char
boundary). Frame composition goes through `shellchan::compose_io_frame(endpoint, kind, body, seq,
…)` — see `crates/spt-daemon/src/iobus.rs:452` for a call with its full argument shape.

### 2. Mid-turn parse under the exactly-once span respec
Non-overlap stays the ADAPTER'S reporting contract: "every reported payload span is reported
EXACTLY ONCE across the turn" (mid-turn chunks + closing remainder disjoint). Core's parse remains
per-ingest-call with NO cross-call dedup machinery, because core-side span dedup would require core
to model turn assembly — which the funnel design refuses on purpose (adapter knows its harness's
turn shape; core owns delivery). Restate in the proposal; it is ruled, not open.

### 3. THE BARE `;;` MARKER UNDER CHUNKED INGEST — the real question, and it is now grounded

Measured in `crates/spt-proto/src/shortform.rs`:
- `SEAL_MARK = ";;"` (line 211), `parse_seal_mints` (line 243).
- Ruling 12 — pairs first, greedily, left to right; two pairs = two ceremonies, never one seal
  spanning between them.
- Ruling 13 — an empty pair (`;;;;`, or whitespace-only) is ignored entirely: no ceremony AND no
  refusal, because a refusal there is noise about a non-event.
- **Ruling 14 — an odd trailing marker is the BARE case: it seals everything after it THROUGH END
  OF OUTPUT**, and the text between the last completed pair and that marker is left untouched.
- Pairing runs BEFORE the bare case, which is the only order under which `;;a;; middle ;;rest`
  reads as one pair plus one bare seal rather than three-marker soup.

**The problem, stated precisely:** "through end of output" is a claim about text the parser HAS NOT
SEEN when a mid-turn chunk is parsed. Parsing a bare marker per-chunk therefore seals to the end of
THAT CHUNK — a strictly smaller region than the author asked for — and it does so silently, because
a short seal is indistinguishable from a correct one in the output.

**doyle's lean:** defer-odd-marker-to-turn-close with per-turn parser state. **My proposal decides
and he gates it.** Note the tension to resolve explicitly: per-turn parser state is the beginning of
turn assembly, which point 2 says core must NOT model. The proposal has to say why a single deferred
marker is not that, or choose differently. That argument is the centre of this artifact.

### 4. Doc sweep + the W3 rate-figure correction (issue comment item 4)
Enumerate from the issue rather than from memory:
- taxonomy row end-of-turn sentence
- frames.md mid-turn paragraph
- frames.md parse-vs-16KB-cap ordering (parse runs over the FULL ingested payload; the cap bounds
  only the EMITTED frame body)
- patterns.md dedup note
- integration checklist row (respec'd per point 2)
- the W3 rate re-derivation
ADR-0048 decisions 1-3 stay perri's locked contract — restated in the brief, not reopened.

## Immediate next steps

1. Read the #234 reader at a NAMED sha; record what it does with an unknown attribute, with the
   file:line. This gates point 1's whole shape.
2. Enumerate the doc sweep sites by grep, not recall.
3. Write the proposal as a document; send doyle the path, not the body.

## Standing context

- Lane worktree `.worktrees/ir57`, pool claimed as `w1-235-spawn-liveness` — RE-CLAIM with a w2
  label at W2 build start (claim from the lane worktree so the identity written is the lane's).
- Land shape: thin PR off current main, ff-only, gated per PR, tested sha == merged sha.
- Waves after this: W3 #239 (new boundary event-class, three variants boot/clear/compact minted
  whole), W4 #229 (role absence → skip-with-loud-status, zero strikes). #241 stays COLD.

## STATUS UPDATE 2026-08-29 (post-clear session)

Steps 1-3 DONE. The proposal is written: `W2-238-MIDTURN-DESIGN.md` at the MAIN repo root
(C:\Users\decid\Documents\projects\spt-core), path sent to doyle, awaiting his gate.

- Point 1 MEASURED at sha 786d2381: the #234 reader IGNORES an unknown attribute (IoLogRow
  iolog.rs:98-119 has no flatten/deny_unknown_fields => serde discards; render_json
  ioevents.rs:237-262 is an allowlist projection). The passthrough precedent is real but lives
  on the EVENT wire (event.rs:255), NOT in this reader. So the attribute must be minted at 5
  named sites.
- Point 3 DECIDED (C): pairs parse mid-turn; an odd trailing ;; in a mid span refuses by name
  (SEAL_BARE_MIDTURN) and mints nothing; ruling 14 verbatim at turn close. Zero cross-call state.
  Declared as a NARROWING of doyle lean (A), whose price is stated in the doc.
- Point 4: 12 doc sites enumerated by grep; rate re-derived (module already carried ~540/hr and
  named this lane its owner) => fork to doyle: keep 1000 (rec) vs raise to 4000.
- Probe running: a temporary unit in crates/spt-store/src/iolog.rs tests (parse_line with an
  unknown JSON key) converts the one serde-default INFERENCE into a measurement. Untracked lane
  edit; keep it as the lane forward-compat unit or drop it.

NEXT (after gate): section 7 build order — registry first, then the 5 sites, then the bare-case
arm, units, doc sweep, e2e, both arms, thin ff-only PR.
