Document: cr-create-commit-ceremony-v0_1
Version: v0.1
Date: 2026-06-29
Type: Phase change request — Operator Layer frontend (a shared component + wiring at three commit points). No engine change — /instantiate, /instantiate/challenge, and the WebAuthn primitives already exist. This is the cross-cutting commit-ceremony gap surfaced by live use of door 3.
Consumer: Claude Code (executor).
Branch base: OL main @ b107290; engine main @ 0b2c232 (engine read-only — reused, not changed).
Origin: Running door 3 live (a real PRD → extract → review → amend) landed on a "Foundation saved. Commit it with your passkey to make it official." screen with no commit affordance — a dead end. Grounding found this is not door-3-specific: the browser commit-with-passkey ceremony (/instantiate/challenge → WebAuthn assertion → /instantiate) is unbuilt for all three doors. Doors 1/2 commit via the conversation, which returns step_up_required, but ChatView handles no step_up_required action — so they dead-end too, less visibly. The engine half is built and verified to the gate; the browser ceremony half was never built.
Grounding: the door-3 "Foundation saved" end-state inspection (DocumentCreateFlow ends at amend, no /instantiate call anywhere in OL; door3.ts has no commit client; ChatView handles only exhaustion_choice_dialog, not step_up_required; getWebAuthnAssertion exists from Phase 48 sign-in) — OL b107290, engine 0b2c232.
When you finish creating an engagement — by any of the three doors — the last step is to commit it with your passkey. The engine is ready for that (it asks for the passkey tap). But the screen never actually offers the tap: door 3 ends on a sentence telling you to commit with your passkey, with no button; doors 1 and 2 end on a message the conversation can't act on. So today, no engagement can actually be finished in the browser — every door stops one step short. This builds the missing step: a shared "make it official" commit that runs the passkey ceremony (ask the engine for a challenge → tap your passkey → commit), wired into all three doors' finish points. Built once, used everywhere. No engine change — it wires up endpoints that already exist.
Through the create-stage builds, the passkey-commit was described as "the one pending real-world step — the Operator's to perform in the browser." That was true of the engine (/instantiate exists, the step-up gate fires, headless checks reached it) but it implied there was a surface to perform the commit on. There is not. No door has a commit button, a challenge call, or a WebAuthn ceremony wired. "The Operator's to perform" should have read "not yet built." This CR builds it; a manifest correction (below) fixes the record.
Why it hid: every door's build verified the commit "to the WebAuthn gate" — true, but that gate is exactly where the headless check stops and the browser ceremony begins. "To the gate" was the literal ceiling of headless verification; the unbuilt ceremony lives in the gap above it, reachable only by a real person in a browser. Live use surfaced it (the fifth exists-vs-works instance of the arc, and the one that hid inside the un-automatable human-presence step).
POST /engagements/{id}/instantiate/challenge (begins the WebAuthn step-up) + POST /engagements/{id}/instantiate (commits & activates, gated on the assertion) + /instantiate-divergent (commit despite findings). Verified to the gate in every door build.src/lib/auth/webauthn-client.ts getWebAuthnAssertion(options) → SerializedAssertion (Phase 48, built for sign-in via /auth/login/begin). The commit ceremony reuses it.DocumentCreateFlow phase === "done" is text only (<h1>Foundation saved</h1> + a <p>), no button, no handler; handleConfirm does amend then setPhase("done") and stops. door3.ts has no instantiate/challenge/commit client.converse → create_engagement_commit, which returns step_up_required; but ChatView handles exactly one request_action (exhaustion_choice_dialog) and nothing for step_up_required, so the engine's step-up renders as an inert companion message./instantiate appears nowhere in OL src/ except comments in DocumentCreateFlow.tsx and door3.ts.challenge → getWebAuthnAssertion → instantiate) is identical across doors; build it once, wire it at each door's commit point./instantiate(/challenge) and getWebAuthnAssertion. Engine read-only./instantiate-divergent path (commit despite findings) per Operator authority, or routes gaps to the conversation. Confirm the real signal shape at Step 0.getWebAuthnAssertion./instantiate) — not a general WebAuthn-step-up framework for every gated action (that generalization is named, not built).Per-step commits, suite green at each, halt-before-push. OL only.
Confirm against OL b107290 / engine 0b2c232:
step_up_required signal shape from each commit path — door 1/2's converse → create_engagement_commit (how step_up_required arrives in ConverseResponse / the action payload) and door 3's /instantiate direct call (the challenge → assertion → instantiate sequence). The shared component must hook the same ceremony from both entry points; confirm the exact signal each surfaces./instantiate/challenge request/response — what the challenge endpoint returns (the WebAuthn options getWebAuthnAssertion needs), and what /instantiate expects (the serialized assertion + any engagement id / findings-override flag).getWebAuthnAssertion's shape — the options it takes and the SerializedAssertion it returns, confirming it maps cleanly onto the challenge response + the instantiate request (it was built for /auth/login/begin — confirm the challenge response is shaped compatibly, or what adaptation is needed)./instantiate-divergent is the Operator-authority "commit anyway" path.Report findings — especially 2 (the two entry-point signals) and 4 (the helper's fit) — then build.
A component that runs: request /instantiate/challenge → getWebAuthnAssertion(options) → POST /instantiate with the assertion → on success, the engagement is active (navigate to it / confirm). Loading + error states (a failed/cancelled passkey tap returns cleanly, re-offers). The findings branch (Step-0.5) offers /instantiate-divergent per Operator authority. Presented as an actionable commit control.
Suite expectation: the component runs challenge → assertion → instantiate; success activates; a cancelled assertion re-offers; findings route correctly.
Replace DocumentCreateFlow phase === "done"'s text-only dead-end with the commit-ceremony component (after amend). "Foundation saved" becomes "Foundation saved — make it official" with the actual commit control.
Suite expectation: door 3's post-amend state presents the commit control; committing activates the engagement carrying the reviewed commitments.
Handle step_up_required in ChatView (the conversation commit path) by presenting the same commit-ceremony component (as a request_action handler alongside the existing exhaustion_choice_dialog). The conversation commit now completes instead of rendering an inert message.
Suite expectation: a door-1/2 conversation commit that returns step_up_required presents the ceremony; committing activates the engagement.
/instantiate(/challenge) and getWebAuthnAssertion reused as-is./instantiate-divergent path or routes to the conversation, not a silent failure.The v0.72 §5 item — "browser passkey-commit pending across all three doors… the Operator's to perform" — is half-wrong: it implied an affordance that was never built. A manifest note (v0.73 or a §5 amendment) should correct it: the commit ceremony was unbuilt across all three doors; this CR builds it. Recorded here so the correction isn't lost; the record should state the true claim ("not yet built") not the softer one ("pending your tap").
DUNIN7 — Done In Seven LLC — Miami, Florida Change Request — Browser commit ceremony (the passkey step-up, all three doors) — v0.1 — 2026-06-29 Live use of door 3 surfaced a dead end: "Foundation saved. Commit with your passkey." with no commit affordance. Grounding found the browser commit ceremony (/instantiate/challenge → WebAuthn assertion → /instantiate) is unbuilt for ALL THREE doors — doors 1/2 dead-end too (ChatView ignores step_up_required). The engine half is built and verified to the gate; the browser half never was — it hid in the gap the headless checks structurally couldn't reach (the human-presence tap). Fix: one shared commit-ceremony component reusing the existing getWebAuthnAssertion helper + the existing /instantiate(/challenge) endpoints, wired at all three doors' commit points. No engine change. Acceptance is a real passkey tap completing a real engagement in the browser, per door. Corrects the v0.72 §5 "pending your tap" claim to "was unbuilt." Base OL b107290, engine 0b2c232.