feat: dig-node chat subsystem — chat message types + chat.* RPC over dig-message/dig-gossip - #133
Merged
Merged
Conversation
MichaelTaylor3d
marked this pull request as ready for review
August 2, 2026 05:43
MichaelTaylor3d
force-pushed
the
feat/chat-subsystem
branch
from
August 2, 2026 05:56
4d25dc8 to
6cdda1c
Compare
Salvage anchor for Lane B of the dig-chat epic (#768): the dig-node chat subsystem — chat message-type crate (band 0x0200 on dig-message) + chat.* RPC + dig-gossip transport wiring. Implementation follows on this branch. Refs #793, #768, #781 Co-Authored-By: Claude <noreply@anthropic.com>
Add the transport half of dig-chat (epic #793, Lane B): the node seals an app-supplied opaque DIGCHAT1 envelope into a dig-message envelope to the recipient's 0x0010 BLS identity key and dig-gossip directed-sends it (opcode 220), and surfaces inbound decoded ChatMessages via a poll RPC. - Add `dig-chat-protocol` as a workspace member crate: the five chat message types on dig-message's dig-chat band (0x0200), content-blind, with KATs. - Register the chat types into a MessageRegistry and add the `chat` subsystem module: seal_outbound / open_into_inbox / process_inbound_frame + a bounded per-node inbox and a monotonic anti-replay counter. - Wire `chat.send` (seal + directed send, returns message_id) and `chat.poll` (drain inbox) into the RPC dispatch and the OpenRPC method catalogue. - Double seal upholds NC-1: neither the DIGCHAT1 body nor the plaintext message id appears in the on-wire bytes; the node never parses chat content. - Bump the workspace version to 0.62.0 (minor) and document the subsystem in SPEC.md §5.5.2. The sealing-key directory (resolveSealingKey) is deferred: the app supplies the recipient sealing key + gossip peer_id, and the inbound sender-key resolver is caller-supplied. Co-Authored-By: Claude <noreply@anthropic.com>
correlation_id is a CLEARTEXT dig-message envelope header; carrying the message_id there would expose it on the wire. Zero it for one-shot chat messages — the id travels sealed inside the ChatMessage payload. Refs #793 Co-Authored-By: Claude <noreply@anthropic.com>
The inbound handler (process_inbound_frame) is implemented + unit-tested, but the run_peer_network loop that feeds it is not yet wired, so chat.poll returns empty in the shipped build until that lands. State this explicitly so an integrator does not build against chat.poll expecting delivery. Addresses the review gate's SPEC-accuracy finding. Refs #793 Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
force-pushed
the
feat/chat-subsystem
branch
from
August 2, 2026 06:24
6cdda1c to
8c8af70
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.
What & why
Lane B of the dig-chat epic (dig_ecosystem#768 / #793) — the dig-node chat subsystem, the transport half of dig-chat. A node seals an app-supplied opaque
DIGCHAT1envelope into adig-messageenvelope to the recipient's0x0010BLS key and dig-gossip directed-sends it (opcode 220); inbound frames are opened, registry-dispatched, and surfaced via a poll RPC. Double-seal upholds NC-1 — the node never parses chat content.Delivered
crates/dig-chat-protocol(new workspace member) — the 5 chatMessageKinds ondig-messageband0x0200(ChatMessagecarrying opaque bytes + receipts/typing/presence), KATs. Sealing-key-agnostic, content-blind.crates/dig-node-core/src/chat.rs—seal_outbound/open_into_inbox/process_inbound_frame, boundedChatInbox, monotonic anti-replayChatState,MessageRegistrywiring, and thechat.send/chat.pollRPC handlers.served: "local"); workspace version0.61.0 → 0.62.0(minor); dig-node-coreSPEC.md§5.5.2.Verified (scoped — see disk note)
cargo fmt --checkclean ·cargo clippy -p dig-chat-protocol -p dig-node-core -p dig-node-service --lib -- -D warningsclean ·dig-chat-protocol13 KATs + doctest pass ·dig-node-core --lib chat6 pass incl. the NC-1 on-wire-ciphertext test (neither the DIGCHAT1 body nor the plaintext message id appears on the wire), send→receive opaque-byte round-trip, fail-closed on unresolvable sender / malformed envelope, bounded-inbox eviction, monotonic counter. TDD caught a real leak (message_id in the cleartextcorrelation_id) — fixed in448d24e.Scoped/deferred (tracked follow-ups — not blocking this foundation)
run_peer_networkdrainingGossipHandle::inbound_receiver()into the inbox) — the handler is built + unit-tested; wiring is gated on the key directory.resolveSealingKey/ DID→(sealing key, peer_id) directory — for nowchat.sendtakes app-supplied{recipient_did, recipient_pub, peer_id, envelope}.chat.send/chat.pollinto the shareddig-rpc-protocolMethodenum; receipts/typing/presence delivery; group/onion.Disk note
The full
cargo build/clippy --all-targets+ theopenrpc_drift_guardtest overflow the ~38G dev-container quota from clean — those gates run here on PR CI. Local verification was scoped to--lib+ the touched crates.Tracks dig_ecosystem#793. 🤖 Generated with Claude Code