Own-account subtree consent gate, deadline bound, and worker dispose fix - #469
Merged
Conversation
…t consent
A product requesting its own account takes no access review, so a cold
subtree that must be fetched from the Account Holder over SSO was resolved
with no host-visible seam. Add a ProductSubtree review so a host can show a
rejectable prompt at that moment.
UserConfirmationReview gains a ProductSubtree(ProductSubtreeReview { product_id })
variant, appended last to preserve the SCALE indices of the existing variants.
On the own-account get path, when subtree_resolution_reaches_account_holder is
true (pairing host, cold cache), the core calls confirm_user_action first:
approve proceeds to the SSO resolve, reject returns HostAccountGetError::Rejected.
A cached slot resolves locally with no prompt, and cross-product access keeps its
existing account_access_authorization gate, so neither prompts here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
disposeCore called free() in the same turn as dispose(). dispose() aborts in-flight receiveFrame dispatch, but wasm-bindgen releases the core's borrow only after the aborted promise settles a microtask later. Calling free() immediately threw "attempted to take ownership of Rust value while it was borrowed" and left the core unfreed whenever a provider was disposed mid-dispatch, which a host does on transient re-renders. Track outstanding receiveFrame promises per core, and after dispose() await them before free(). The whole-runtime dispose path awaits every core teardown before freeing the pairing runtime. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
The timeout and cancel arms of remote_authority_call awaited the parked call after cancelling it. A call parked in the statement-store setup, which does not watch the cancel token, ignored the cancel, so that await outlived the deadline and the request hung instead of failing. On cancel or timeout, race the call's unwind against a short grace, then drop it. In the normal case the call observes the cancellation and unsubscribes its statement streams within the grace; a call parked in the setup region is dropped at the grace rather than hanging. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
The workspace-wide UserConfirmationReview match in the host CLI's approval summary was left non-exhaustive by the new ProductSubtree variant. Add its arm, and apply rustfmt to the earlier commits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
TarikGul
reviewed
Aug 21, 2026
TarikGul
reviewed
Aug 21, 2026
TarikGul
reviewed
Aug 21, 2026
Member
|
Looking good, just a few comments. Feel free to ping me when its out of a draft. |
…ering The worker's dispose-must-await-in-flight-frames ordering shipped untested because the worker entry binds `self` and exports nothing. Move dispatchFrame and disposeAwaitingFrames into worker-core-registry so the ordering is a unit, and test the case TarikGul asked for: a frame in flight, a dispose mid-flight, no borrow throw, the core freed. A second test pins that free() throws while a frame is borrowed, so the first genuinely exercises the ordering. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
…gate Two review points from the PR: - The whole-runtime dispose nulled `runtime` inside the async block, leaving it non-null while cores disposed, so a message arriving mid-disposal could pass its `if (!runtime)` check. Capture the handle and null `runtime` synchronously, then free the capture after the cores finish. - `subtree_resolution_reaches_account_holder` defaulted to `false` (no prompt), a fail-open default on a consent gate that a new authority could skip by omission. Make it a required trait method; the signing host implements it explicitly, deriving locally so it never prompts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y65XQWkbMjfxG43gKvVV1b
johnthecat
marked this pull request as ready for review
August 21, 2026 13:18
johnthecat
enabled auto-merge
August 21, 2026 15:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes on the own-account / desktop-host path.
Product subtree consent gate
Reason. A product requesting its own account takes no access review, so a cold subtree fetched from the Account Holder over SSO resolved with no seam the host could see or reject.
Intent. Let the host draw a rejectable prompt at that fetch.
Fix. New
UserConfirmationReview::ProductSubtree(ProductSubtreeReview { product_id }), appended last so existing SCALE indices are untouched. On the own-account cold path the core callsconfirm_user_actionfirst: approve resolves over SSO, reject returnsHostAccountGetError::Rejected. A cached subtree resolves locally with no prompt, and cross-product access keeps its existingaccount_access_authorizationgate. Codegen and Swift bindings regenerated.Bound remote authority calls at their deadline
Reason.
remote_authority_callawaited the parked call after cancelling it. A call parked in the statement-store setup ignores the cancel token, so the await outlived the deadline and the request hung instead of failing.Intent. A deadline that actually bounds the call, while still tearing the call down cleanly.
Fix. On cancel or timeout, race the call's unwind against a short grace, then drop it. In the normal case the call observes the cancellation and unsubscribes its statement streams within the grace; a call parked in the setup region is dropped at the grace rather than hanging.
Worker dispose ordering
Reason.
disposeCorecalledfree()in the same turn asdispose().dispose()aborts the in-flightreceiveFrame, but wasm-bindgen releases the borrow a microtask later, sofree()threw "attempted to take ownership of Rust value while it was borrowed" and leaked the core on any mid-dispatch dispose.Intent. Free without the borrow throw.
Fix. Track in-flight
receiveFramepromises per core and await them afterdispose(), beforefree().