Skip to content

CONTRACT: add scoped voice refusals and confirmed permission receipts - #2145

Merged
schlessera merged 3 commits into
mainfrom
feat/114-voice-refusal-42413928
Oct 17, 2026
Merged

schlessera merged 3 commits into
mainfrom
feat/114-voice-refusal-42413928

Conversation

@schlessera

@schlessera schlessera commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Refs #114

What changed

Live conversation can refuse pending ordinary-turn approvals through the existing scoped voice-denial channel while backend work, chat progress and other interactive cards keep running. The card locks only the refused requests and waits for the host's actual outcome, including a winning visual grant, expiry without tool_result, and reconnect uncertainty. Posture-denied actions get one host outcome and no grant card.

Why this shape

Implements the approved #114 permission design on the #960 conversation client. The approved fallback is an earcon plus visual card/strip because neither selected service has a proven deterministic exact-copy permission speech path. Permission copy never becomes model commentary or standalone TTS. Original attributed user input takes precedence over question/message binding; assistant and unknown-origin input cannot invoke refusal. Built-in attribution remains unqualified, and no spoken grant exists.

Proof

  • bun run check:pr --base feat/960-voice-ui-42413928: 638 tests / 3806 assertions passed against the committed layer, including current API reports, citations, lint, leakage and contribution changeset checks.
  • Full build and strict types passed. A named minor changeset covers ui-sdk, ui-react and ui-server; the normative wire document accompanies the CONTRACT: behavior commit.
  • Real pinned offline Chromium: 39 scenarios passed. The two new refusal/snapshot assertions first failed with zero denial frames on the old UI, then passed. Tests include real PCM earcons/capture, refusal during a cue, payload-free visual copy, duplicate suppression, original-input attribution, multi-request snapshots, later/background isolation, affirmative rejection, terminal expiry, screen races, reconnect receipts and continued ordinary chat interaction.
  • Removing original-user attribution failed the named no-acoustic-decision assertion; removing scope filtering denied three requests rather than the intended two; removing once-only cue tracking created two native audio sources instead of one; treating dispatch as confirmation made the card denied before the host. Each failed at its intended behavioral assertion, then all 39 scenarios passed after restoration.
  • Real host/SDK tests: 87 tests / 259 assertions passed. With an explicitly authorized fake principal, the posture-outcome regression first failed with zero host resolutions, then passed with exactly one and no pending grant card.
  • Both 320px themes retain at least 264px of transcript, 44px targets and no strip overflow with simultaneous review/refusal; screenshots reviewed. Only the controls' eight pixels of empty vertical space give way in that tight case.
  • Current integrated local proof: 724 fast and 3,950 affected tests passed; actual Chrome recovery 2 tests / 16 assertions passed; 39 pinned offline conversation/permission scenarios passed. Both permission commits range-diff unchanged after the server rebase onto merged UI squash 85873db77bf09143c51818255d2d4733a8eb1f67.
  • Final proof-binding correction passed 950 fast and 162 affected incremental checks, with an intended failing/restored source-drift mutation; receipt.
  • Selected hosted candidate proof 39038370902 passed on head d06e8d1f4c8334b45293ace35c7c607419122dff after the UI merge. Native upper-layer candidate identity is tracked in ci: native stacked PR events do not match contract and candidate identity guards #2141; no aggregate bypass, unrelated-main refresh or older-green substitution is claimed.

Checklist

  • Complete selected hosted candidate proof passed: run 39038370902, all 14 product jobs and aggregate; 14,478 unit tests and all 39 conversation/permission browser cases.
  • Independent implementation and offline runtime/mutation proof are complete.
  • The explicitly reserved maintainer listening pass is complete.
  • PR and advanced issue ui-react: speak the approval announcement and accept a scoped spoken refusal #114 milestones read back as 0.44.0; repeat immediately before merge.
  • A named minor changeset is included.
  • Leakage and contribution guards passed.
  • Normative contract docs, behavior and moved citations accompany this change.

Anything left open

Keep #114 open. The approved real-device listening pass is reserved for the maintainer, on speaker and headphones, with the configured Gemini/GPT-Live services. Verify the earcon/visual fallback, continued chat controls and host outcome; record whether original-user attribution actually permits scoped refusal and whether output leaks into recognition. Both built-ins currently report unknown acoustic origin, which cannot authorize a denial. Qualification may therefore remain unproven; do not promote capabilities to make the check pass. Record a bounded sanitized result under #114/#961, with no credentials or deployment details. No paid/live call or device-quality claim was made here. #961 owns the broader measured qualification and activation gate. Native CI identity policy/integration remains #2141.

Maintainer ruling — 2026-10-17: The known ActionCard intermediate-opacity and final-disappearance timing findings in #1946 remain under evidence collection and are non-blocking for other issues. Matching failures must retain their actual failed identities and explicit attribution; this is accepted animation risk, not a repair or a green CI claim. Other proof and merge requirements remain applicable.

The retained ActionCard 713.9 ms final-disappearance failure does not block this voice-permission work. Adapter/client integration, current candidate qualification, native CI identity support and the explicitly reserved real-device/listening requirements retain their independent scope. No live provider qualification or completion is inferred.

@schlessera
schlessera added this pull request to stack #2135 October 16, 2026 13:13
@schlessera schlessera added this to the 0.44.0 milestone Oct 16, 2026
@schlessera schlessera added contract Touches the integration contract: CONTRACT: commit, contract doc updated in the same commit. type: feat A new capability or a change in user-visible behaviour. area: ui-react React chat/files/voice components, stores, WebSocket transport. security Auth, isolation, egress, secrets, or anything in the threat model. labels Oct 16, 2026
@schlessera
schlessera marked this pull request as ready for review October 16, 2026 13:14
@schlessera
schlessera marked this pull request as draft October 16, 2026 16:44
@schlessera
schlessera force-pushed the feat/114-voice-refusal-42413928 branch from 8c59ad4 to fc033a7 Compare October 16, 2026 16:51
@schlessera

Copy link
Copy Markdown
Owner Author

Current draft PR #2145 head fc033a77e28487d92a41b9274266219178fdc49b targets UI parent 2ded64053f2ba6d952567d5defde82cf5b9886ff in native stack #2135. It contains the permission implementation and an additional recovery correction. The rebase preserves main-model/title-usage accounting alongside the scoped voice-posture outcome handler. All moved source citations are anchored; milestone remains 0.44.0.

The earlier confirmation 38906390560 exposed a real regression: applying a voice receipt changed transcript tool status before ordinary result/recovery routing could recognize the pending restored card. This hid terminal closure and cross-page answer evidence. Receipt phases now lock decisions through awaitsDecision, while ordinary host results retain ownership of transcript status. The existing restored-store tests fail on the intended ended assertions before this change and pass after it. The visual-grant race still verifies the confirmed grant receipt, visible wording and disappearance of approval controls.

Current candidate evidence:

  • Focused host/SDK/restoration tests: 106 passed / 326 assertions, including the posture outcome and restored-card lifecycle.
  • Pinned offline Chromium conversation scenarios: all 39 pass on the rebased source with rebuilt SDK/client browser inputs; this includes continuing chat progress/cards, permission races, scope/epoch/capture guards and phone/desktop layout checks.
  • The original real-browser approval recovery test now passes both scenarios / 16 assertions: reload recovery and a second page answering while the first becomes read-only with the correct receipt. Its setup successfully completed the full current package build; the test took 136.58 seconds including setup.
  • Strict types and lint pass. An earlier simultaneous lint walk raced a temporary host-test fixture's deletion; the subsequent isolated scan is clean.
  • check:pr --base feat/960-voice-ui-42413928 completed all initial gates and 699 focused tests / 4,420 assertions. Its separate import-graph feedback was deliberately interrupted after those passes while waiting for workspace access; the entire preflight is not claimed green. The earlier browser setup timeout and stale build import failure remain setup failures, not behavioral mutation receipts; rebuilt inputs and the direct native test provide the passing evidence above.

The fixes and tests are pushed. GPT's next dependency-order confirmation 38933150766 is still waiting for a hosted runner; upper native aggregate support remains #2141. Keep this PR draft until lower layers land and its resulting current candidate can receive complete hosted confirmation. The earlier failed hosted run is not a passing receipt, and the local checks do not replace its selected categories.

This remains Refs #114. The maintainer-reserved listening check remains open under #961, alongside provider access and an explicit numerical spend limit before any paid measurement. No live provider or device qualification was performed.

@schlessera

Copy link
Copy Markdown
Owner Author

Current voice-stack delivery recheck, 2026-10-17: the frozen heads are GPT #2070 1a6cb2cefa0326f4e65421898e94fc3c4eb02122, UI #2142 7b87dff3113ae807b5a36f169d1aab2e2c784147, permission #2145 4c2dca7e4b79023fb236d3a94b75aa825e15f671 in native stack #2135. Gemini #2063 is already merged.

The current actual native merge chain again uses synthetic predecessors:

  • GPT checkout e3da8cef9ce9a4f4cbdd713bbd85aceadee792fa: parents fixed trunk 8c4d191e761bec31f3267d3b612a77712692f54a / frozen GPT head, tree 0c5ecb958f1a4f0a9c0352fe70208d581ca9bcb4.
  • UI checkout b10efee5ba865e89cbd6cce2759c1deaf5bb3450: parents GPT synthetic checkout / frozen UI head, tree f408f9e06ebbf0048b3ae2baae6ed95ce9a7aea9. Its declared live parent is the GPT branch head, not that synthetic commit.
  • Permission checkout c7dac5c8e0dc7bfa832ff6abe57f1032204cd22c: parents UI synthetic checkout / frozen permission head, tree 8d13f1dca53d69003ce776a6b7f34d672995a9be. Its declared live parent is the UI branch head.

Immutable GitHub commit responses confirm all three identities. UI metadata job 117369693498 in draft run 39023456026 actually checks out the UI synthetic commit and records that tree/parent pair. This is metadata evidence, not full qualification. The unchanged exact-own-parent validator on the product branches cannot admit the two upper shapes.

Queued upper confirmation runs 39023921626 and 39023923038 were deliberately cancelled before selected expensive jobs, and both upper PRs returned to draft. These are not passing receipts. The valid bottom-layer request 39023395726 remains active for ordinary dependency-order delivery. No #2141 implementation, native-policy waiver, guard weakening or duplicate fix is introduced here.

Both upper layers pass 723 focused checks; the combined current source passes strict types, 39 pinned conversation browser scenarios and both native approval recovery cases (full package build in setup, 172.87 seconds total). Their supplemental import-graph runs encountered the existing 180-second build-hook timeout and were stopped after retaining the failed receipts; entire preflights are not claimed green. Keep complete hosted qualification as the remaining delivery bar.

@schlessera

Copy link
Copy Markdown
Owner Author

The current prepared stack is pushed; this layer remains draft, milestone 0.44.0. All feature commits compare unchanged by range-diff. Full source identities, historical CI and current blockers are recorded in the latest #2070 handoff.

Current top head cb250a48417c776b2679cf04156d6dd5917e956a passes a separate full build and all 39 pinned Chromium conversation/permission cases (29.54 seconds). Both async adapters pass 42 loopback cases at the matching current GPT layer. The current recovery setup separately fails its unchanged 180-second package-build hook; phase evidence is on #1600. Its earlier two passing recovery cases are historical, not a current-head result. No assertion, timeout or offline guard changed.

Delivery awaits the focused diagram source-binding repair #2322 / #2314, whose required preflight is blocked by #2153, then current selected hosted proof and dependency-order native merges. The latest draft gates pass but do not substitute for full product qualification. #114 retains its reserved human verification and stays open under Refs.

@schlessera
schlessera force-pushed the feat/114-voice-refusal-42413928 branch from cb250a4 to 97ab5ad Compare October 17, 2026 12:28
@schlessera

Copy link
Copy Markdown
Owner Author

Delivery resumed after #2326 landed the diagram binding repair. Current pushed heads: #2070 3dc08df98e155d08b9feda38ceb05ce68e82415f, #2142 3eae038d092c7ea8f498f5b02e0c164bedb385cd, #2145 97ab5adaf5a5956179f0ba846615daa3a3be69b6, base 7cc86931e763f0eca636b89abd78b3b5371ec027. GPT and permission feature commits compare unchanged; the UI range-diff differs only in an upstream backend citation offset, verified against the source.

Current focused adapters/binding proof passes 52 cases / 172 assertions; the named restart case also passes. GPT complete local preflight passes 542 invariant tests plus 25 affected feedback tests. Top-layer actual Chrome recovery passes both cases / 16 assertions (163.71 seconds), and all 39 pinned Chromium conversation cases pass (28.93 seconds). Delivered forward-closure builds complete under the unchanged setup budget; no guard or timeout change is included here. Upper-layer local preflights remain in progress, with UI fast invariants already passing 724 cases.

GPT is ready and confirmation 39032664018 is running all fourteen selected product categories. Contract and metadata pass. Actual checkout f9889eb78e00c38f1f94b2013242176d079adb72 has parents recorded base/current GPT head, tree 040dcebe25ead4aecb7cc22f32a99e3119185e7a; immutable API and fetched Git object agree. This identifies its candidate, not a completed whole-run result. Upper layers remain draft for dependency-order delivery. The obsolete #2314 blocker has been removed from #959.

@schlessera
schlessera force-pushed the feat/114-voice-refusal-42413928 branch from 97ab5ad to 6dc23cf Compare October 17, 2026 12:56
Base automatically changed from feat/960-voice-ui-42413928 to main October 17, 2026 13:47
Keep host transcript status separate from permission receipt phases. Voice phases still lock their controls through awaitsDecision, while restored cards remain visible to the existing result and cross-page recovery paths. Two existing recovery assertions fail before this change; all 19 tests and 67 assertions pass after it. Update the moved source citations.
@schlessera
schlessera force-pushed the feat/114-voice-refusal-42413928 branch from 6dc23cf to 168c31a Compare October 17, 2026 13:47
@schlessera
schlessera marked this pull request as ready for review October 17, 2026 13:47
@schlessera
schlessera marked this pull request as draft October 17, 2026 13:49
@schlessera
schlessera marked this pull request as ready for review October 17, 2026 13:52
@schlessera

Copy link
Copy Markdown
Owner Author

Final permission head: d06e8d1f4c8334b45293ace35c7c607419122dff, on merged UI squash 85873db77bf09143c51818255d2d4733a8eb1f67. Both permission behavior commits range-diff unchanged through the server rebase.

A focused source-dispatch check caught the remaining reviewed-source pin omission in this layer before merge: the comment-only update in hooks/websocket-handlers/connection.ts changed its audited bytes. Audited all ten declared sources; only this pin mismatched. Reviewed its complete delta: no registry ownership, handler shape, imports or call-site change. Updated its hash and extended the existing source-drift regression to cover that handler. There is no product behavior change in this corrective commit.

Failing-first receipt: the two normal binding assertions failed on the old pin. Corrected focused checks passed 41 tests / 249 assertions. Disabling hash enforcement made the named registry/source-drift test fail with expected false versus received true; restored the guard. Incremental check:pr against the inspected pre-correction head then passed 950 fast tests and 162 affected tests. Earlier integrated behavior proof remains 724 fast + 3,950 affected tests, actual Chrome approval recovery 2 tests / 16 assertions, and 39 real pinned offline conversation/permission scenarios.

The first hosted ready run 39038009173 was cancelled deliberately when this omission was found; it is not a successful proof receipt. The corrected head is ready for fresh selected hosted proof. Keep #114 open for the reserved listening requirement; no paid/live provider or device qualification is claimed.

@schlessera

Copy link
Copy Markdown
Owner Author

Final selected confirmation run 39038370902 passed, including all 14 product jobs, metadata and final aggregate. Separate contract run 39038368893 passed. Superseded draft/previous candidate cancellations are not used as proof.

Inspected head d06e8d1f4c8334b45293ace35c7c607419122dff; actual checkout e3171b6d7e149ec9d67eaaee03c6fefb578c4846, tree 56ba27792b64c808b81df0412b4b49344bb7a96a, parents 85873db77bf09143c51818255d2d4733a8eb1f67 and the inspected head. All 15 selected job checkout logs agree. Four unit checkout/resource/summary artifacts and all eight private worker checkouts agree, with distinct dependency inodes within each pair.

Unit shards: 3,810 + 3,570 + 3,487 + 3,611 = 14,478 passing tests, zero failed/todo cases. The 28 expected skips comprise 24 opt-in paid image tests and four inactive sqlite-unavailable placeholder tests; their corresponding actual sqlite cases ran. All 39 conversation/permission browser scenarios executed successfully in the pinned layout job. Runtime and host-runtime, both browser/layout shards, endurance, captures, packaging and strict verification all passed.

Live main remains the tested UI base 85873db77bf09143c51818255d2d4733a8eb1f67. PR and advanced issue #114 milestones read back as 0.44.0; npm still reports 0.43.1. No pending review or branch-rule override. Proceed through the normal native stack merge and verify the actual squash tree and ancestry afterward.

This is Refs #114: its reserved real-device listening remains open, alongside #961's protected access/numerical-budget and automated real-audio qualification. No paid/live call, original-user acoustic attribution or device capability is inferred.

@schlessera
schlessera merged commit 9423920 into main Oct 17, 2026
19 of 30 checks passed
@schlessera

Copy link
Copy Markdown
Owner Author

Merged #2145 as 9423920fcd696c57156a20424789e871066c21f4. Verified on remote main: parent 85873db77bf09143c51818255d2d4733a8eb1f67, tree 56ba27792b64c808b81df0412b4b49344bb7a96a, exactly equal to the fully passing tested tree. PR and advanced issue #114 milestones read back as 0.44.0; #114 remains open under Refs for the reserved listening requirement. All four voice implementation layers are now delivered. The post-merge automatic run is separate from the successful pre-merge confirmation; no later run result is inferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ui-react React chat/files/voice components, stores, WebSocket transport. contract Touches the integration contract: CONTRACT: commit, contract doc updated in the same commit. security Auth, isolation, egress, secrets, or anything in the threat model. type: feat A new capability or a change in user-visible behaviour.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant