spec: add the core/room domain, unifying rooms and DMs - #47
Merged
Merged
Conversation
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. |
room-path names the device-id(s) whose signature makes a room:member
membership token valid, rooted differently by shape: an owner-named
room (<owner-hex>/<local-name>) roots trust at the owner in the path;
a DM (the sorted pair of exactly the two participants' hex device-ids)
roots trust at the verifier itself, since either named party being an
acceptable root would let a sender self-issue a token and message a
stranger unsolicited.
room.send/room.read/room.leave/room.members share one capability,
room:member, mirroring exec:pty's existing one-resource-many-verbs
pattern. room.join/room.invite are deliberately ungated -- no token
field at all -- since a room with no prior relationship has no token
to gate first contact on; approval mints a token on the spot, carried
back as an extension field on the existing manage-ok response rather
than a new frame shape.
message-ref gives room.send's optional refs array one open, typed
relation ("reply", "forward", and any future kind) instead of a
separate ad-hoc field per relation, the same "open on purpose" pattern
capability-scope.kind already uses.
1.0.1 fixes a lexer bug where a backslash-escaped character inside a CDDL text-string literal kept its backslash instead of being resolved to the literal character it escapes. Without this, core/room's own dm-room-path rule (and the already-shipped namespaced-domain-id rule) generate a Zod regex that silently matches the wrong thing.
Adds the room-path/room-send/room-read/room-leave/room-members/ message-ref/room-join/room-invite schemas and the delegations-remaining claim, generated against cddl.js 1.0.1 so dm-room-path's escaped-plus regex is correct rather than double-escaped.
Covers room.send (with a reply message-ref), room.read, room.leave, room.members under a room:member token, the ungated room.join/ room.invite pair with no token field at all, and the manage-ok grant response riding manage-ok's own extension tail. Two new token vectors exercise the delegations-remaining fix directly: an owner's root grant capped at one further re-delegation, and a delegated child narrowed to zero -- the exact chain that closes the unbounded-admission bug. All nine round-trip through both the TS conformance test and Rust's conformance-check binary with zero Rust source changes, confirming the manage-command-params Json catch-all and capability-scope's open kind field already cover a brand new domain without any typed Rust arm.
Mearman
force-pushed
the
feat/core-room-domain
branch
from
September 11, 2026 14:45
ca35fd1 to
bbe321c
Compare
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.
Closes #31.
Adds
core/room: one domain covering both named, persistent rooms and two-party DMs, gated by a singleroom:membercapability for the four ordinary participation verbs (room.send/room.read/room.leave/room.members), mirroringexec:pty's own one-resource-many-verbs shape.room.join/room.inviteare deliberately ungated -- no token field at all -- since a room with no prior relationship has nothing to gate first contact on; approval mints a token on the spot and returns it as an extension field on the existingmanage-okresponse.Membership proof is rooted in the room-path's own shape: an owner-named room (
<owner-hex>/<local-name>) roots trust at the owner named in the path, but a DM path (the sorted pair of the two participants' hex device-ids) roots trust at the verifier itself -- if either named party were an acceptable root, a sender could self-issue a token and message a stranger unsolicited.Two things found and fixed while building this, not left as known gaps:
room:membercould mint a narrower child carrying the identical verb (narrowing preserves the capability), so any member could transitively admit anyone to any depth, and kicking one member's grant would take down their entire invited subtree since only a token's own issuer may revoke it. Fixed with a new? delegations-remaining: uintclaim ontoken-claims-- absent means unbounded (every existing token keeps its current meaning), present means a child's value must be strictly less than its parent's. General, not room-specific:exec:ptyhas the identical latent bug and gets the fix for free..regexppattern needing an escaped backslash (dm-room-path's\\+, and the already-shippednamespaced-domain-id's\\.) generated a JS regex with an extra literal backslash, silently matching the wrong thing. Fixed at the source: webdriverio/cddl#91/#92 upstream, cherry-picked into ExaDev/cddl.js#11 (released as 1.0.1), bumped here.message-ref = { id: bstr, relation: tstr }givesroom.send's optionalrefsarray one open, typed relation ("reply", "forward", anything future) instead of a separate ad-hoc field per relation -- the same "open on purpose" precedentcapability-scope.kindalready set.Nine new conformance vectors (7 frame, 2 token) round-trip through both the TS conformance test and Rust's
conformance-checkbinary with zero Rust source changes -- confirmsmanage-command-params'sJsoncatch-all arm andcapability-scope's already-openkindfield genuinely cover a brand new domain with no typed Rust arm needed, not merely assumed.Test plan
just spec && just conformance-- all 9 new vectors PASS in both TS and Rustjust build && just test && just lint-- all greencargo test && cargo clippy --all-targets -- -D warnings && cargo fmt --check-- all green, zero Rust diff