Version. v0.1
Date. 2026-06-25
Status. Drafted. Not executed. Requires Step 0 grounding (below) and Operator authorization before any code.
Type. Defect fix — Companion conversational voice.
Grounds on. Scoping note loomworks-conversational-fidelity-scoping-note-v0_1 (filed loomworks-record c60f565). Exact text of companion_persona.md (dd21818) and commit_assertion.md (40eff76).
Seed check. Cleared against candidate seed v0.12 — fix implements both plain-terms discipline and fidelity-about-state; reconciles them rather than trading one off. See scoping note "two seed commitments in tension."
The Companion tells the Operator that held drafts are "saved" and "in the record" during normal conversation. They are not — they are held, awaiting commit. This fixes it by teaching the persona which plain word goes with which state: a draft awaiting the Operator's okay is "waiting," and only committed work is "saved" / "in the record." No new vocabulary, no return of engine words ("held"/"committed") to the conversational voice. One persona file changes; one optional template aligns; one test guards the fix.
The conversational voice runs through the responder LLM path: general_conversation → route_intent returns None (router.py:2709) → converse.py no-route branch → assemble_prompt(...) → generate_response(...). assemble_prompt opens unconditionally with companion_persona.md.
The persona's NEVER list bans the engine state-words and offers saved and waiting as plain replacements — but does not bind word to state. The list is state-blind. The LLM, asked about a held draft, picks "saved" and produces a false state claim ("it's saved, it's in the record") for work the Operator has not committed. This violates fidelity-about-state (Operator-authority: an artifact is not in a state until the Operator moves it there) while the surrounding plain-terms substitution is doing its job correctly.
The honest distinction already exists in the system — commit_assertion.md draws it ("a draft you have noted but not yet committed is 'held, awaiting your commit' — never 'saved' or 'in the record'") — but only on the server-composed bypass path, which does not load the persona. The conversational path never received the mapping.
D1 — Persona gains a state-to-word fidelity mapping. The NEVER list's ban stays exactly as-is (plain-terms preserved). A new instruction binds the already-approved plain words to states: a state the Operator has not yet approved (held) is described with a waiting-word, never a saved-word; only committed work is described as saved / in the record / on the record.
D2 — No new vocabulary; no engine words on the conversational surface. The fix uses only words already in the persona's approved list (waiting, draft, saved). The conversational voice still never says "held," "committed," or "retracted."
D3 — commit_assertion.md aligned to plain-and-honest words. It currently uses literal "held"/"committed" in a dormant (server-composed) instruction. Align its wording to the same plain vocabulary so the two documents agree and a future path change cannot resurface engine words on an LLM path. (Low risk — the path is server-composed today, so this is forward-protection, not a behavior change.)
D4 — A conversational-path fidelity test guards the fix. A test asserting that a responder-path reply about a held draft carries waiting-language and does not contain "saved"/"in the record." This is the regression guard and the test acceptance item #8 of CR-2026-121 should have had. It exercises the assemble_prompt → generate_response path, distinct from CR-2026-121's commit-path tests.
The persona and template changes are grounded on exact text already in hand. The test work is not — these must be verified against the live tree before D4 is written:
S0-1 — Persona current text. Confirm companion_persona.md at src/loomworks/orchestration/prompts/companion_persona.md still matches the text this CR grounds on (the NEVER list with held, committed, retracted banned and saved, waiting prescribed). If it has moved since dd21818, surface the diff before editing.
S0-2 — Template current text. Confirm commit_assertion.md at src/loomworks/orchestration/prompts/intent_instructions/commit_assertion.md still matches (40eff76).
S0-3 — Test placement and harness. This is the real grounding need.
tests/test_cr_2026_121_commit_assertion.py per prior report)? What is the harness for asserting on a composed reply?assemble_prompt → generate_response) end-to-end, or do conversational-path tests stub the LLM call? Report how responder replies are tested today — whether the LLM is mocked, replayed, or called live.
S0-4 — Persona load points. Confirm assemble_prompt is the only loader of companion_persona.md and that no other surface composes conversational replies outside it (the scoping note identified the bypass intents; confirm the list is complete: commit_assertion, create_project, finalize_project, commit_project_draft, orient, completeness-check). If another responder entry point exists, name it.
companion_persona.md (the one substantive change)
Keep the NEVER list verbatim. Add a state-fidelity instruction. Candidate wording (exact text is a drafting decision; principle is fixed — a state the Operator has not approved is never described with a word implying they have):
> STATE FIDELITY > Be exact about what the Operator has and has not approved. A note you have taken down but the Operator has not yet okayed is waiting — "waiting for your okay," "a draft, not saved yet." Never call it "saved" or "in the record"; that would claim an approval the Operator has not given. Only once the Operator has okayed it do you say it is saved — "saved to the project," "in the record," "on the record." Work the Operator has set aside is withdrawn / "no longer current." When you are unsure whether something has been okayed, say it is waiting, not saved.
Placed immediately after the NEVER block so the binding sits with the vocabulary rule it refines.
commit_assertion.md (D3, optional-but-recommended alignment)Reword the literal "held"/"committed" in the template's prose to the plain vocabulary, preserving the exact state distinction it already draws. (The template's function — naming the held number and content before commit, naming what was committed after — is unchanged; only the surface words shift to match the persona, so the two never contradict if the path ever changes.)
Per S0-3's resolved design. Default expectation pending Step 0: assert the assembled responder prompt (for a held-draft context) contains the state-fidelity instruction and that, against a controlled/mocked completion, the forbidden saved-words do not appear for held state. Exact form set by S0-3.
companion_persona.md carries the state-fidelity mapping; the NEVER list is unchanged; no engine words added to the conversational surface.commit_assertion.md wording aligned to the plain vocabulary (D3), or D3 explicitly deferred with reason recorded.
Per-step commits, suite green at each. Stage by explicit path; never git add -A. Feature branch cr-2026-122-conversational-fidelity, --no-ff merge to main. Halt before push; explicit push authorization. Halt at S0-3 before writing the test.
DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-122 — Conversational Fidelity — v0.1 — 2026-06-25