Skip to content

Add binding-scoped directed TinyBus signals - #63

Merged
senamakel merged 18 commits into
mainfrom
storage-host-callback-signals-7522
Oct 12, 2026
Merged

senamakel merged 18 commits into
mainfrom
storage-host-callback-signals-7522

Conversation

@senamakel

Copy link
Copy Markdown
Member

The storage Documents watch contract needs payload-free change notifications delivered over TinyBus signals. Ordinary signals are broadcast, so a matching module could otherwise observe another module's watch activity.

This adds a separate directed_signal message kind. Only an SDK-created HostCallbackBinding can emit it; the binding derives its destination from the currently live, verified module peer. The broker checks the active binding and exact declared path, interface, and member again at routing time, then delivers to that unique recipient. Revoked bindings, undeclared members, forged sender/destination fields, and outsider peers are refused. Existing broadcast signal routing remains unchanged.

HostCallbackBinding::emit_signal and Proxy::receive_directed_signal expose the capability without exposing a raw host connection. The protocol document is now revision 2 because revision-1 readers cannot safely deserialize this message kind. The module_context native fixture subscribes and a compiled-cdylib test proves the bound module receives the signal while an outsider with the same match rule receives nothing.

Validation:

  • cargo fmt --all -- --check
  • cargo test --workspace --all-features
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • RUST_TEST_THREADS=1 scripts/test-e2e.sh (43 passed, including the compiled module signal test)

Relates to tinyhumansai/openhuman#7522.

senamakel and others added 18 commits October 12, 2026 20:55
…src/message/mod.rs

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a directed_signals match rule builder and a Proxy helper to subscribe
to recipient-directed signals, and serialize the new message kind to the
wire. Directed signals are delivered only to the unique recipient bound by
a live SDK callback, so they need their own subscription path rather than
the ordinary signal fan-out.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a HostCallbackSignal type describing a finite set of
recipient-directed signals a host callback may emit, and track declared
signals alongside endpoints in the callback state. This gives the module
a place to record which signals a callback is permitted to send.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Host callback bindings can now declare a finite set of signals and emit them
only to the binding's current verified module peer, with the destination
resolved from live binding state rather than chosen by the caller. The broker
re-checks the declaration and active binding when routing, which closes the
revoke/send race.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Directed signals are now delivered to the named destination rather than
broadcast through match rules, with the router verifying that a host
callback holds authority for the source and destination pair. The
protocol version is bumped to 2 and the CLI renders the new message
kind.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The callback eligibility check compared the source against the module and required source and destination to be equal, which rejected valid directed signals. It now verifies the destination matches the callback's own destination and the source matches the loaded module, and the protocol docs describe the directed_signal kind and its routing rules.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests asserting that directed signals reach only the live bound module and its declared member, and reject forged senders, destinations, and members. The router now validates the message kind and routing fields before matching host callbacks, so malformed directed signals fail early.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformat long expressions and assertions across the message, host
callback, and router modules to satisfy rustfmt. The host callback test
also attaches peers with their outboxes directly instead of patching the
router afterwards, and drops a stray unwrap on add_match.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests asserting that a directed signal must have exactly one unique
recipient and cannot be confidential, and that directed signal match rules
do not match broadcast signals or vice versa.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Extend the test module's imports to bring in MatchRule alongside Router so
the host callback tests can reference match rules.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add explicit type annotations to the parsed path, interface, and member
values in the host callbacks test so the parser's target types are
unambiguous.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The example service now subscribes to its own WatchChanged directed signal
and exposes a WaitForWatchChanged method that awaits the next message and
returns its body, demonstrating how a module can consume directed signals
it emits.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add an ignored integration test asserting that a loaded module receives only
the host directed signal it declared, while an unrelated connection subscribed
to the same signal gets nothing. The example and message tests were reformatted
to satisfy rustfmt.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Match rules parsed from a string now recognise "directed_signal" as a
message kind, so rules that filter on directed signals can be built from
their textual form instead of silently failing to match. The unused
module id binding in the host callbacks test was dropped alongside it.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module context example now advertises the WaitForWatchChanged member so the sample interface matches the members exercised elsewhere.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a test asserting that a rule with type=directed_signal matches a
directed signal message, and that a plain type=signal rule still matches
an ordinary signal. This pins down that the two message kinds are
distinguished during rule parsing and matching.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The protocol document now declares version 2, and the error message for a signal carrying a private body was shortened to a plainer phrasing.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test name and assertion were updated to match the current validation
error, which now reports that a signal cannot carry a private body rather
than referring to it as a broadcast.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Oct 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

This review includes 15 billable files and costs up to $3.75.

Or wait 48 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 05dac1c9-804c-4270-8422-b03c4eca426d

📥 Commits

Reviewing files that changed from the base of the PR and between e923251 and 2900abb.


📒 Files selected for processing (15)
  • crates/tinybus/examples/module_context.rs
  • crates/tinybus/src/bin/tinybus/unix.rs
  • crates/tinybus/src/broker.rs
  • crates/tinybus/src/connection.rs
  • crates/tinybus/src/lib.rs
  • crates/tinybus/src/message/mod.rs
  • crates/tinybus/src/message/mod_tests.rs
  • crates/tinybus/src/module/host_callbacks.rs
  • crates/tinybus/src/module/host_callbacks_tests.rs
  • crates/tinybus/src/module/host_tests.rs
  • crates/tinybus/src/module/mod.rs
  • crates/tinybus/src/proxy.rs
  • crates/tinybus/src/router.rs
  • crates/tinybus/src/router_tests.rs
  • docs/protocol.md

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@senamakel
senamakel merged commit 9e5961c into main Oct 12, 2026
14 checks passed
@tinysweeper

tinysweeper Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

⚠️ Review failed for 2900abbd21e2. the review of #63 did not finish within 900s

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.

1 participant