Add capability-grant primitive (unsolicited push-grant counterpart to capability-request) - #122
Merged
Merged
Conversation
Adds the generic unsolicited push-grant counterpart to capability-request: an outer verb naming the target capability, and params carrying only the pre-minted granted-token, with no scope or invitee field since manage-request-frame's own top-level scope and destination already carry both facts. Regenerates protocol.cddl and protocol.ts's zod schemas from the new rule. Also exports tokens.ts's scopeNarrows so capability-grant's own verifier can check a pushed token's scope against the enclosing request's scope using the identical narrowing relation delegation chains already use, rather than a second implementation of the same rule.
Implements the unsolicited push-grant counterpart to capability-request.ts: sendCapabilityGrant pushes an already-minted token to a peer, and createCapabilityGrantHandler verifies an incoming push against all four capability-grant obligations (bearer names the recipient itself, capability matches the outer verb, the token independently passes ordinary verification, and its scope equals-or-roots the enclosing request's own scope) before notifying the domain -- there is no decide()/timeout mechanism since the wire primitive carries no protocol-level approval round trip. Registers the new module as its own tsdown build entry and package export subpath, matching capability-request.ts's own precedent.
Adds mintRoomInviteGrant (a room-specific specialization of mintCapabilityToken, needed on the inviter's own side since a push grant has nothing to send until the token exists) and sendRoomInvite (a thin wrapper over capability-grant.ts's own sendCapabilityGrant), mirroring requestToJoin's own wrapper over requestCapability on the pull side. Wires createRoomRouter's dispatch loop to route an incoming capability.grant under room:member to createCapabilityGrantHandler, surfacing a verified invite through a new onRoomInvite handler slot on RoomRouterHandlers -- wire-mesh's own reference client had no room.invite implementation at all until now, only room.join.
…ment The router's module doc comment described only room.send/room.join dispatch, leaving the just-added room.invite routing unmentioned.
Mearman
marked this pull request as ready for review
September 14, 2026 10:59
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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.
Adds the generic, capability-agnostic capability-grant wire primitive: an unsolicited push counterpart to capability-request, generalizing core/room's own room.invite shape (owner mints a token unprompted, delivers it in the request itself) the same way capability-request already generalized room.join's pull half.
CDDL adds
capability-grantto management.cddl alongside capability-request. The TypeScript domain module (capability-grant.ts) providessendCapabilityGrant/buildCapabilityGrantCommandon the pushing side andcreateCapabilityGrantHandleron the receiving side, checking all four wire obligations before notifying the domain: the token's bearer names the receiver itself (never a relay-asserted hint), its capability claim matches the outer verb, it independently passes every ordinary token-verification obligation, and its scope equals-or-roots the enclosing request's own scope. There is no protocol-level approval round trip -- a receiver's manage-response reports validation success or failure only, never a human decision, matching room.invite's existing design.web-console's room-client.ts wires this up as core/room's reference specialization:
mintRoomInviteGrantmints a room:member token for an invitee,sendRoomInvitepushes it, andcreateRoomRouternow dispatches an incoming room.invite to a newonRoomInvitehandler slot after verification. wire-mesh itself had no room.invite implementation at all before this (only room.join) -- agent-comms is the only prior consumer, and its own equivalent handler is what confirmed the bearer-must-equal-the-recipient's-own-identity obligation this PR's verifier implements.No Rust changes: confirmed via
cargo test -p wire-mesh-wirethat, like every other management verb, capability-grant rides manage-request-frame's untyped params/response catch-all with no new typed struct needed.Closes #117
Part of #83