Section H of the elicitation instrument already asks who produces the first version, when words stop being enough, and what should arrive rough. It shipped on 6 September 2026, along with the contract field, the draft mapping, the prompt injection and the render. This plan does not re-add any of it.
What is missing is any signal that it exists. The Advisory Contract governing every AI surface today is the one approved on 22 July — before section H, and before the mapping fix meant to carry the re-igniter answer to Mira. A builder fix is inert until a draft is rebuilt, and nothing says so.
The problem
The requested work is built
Every question in the note maps to a shipped question, near-verbatim:
h1 who produces the first version and whether that changes by stage;
h2 when words stop being enough and what has to be seen or played with;
h3 what arrives finished versus rough. AdvisoryContract.collaborationProtocol
holds them, ContractDraftBuilder quotes them verbatim,
DossierContextBuilder.compactContext() injects them ahead of the prohibitions, and the
Dossier renders them as a card. The prior plan is
.claude/plans/dossier-collaboration-protocol.md, implementation complete, manual testing
entirely unchecked.
What the stored data says
Read out of dossier.json, last written 24 July 2026:
31 answers stored, ids a1–g2. g3, h1, h2 and
h3 are all unanswered. The live contract was approved 2026-07-22 and has
no collaborationProtocol key at all. The b4 re-igniter line is not in
objectiveFunction — the mapping fix landed 6 September, but a mapping only takes
effect when a draft is rebuilt, and no rebuild has happened. Your suspicion in the note is right at the
data level even though the code was corrected: it still has not reached Mira.
Two answers still fall on the floor
ContractDraftBuilder's header promises that "everything else in the instrument
reaches a field." That is false for two ids, neither listed as deliberately unmapped.
g3 — "Is there anything about how you work that every AI keeps
getting wrong?" — is the catch-all your note names as the question that was supposed to catch all
of this. It is unmapped. Had it been answered in July, the answer would have gone nowhere.
a1 — the count of live endeavors and whether it is deliberate — is not
merely recall. Whether six concurrent projects are a choice or a drift governs whether launch-risk
advice may suggest consolidation, the most-guarded territory in the contract.
Approach
Rebuild-and-diff rather than version counters
Half the detector exists: DossierStore.openQuestionIds already computes unanswered and
unsure-skipped questions, and is referenced by no view in the project. Rendering it is the cheap half.
The expensive half is the b4 case, where the question is answered and the
mapping changed underneath it. A stored instrument version and a builder-revision int would work and
would drift. Asking buildDraft(from:existing:) what it would add is a pure
function of current code plus stored answers, with no bookkeeping to keep in sync — and it reuses the
same signature comparison, so detection and assembly cannot disagree.
A coverage test, not a comment
The deliberately-unmapped list is prose in a header comment, which is exactly how a1 and
g3 slipped out of it. Making it a Set<String> and asserting round-trip
coverage from synthetic answers turns the promise into something that fails a build when it stops being
true.
Decisions made for you
This plan is smaller than what was asked for
The note asks for three questions to be added. They exist. Writing them again would create a second plan for work already checked off, so this plan fixes the reason you could not tell. Reversible by saying so — if the shipped wording is wrong, rewording is a different and much smaller task.
g3 routed to the collaboration protocol
"What every AI keeps getting wrong" is explicitly about how you work, which puts it beside h1–h3 rather than in the framing rules. It could equally be about delivery, in which case it lands oddly. Cheaper than a field of its own, and visible on the review screen where you can move the text before approving.
Staleness stays in-view and does not reach the Workbench
A background-activity row would catch you without opening the profile. It would also re-raise itself,
which is the framing-rule violation the drift-alert design already forbids. Chose the quiet failure over
the noisy one. Reversible with one WorkbenchStore.register call.
The work
Phase 1 — Close the last two silent drops
9 tasks · done Lands independently; nothing else depends on it.- Map
g3intocollaborationProtocolinContractDraftBuilder, quoted verbatim under the label "What AI tools keep getting wrong about how I work" - Map
a1intoobjectiveFunctionas a concurrency stance line combining the count and the deliberate/accident/managing select, so advice knows whether the portfolio shape is a choice - Correct
ContractDraftBuilder's header comment — its deliberately-unmapped list currently omits both ids while the prose claims full coverage - Add a
deliberatelyUnmapped: Set<String>constant onContractDraftBuilderso the list is code rather than a comment that can go stale - Add a sentinel round-trip coverage test: build a draft from synthetic answers carrying a unique marker per question, assert every marker reaches the contract unless its id is in
deliberatelyUnmapped - Handle the formats whose
textthe builder never reads (.rank,.allocate,.countThenSelect) in that test with a format-appropriate payload marker rather than exempting them - Run the coverage test through the standalone swiftc harness in the scratchpad, not
xcodebuild test - Install the harness at
scripts/harnesses/contract-coverage/with ascripts/verify-contract-coverage.shrunner, matching the instruction-manager harness convention - Fix
ContractElicitationViewrendering an empty review step: with every question answered the view opens atquestions.count, anddraftwas only ever assigned byonChange(of: questionIndex), which never fires
Phase 2 — Make contract staleness visible
8 tasks · done The systemic fix. Half of it is already written and unrendered.- Add
ContractDraftBuilder.pendingAdditions(from:existing:) -> [String], returning the lines a merge would add to the stored contract, reusing the existingsignature/mergeTextcomparison so detection and assembly cannot disagree - Add a
contractStalenesscomputed property toDossierStorereturning the open question ids and the pending additions - Render a staleness advisory in
DeveloperDossierView's Advisory Contract card when either list is non-empty, above the contract fields - State both facts plainly and separately — how many questions are unanswered, and how many stored answers are not yet reflected in the approved contract
- Change the "Revisit the interview" button label to name the work when staleness exists (e.g. "Answer 4 open questions")
- Keep delivery deterministic and templated — no AI call on this path, per the Dossier's drift-alert invariant
- Keep it in-view only: do not register it with
WorkbenchStoreand do not raise a notification, so it cannot become a recurring nag - Confirm the advisory reads as neutral information rather than a prompt to catch up, against the contract's own framing rules
Phase 3 — Optional: structure the see-versus-play priority
3 tasks Recommended skip.h2 prose already carries the ordering.
- Only if wanted: add
h4with a.rankformat over user-agnostic forms — a picture or mockup, something clickable, a working slice, more wordsoptional - Only if wanted: word it so "more words" ranking first is an equally natural answer, per the instrument's fairness ruleoptional
- Only if wanted: map
h4intocollaborationProtocolbeneath theh2line and bumpinstrumentVersionto 1.6optional
Phase 4 — Export propagation (follow-up from the first checkin)
3 tasks · done Raised as an out-of-scope concern on the 21:49 checkin, then investigated.- Confirm whether a contract rebuild marks stored projection records stale —
currentContentHash()hashesfullMarkdown(), which carries both the objective function and the collaboration protocol, so the rows already self-report and offer "Regenerate & Copy" - Call
DossierClaudeCodeSync.writeIfEnabled()andDossierSharedExport.writeIfEnabled()fromDossierStore.approveContract(), since both were reachable only from the Generate & Copy button in Exports - Survey the other deterministic builders for the same silent-drop shape and decide whether the coverage harness generalizes — it does not;
ContractDraftBuilderis the only service that reads stored answers by hardcoded id
Verification
4 tasks · done Compile check only — runtime behavior is yours to confirm.- Build with
xcodebuild -scheme "Code Raven" -destination 'platform=macOS' build - Confirm the product actually relinked with
scripts/verify-build-product.sh - Confirm the coverage test fails when a mapping is deliberately removed, so the guard is real rather than vacuous
- Confirm no existing stored answer or contract fails to decode after the changes
Manual Testing
10 tasks · yours This is the section that actually repairs Mira. No code change substitutes for it.- Relaunch the app — the running build predates these changes, so nothing below is visible until you doSarah
- Open the Developer Profile and confirm the Advisory Contract card names 2 stored answers not yet reflected, listing the concurrency and
g3linesSarah - Press "Rebuild the contract" and confirm the review step renders rather than opening blankSarah
- At the review step, confirm your existing contract text survives verbatim in every field you hand-editedSarah
- Confirm the rebuilt draft adds the concurrency line to the Objective Function and the
g3line to the Collaboration Protocol — theb4,b1andd5lines already landed on 20 SeptemberSarah - Approve the revised contract and confirm the Collaboration Protocol card appears in the DossierSarah
- Confirm the staleness advisory disappears once approvedSarah
- Ask Mira something design-shaped and confirm she produces the first version without being asked toSarah
- Ask Mira for something at the point where words stop being enough, and confirm she reaches for a visual before proseSarah
- Run an expert meeting and confirm Mira's opening reflects the protocol rather than handing you a blank fieldSarah
Risks & edge cases
This plan cannot fix the thing you actually noticed
Mira ignored your collaboration dynamic because the contract governing her prompts has no collaboration protocol in it, and no code change puts your words there. Only the Manual Testing section does. Phases 1 and 2 reduce the chance of a repeat; the repair itself is four answers and an approval.
The staleness advisory is a nag surface by construction
It appears every time the Advisory Contract card renders until the contract is re-approved. Correct
for a two-item list that resolves in five minutes; wrong if the open list is ever long and you have
decided not to answer it. If that happens the answer is a notApplicable skip, which
openQuestionIds already excludes — no code change needed.
Malcolm's seed predates section H
.claude/dossier-seeds/malcolm-elicitation-2026-07-20.md has no h1–h3, so his profile will
show four open questions the first time it renders. Correct behavior, and worth knowing before it looks
like a bug on the second install.
The coverage test is only as honest as its markers
A question whose answer is folded into a derived phrase rather than quoted could pass the marker check while still losing your words. The test proves an answer reached a field; it does not prove it arrived intact.
Rebuild-and-diff runs on every appearance of the profile view
Deterministic string work over ~31 answers, so trivial today. If the instrument grows enough for that
to matter it wants caching on dossier.updatedAt, not a version counter.
Out of scope
Re-adding the section H questions — they exist, which is the point of this plan.
Re-running the full elicitation for anyone.
Inferring the collaboration protocol from session history rather than asking.
Any rewording of existing questions a1–g3.
VentureRaven's read side of the shared export, still unbuilt.
Testing how the protocol reads at the far end of injection, which remains the untested link in the whole chain.
Final review
What this does well
It refuses to build what already exists, and it names the actual failure: a contract stale for two
months with no surface saying so. The two unmapped ids were found by checking every question id against
the builder rather than trusting its header comment, and g3 being unmapped is a sharp
finding given your note calls that question the catch-all that should have caught this. The
rebuild-and-diff detector has no version bookkeeping to drift, and half of it is already written.
Where it is weakest
The g3 field routing is a guess. The coverage test proves arrival, not fidelity. And
Phase 2 surfaces staleness only on a view you have to visit — if you do not open the Developer Profile,
the contract stays stale and silent exactly as it did since July. A workbench row would fix that and
would violate the re-nag rule; I chose the quiet failure over the noisy one, and that choice is
arguable.
What I would adjust if pushed
Drop Phase 1's a1 mapping. It is the one change that puts new interpretive material — a
stance about your portfolio shape — into the contract on my reading rather than yours, and the
concurrency count is already visible to the portfolio synthesizers. Keeping it because launch-risk
advice currently has no way to know the shape is deliberate, which is the exact territory the candor
invariant guards.
The findings are read out of code and your stored data rather than inferred: the shipped section H, the July contract with no protocol key, the missing b4 line, the two unmapped ids, the unrendered openQuestionIds. Lower than the prior plan's 88 because the deliverable is smaller than the request, and because the part that actually repairs Mira's behavior is four answers only you can write.