DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/cr-2026-204-loomworks-chat-provenance-marker-v0_1.md

DUNIN7-M4 — INFRASTRUCTURE CHANGE REQUEST

CR-2026-204 — The chat-provenance marker: unconditional, structured, model-untouchable (v0.1)

Version. 0.1 · Date. 2026-08-11 · Author. Claude Code (drafting, from the disclaimer scoping) / Marvin Percival (approving). Target. /Users/dunin7/loomworks-engine AND /Users/dunin7/loomworks (the live surface — loomworks-ui is the stale one), both branch main. Baseline. Engine 64610b4, surface 35a49c9. CC confirms at Step 0. Companion to. inspection-briefs/loomworks-ungated-chat-disclaimer-scoping-v0_1 (record 34c27cc) and inspection-briefs/loomworks-ungated-chat-production-and-creation-batch-v0_1 (record c9edc3a) — where this CR and the briefs disagree, the briefs govern, verified against code. Charter. Autonomous regime. Status. DRAFT — awaiting the gate. Do not execute.


0. Settled — the Operator's rulings, 2026-08-11. Do not re-raise.

  1. Option 3 on ungated production: the Companion may produce prose with a governed equivalent, and must say plainly what it is not — chat text, not a Shape, no provenance, not in Memory or the record.
  2. Structured marker, unconditional. Selective firing needs a detector the server doesn't have, and selective absence becomes a claim held by a probabilistic layer — the weakest-layer failure moved up one level. Unconditional is the only version the server fully holds; it favors one standing marker over a repeated sentence. No detector exists anywhere in this CR.
  3. The frontend cost is accepted. A marker the model can't overwrite is a different guarantee from words in a string the model authors. The post-generation prose seam is not taken.
  4. This disposes of the unarmed promise for chat prose: the marker says outright that nothing governed was produced, so there is no okay-flow left to imply.

1. The design

A. The channel fact, on the wire and in the record. New field composition on ConverseResponse and new nullable TEXT column composition on conversation_turns (own column, the organized_view_citation precedent — structured_data holds one payload of things the turn produced; this is a fact about the turn's channel). Vocabulary, enumerated in full now (pre-flight shape 4): 'model_prose' and 'server_composed'. TEXT + CHECK constraint admitting exactly those two. Single source of truth: one constants pair in orchestration, imported by writer, migration test, and schema — never retyped.

B. Every branch stamps it — the assignment is exhaustive, not detected. Server-composed: cold-open greeting, completeness-check bypass, delegated responses (all _companion_error-built replies — denials, all-claim acks, held/committed acks, orient), the no-key fallback, the blank-reply substitution (6b), account-status replies. Model prose: path (b) generate_response output. Edge named and chosen: RESPONDER_FALLBACK (and the tier-voice-augmented path-b replies) arrive through generate_response and stamp model_prose even though the fallback string is server-authored — the marker's claims (not a Shape, no provenance, not in Memory) are true of them regardless; channel, not authorship, is what the marker asserts.

C. Persistence and projection. record_turn gains the composition kwarg; /operator/conversation-history projects the column. **Null stays meaningful: every turn written before this CR reads null = unrecorded, and the surface must render null as absent — never as server_composed, never as a marker.** (The B-52 empty-vs-null discipline, applied to a column.)

D. The surface marker (/Users/dunin7/loomworks). Companion turns whose composition is model_prose render one standing marker element — a small, persistent label in the turn's frame, not a sentence in the transcript text. Ruled wording basis: chat text — not a Shape, carries no provenance, not in Memory or the record (short label + the full sentence on disclosure is Step 3's design; the content of the claim is settled). Frontend disciplines apply: strings in strings.ts, no string concatenation in UI text, logical CSS, ONE-WIDTH law. Turns with server_composed or null render nothing.

2. Consequences named, so they are chosen

3. Tests — each observed failing first, per the standing discipline

Engine: every branch's stamp pinned (one test per branch arm of the converse dispatch — cold-open, completeness, delegated, orient, no-key, blank-fallback, path-b); persistence round-trip; history projection; CHECK constraint rejects a third value; null on pre-CR rows untouched by backfill (no backfill — deliberately). Surface (vitest, tests/components/lib/ per the B-71 collection rule if adapter-shaped): marker renders on model_prose, absent on server_composed AND null; strings from strings.ts. Fence: the trivial-small-talk turn carries it (unconditional pinned).

4. seed-mutability impact

Kind C expected: the marker reads the pipeline branch, writes a turn column, and renders — no seed contact on any path. Checked at Step 1 (the delegated branch carries seed-derived draft content through it; the marker itself reads none of it). A null finding is an entry; recorded either way.

5. Build steps

| Step | What | Mode | |---|---|---| | 0 | Pre-flight — baselines confirmed, both trees clean. | Auto | | 1 | Verify branch inventory §1B against code (every ConverseResponse construction site enumerated — none unstamped); tests written and observed failing. | Auto | | 2 | Engine: constants, migration, stamps, record_turn, projection. | Auto | | 3 | Surface: marker component + strings + history wiring. | Auto | | 4 | Both suites; ruff; mypy; surface vitest. Eye-test: a model-prose turn and a server-composed turn observed live with the marker present/absent (standing eye-test discipline). | Auto | | A | Checkpoint. | Checkpoint | | 5 | Tag cr-2026-204-chat-provenance-marker (engine) + surface commit. Push both. Watch both runs and report. Redeploy the surface per the recorded procedure. | Auto |

6. Acceptance gate

  1. Exhaustive stamping: every ConverseResponse construction site enumerated at Step 1 and stamped — a construction site with no stamp fails the suite (constructor-level default is not used; explicit at every site so a future branch cannot silently inherit a wrong value).
  2. Null discipline: pre-CR turns render nothing; no backfill in the diff.
  3. Unconditional pinned: the small-talk fence test.
  4. No detector anywhere in the diff — no reply-content inspection of any kind.
  5. Both suites green (zero failures); gates clean; both push runs watched and reported; surface redeployed and eye-tested live.
  6. seed-mutability recorded.

7. Kickoff prompt


Execute CR-2026-204 v0.1 at change-requests/cr-2026-204-loomworks-chat-
provenance-marker-v0_1.md in loomworks-record. Confirm CR number and
both baselines first. Two repos: engine + /Users/dunin7/loomworks (NOT
loomworks-ui).

§0 is settled: structured marker, unconditional, no detector. If you
find yourself inspecting reply content to decide whether to mark, stop
— that is the ruled-out design.

The stamp is explicit at every ConverseResponse construction site; no
constructor default. Null means unrecorded and renders as absent —
never backfill, never render null as server_composed.

Each test observed failing first. The small-talk fence test is the
ruling in test form: a "hello" turn carries the marker.

DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-204 — the chat-provenance marker — v0.1 — 2026-08-11 The channel says what it is; absence is never a claim.