Skip to content

Add capability-grant primitive (unsolicited push-grant counterpart to capability-request) - #122

Merged
Mearman merged 4 commits into
mainfrom
feat/capability-grant-primitive
Sep 14, 2026
Merged

Mearman merged 4 commits into
mainfrom
feat/capability-grant-primitive

Conversation

@Mearman

@Mearman Mearman commented Sep 14, 2026

Copy link
Copy Markdown
Member

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-grant to management.cddl alongside capability-request. The TypeScript domain module (capability-grant.ts) provides sendCapabilityGrant/buildCapabilityGrantCommand on the pushing side and createCapabilityGrantHandler on 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: mintRoomInviteGrant mints a room:member token for an invitee, sendRoomInvite pushes it, and createRoomRouter now dispatches an incoming room.invite to a new onRoomInvite handler 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-wire that, 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

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
Mearman marked this pull request as ready for review September 14, 2026 10:59
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-14T11:10:29.312889Z c8dcf25 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Mearman
Mearman merged commit a69afab into main Sep 14, 2026
8 checks passed
@Mearman
Mearman deleted the feat/capability-grant-primitive branch September 14, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add capability-grant primitive (unsolicited push-grant counterpart to capability-request)

1 participant