Parent: #28
core/room's room.join/room.invite (spec/room.cddl:126-155) hand-built the ungated-request-then-human-approves-then-mint-and-return-token flow for one scope kind. This generalizes it into a domain-agnostic primitive any capability can use, adds the timeout handling neither room.join nor agent-comms' connect_request currently has, then migrates room.join/room.invite onto it rather than leaving two parallel implementations of the same idea.
Sub-issues below cover the wire addition (capability-request/capability-grant-ok), a queryable canGrant() helper pulled out of mintCapabilityToken's own narrowing check, requester- and receiver-side timeouts for any held-open manage-request, an optional valid-until field reusing the message/token-lifetime mechanism from section E, and the migration of room.join/room.invite onto the new primitive.
Extended by a further design pass into three more pieces, no longer deliberately deferred:
A request/approval round trip stays single-round-trip even for a narrowed-plus-conditioned grant: the approver mints and returns a token for whatever it's actually willing to give (narrower capability, added conditions), and the requester's own decision to use or discard that token is what stands in for "accept the counter-offer" -- no separate negotiation protocol needed on top of the existing mechanism.
PR #93 opened: the wire shape for #78 (capability-request/capability-grant-ok) is now added to core/management. Migrating room.join/room.invite onto it, and the canGrant/canSatisfy check, timeouts, and valid-until field it unblocks (#79-#83), remain open follow-up work.
Parent: #28
core/room'sroom.join/room.invite(spec/room.cddl:126-155) hand-built the ungated-request-then-human-approves-then-mint-and-return-token flow for one scope kind. This generalizes it into a domain-agnostic primitive any capability can use, adds the timeout handling neitherroom.joinnor agent-comms'connect_requestcurrently has, then migratesroom.join/room.inviteonto it rather than leaving two parallel implementations of the same idea.Sub-issues below cover the wire addition (
capability-request/capability-grant-ok), a queryablecanGrant()helper pulled out ofmintCapabilityToken's own narrowing check, requester- and receiver-side timeouts for any held-open manage-request, an optionalvalid-untilfield reusing the message/token-lifetime mechanism from section E, and the migration ofroom.join/room.inviteonto the new primitive.Extended by a further design pass into three more pieces, no longer deliberately deferred:
conditions: [* PredicateNode]list, evaluated by a single trilean-backed evaluator. This is what an approver narrowing a request beyond plain scope containment (a specific capability at a specific scope, plus an arbitrary extra condition) actually needs -- e.g. approving a narrower capability than requested with an additional condition attached, which the flat hardcoded-fields model can't express without inventing a new field every time.A request/approval round trip stays single-round-trip even for a narrowed-plus-conditioned grant: the approver mints and returns a token for whatever it's actually willing to give (narrower capability, added conditions), and the requester's own decision to use or discard that token is what stands in for "accept the counter-offer" -- no separate negotiation protocol needed on top of the existing mechanism.
PR #93 opened: the wire shape for #78 (capability-request/capability-grant-ok) is now added to core/management. Migrating room.join/room.invite onto it, and the canGrant/canSatisfy check, timeouts, and valid-until field it unblocks (#79-#83), remain open follow-up work.