Date. 2026-08-14 · Mode. READ-ONLY, nothing built. Engine 3c925ba, surface 322a216 (clean).
The ordering question, answered first: AGREED — B-101 goes ahead. A record you can't read is data loss in effect, present tense, and every future save-offer conversation mints another poison turn; B-99 is a missing sentence on a correct outcome. B-101 is scoped first below; B-99's shape-sweep follows.
Today: ONE turn, ONE engagement — E0128 alone. The full census of persisted structured_data kinds in playground_dev: upload_results (13 turns / 1 engagement), voice_recording (7 / 2), answer_sources (1 / 1), save_offer (1 / 1 — E0128), plus 190 JSON-null rows (the normal no-payload case, harmless). The read union's five members cover everything persisted except save_offer. The unregistered set is exactly one tag.
Smaller than feared today — and structural tomorrow, which is why the urgency read still holds: the writer (converse.py:1456, the R1 held-tray fix — the offered note's number carried deterministically to the next turn) fires on every add_knowledge save-offer that carries a display number. Every future offer-bearing conversation adds a poison turn to its engagement. E0128's own came from the walk's composer captures — the Operator's Held 1/Held 2 pastes each drew an offer, and the offer wrote the tag.
conversation_turns.structured_data write flows through ONE composer block (converse.py's if/elif chain) plus the voice-recording attach path — emitting exactly the five union members plus save_offer. The other "kind" grep hits (agent, person, reconciliation_correction) are other domains' payloads (actor refs, credit proposals), not turn data. Code and database agree: one unregistered tag, not a family.dict[str, Any] (the orchestration dataclass, conversation_turns.py:124); ONLY the read side validates, through the discriminated union (orchestration/schemas.py:1572). The writer can mint any vocabulary; the reader finds out later. The single-source-of-truth vocab discipline (classifier/handler) extends here: kinds should be one enumeration both sides import — that is the fix that prevents tag N+1.save_offer is deliberately NOT in ConverseResponse ("internal signal only" — the write site's own comment); the live surface never sees it. Only the history read validates it. The defect was invisible until someone reloaded an offer-bearing conversation — E0128 was simply first.lib/types.ts:293-335) also lacks save_offer — the fix either adds it both sides or the surface treats unknown kinds as absent (degrade there too).invalid_input handler 422s the ENTIRE page. E0128's history is ~98% readable and 100% unreadable. Degrade shape: per-turn validation; an unknown/invalid payload projects as structured_data: null (optionally a placeholder marker), the turn's text still served. Its test: a page containing an unknown-tag turn returns the readable turns.
CR shape (small, no prerequisite): engine — add the save_offer union member; per-turn degrade-don't-fail; the kinds enumeration made single-source (writer imports it). Surface — the mirror member or tolerate-unknown. E0128's history becomes readable with no data change: the turn was always valid; only the reader's vocabulary was behind.
The criterion that separates the defect from the idiom: empties-as-idle-state rendered honestly vs empties-as-action-outcome swallowed by unmount. Sweep of every zero-length render gate in the surface:
isEmpty renders labeled empties), EngagementPickerDialog, SavedFilterList ("No saved filters yet…"), ToolsMenuView. The house already does idle-empties well — the defect was specifically an ACTION-outcome empty (the user's answer emptied the list) hitting a guard written for idle-empties.WorkspaceSelector (length === 0 → null): no in-component delete exists, so its empty is never an action outcome — and the component is currently unconsumed (its consumer was deleted; kept deliberately). Not the shape.CandidateCommitBanner unmounts on the very commit it exists to report — but its onCommitted triggers a full page reload whose landing state (the committed page, the list's "named and committed") IS the report. Reload-as-report is cruder than a rendered confirmation but not silent; if the reload ever becomes a soft refresh, this becomes B-99's shape exactly. One line in the B-99 CR's consequences is enough.B-99's fix stands as filed (the converged outcome renders a closing state — "nothing left open; this draft is ready to commit" — handing off to the banner; test drives the converged outcome and asserts the report renders before any unmount), now with the sweep's assurance that it is one site, not a class — and one sentence for the banner's adjacency.
The B-101 CR draft (engine union member + per-turn degrade + single-source kinds; surface mirror), then B-99's (one site, small, the sweep annexed). Both scoped; neither drafted.
DUNIN7 — Done In Seven LLC — Miami, Florida — B-101/B-99 scoping — v0.1 — 2026-08-14 One tag behind, one page hostage; the writer minted vocabulary the reader never learned. And the silent close is one site, not a habit.