Skip to content

feat: add SubscribeEvents stream and consolidate gRPC-Web transport into @compass/client - #2

Merged
mattwilkinsonn merged 4 commits into
mainfrom
sea-1024-compass-contract--cook
Jun 29, 2026
Merged

feat: add SubscribeEvents stream and consolidate gRPC-Web transport into @compass/client#2
mattwilkinsonn merged 4 commits into
mainfrom
sea-1024-compass-contract--cook

Conversation

@mattwilkinsonn

@mattwilkinsonn mattwilkinsonn commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Add SubscribeEvents server-streaming RPC and consolidate the gRPC-Web transport into @compass/client

What changed

Proto contract

A SubscribeEvents server-streaming RPC is added to CompassService. It accepts a SubscribeEventsRequest with a since_seq cursor (0 = snapshot-then-tail, >0 = gap-free resubscribe) and streams Event messages. Each Event carries a daemon-assigned monotonic seq, a Unix-ms timestamp, and a oneof payload that currently covers DaemonStatus and ResyncRequired. DaemonState is a new enum with UNSPECIFIED and READY variants. The RPC_RESPONSE_STANDARD_NAME buf lint rule is suppressed for this RPC because the stream delivers domain events rather than a one-shot response.

@compass/client

  • createCompassWebClient(baseUrl) is introduced as the single entry point for web UI code. It internally constructs the gRPC-Web transport, so callers no longer need to import or depend on @connectrpc/connect-web directly.
  • createCompassClient(transport) is kept for non-web consumers that supply their own transport.
  • @connectrpc/connect-web is promoted from a dev dependency to a runtime dependency of the package.
  • New types (Event, DaemonStatus, ResyncRequired, SubscribeEventsRequest) and the DaemonState enum are re-exported from the package index.

apps/ui

  • The direct @connectrpc/connect-web dependency is removed; the UI now reaches the daemon exclusively through @compass/client.
  • The local client.ts module and its test are deleted; createCompassWebClient from @compass/client replaces them.
  • The separate tsconfig.test.json and the test-file exclusion in tsconfig.json are removed, simplifying the TypeScript configuration to a single config.
  • The typecheck task is simplified to a single tsc --noEmit invocation.
  • The test task passes --pass-with-no-tests so the task does not fail when no test files are present.

Linter

Biome is configured to error on direct imports of @connectrpc/connect and @connectrpc/connect-web everywhere except inside packages/compass-client, enforcing that all other code reaches the daemon only through the owned @compass/client door.


Summary by cubic

Adds the SubscribeEvents server-streaming RPC and introduces createCompassWebClient to centralize gRPC‑Web behind @compass/client, making the UI use a single, owned door to the daemon. Aligns with SEA-1024 by delivering the event channel and fencing raw Connect imports.

  • New Features

    • SubscribeEvents stream with since_seq cursor; responses include seq, at_unix_ms, and payloads: DaemonStatus and ResyncRequired. Uses the standard <Rpc>Response name.
    • @compass/client exports createCompassWebClient(baseUrl); createCompassClient(transport) remains. Re-exports streaming types, DaemonState, and Transport.
  • Refactors

    • Moved @connectrpc/connect-web to a runtime dependency of @compass/client; removed from apps/ui.
    • UI now uses createCompassWebClient; removed the local wrapper and its test. Simplified TS config and tasks (single tsconfig; tsc --noEmit; bun test --pass-with-no-tests).
    • Biome fence bans direct and subpath imports of @connectrpc/connect/@connectrpc/connect-web outside packages/compass-client.
    • Updated apps/ui task inputs to track /packages/compass-client/package.json and tsconfig.json (test) for accurate cache keys.

Written for commit 27ba8c6. Summary will update on new commits.

Review in cubic

Closes SEA-1024

…import fence

SubscribeEvents adds the server-streaming half of compass.v1 (compass.md §7.2): an Event envelope with a daemon-assigned monotonic `seq` and `since_seq` resubscribe for gap-free reconnect, carrying a typed DaemonState payload that grows to board/agent/audit variants behind the buf breaking gate. buf lint excepts RPC_RESPONSE_STANDARD_NAME so the stream stays `Event`, not a one-shot response.

Enforces the owned door: @compass/client gains createCompassWebClient (bundling the gRPC-Web transport) and a biome noRestrictedImports fence bans @connectrpc/connect{,-web} outside the client, so UI code reaches the daemon only through the generated client. apps/ui drops its redundant transport wrapper and imports only @compass/client.

Closes SEA-1024.
@linear-code

linear-code Bot commented Jun 28, 2026

Copy link
Copy Markdown

SEA-1024

@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, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10f7f7ac-1940-4fc6-85ca-b2e7e751d1db

📥 Commits

Reviewing files that changed from the base of the PR and between b70887b and 27ba8c6.

📒 Files selected for processing (1)
  • apps/ui/moon.yml

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a web-friendly Compass client helper for browser/gRPC-Web use.
    • Introduced live server event streaming (including daemon status updates and resync-required signaling).
  • Bug Fixes
    • Updated test runs to succeed when no test files are present.
    • Streamlined type-checking to run a single pass.
  • Refactor
    • Removed the UI’s previous daemon client adapter and updated related client tests.
  • Chores
    • Adjusted TypeScript configuration, runtime dependencies for the client package, and tightened import linting rules.

Walkthrough

Adds a SubscribeEvents server-streaming RPC and supporting daemon state messages, moves gRPC-Web client wiring into compass-client, updates UI task and tsconfig behavior, and adds Biome rules restricting direct @connectrpc imports outside compass-client.

Changes

SubscribeEvents RPC and client consolidation

Layer / File(s) Summary
SubscribeEvents proto schema and contract tests
crates/compass-proto/proto/compass/v1/compass.proto, crates/compass-proto/tests/contract.rs
Adds SubscribeEvents streaming RPC to CompassService; introduces SubscribeEventsRequest, SubscribeEventsResponse, DaemonStatus, DaemonState, and ResyncRequired; adds Rust smoke tests for payload matching, enum stability, and default cursor behavior.
compass-client web helper and exports
packages/compass-client/package.json, packages/compass-client/src/index.ts, packages/compass-client/src/index.test.ts
Moves @connectrpc/connect and @connectrpc/connect-web to runtime dependencies; adds createCompassWebClient(baseUrl) using gRPC-Web transport; expands re-exports to include the new event-stream types and DaemonState; updates the test to assert subscribeEvents is present.
UI app cleanup and task updates
apps/ui/package.json, apps/ui/tsconfig.json, apps/ui/moon.yml
Removes the UI connect-web dependency, folds test files into the main tsconfig, changes typecheck to a single tsc --noEmit, and changes test to bun test --pass-with-no-tests.
Biome import restrictions for connectrpc
biome.json
Adds noRestrictedImports rules for @connectrpc/connect and @connectrpc/connect-web, with an override that disables the rule in packages/compass-client/**.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • sealedsecurity/compass#1: Introduced the initial compass.v1 proto and compass-client wiring that this PR extends with SubscribeEvents and createCompassWebClient.

Poem

🐇 I hop through streams where events now flow,
The daemon speaks in a tidy glow.
Old client burrows close behind,
New web paths woven, well designed.
With since_seq, I won’t lose the trail,
And bunny ears cheer as packets sail.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: the new SubscribeEvents stream and gRPC-Web transport consolidation.
Description check ✅ Passed The description is directly related to the changeset and accurately outlines the proto, client, UI, and lint updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sea-1024-compass-contract--cook

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

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jun 28, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces the SubscribeEvents server-streaming RPC to the compass.v1 contract and centralizes the gRPC-Web transport inside @compass/client, so the UI no longer needs to depend on @connectrpc/connect-web directly.

  • Proto & generated code: Adds SubscribeEventsRequest/SubscribeEventsResponse with a since_seq cursor, a DaemonStatus/ResyncRequired oneof payload, and the DaemonState enum. Rust and TypeScript generated bindings are both updated; contract tests cover seq fields, enum wire values, and the since_seq = 0 snapshot default.
  • @compass/client: createCompassWebClient(baseUrl) wraps the transport internally; createCompassClient(transport) is kept for non-web consumers. Transport is re-exported to let those consumers type their variables without importing @connectrpc/connect directly (which the new Biome fence would otherwise block).
  • Biome fence: noRestrictedImports errors on direct @connectrpc/connect* imports everywhere outside packages/compass-client, enforced via both exact paths and subpath group patterns, with a correct override for the client package.

Confidence Score: 5/5

Clean, well-scoped change — proto contract, generated bindings, TypeScript client, and lint fence are all consistent with each other and with the existing codebase patterns.

All layers (proto, Rust tonic stubs, TypeScript generated bindings, client package, UI wiring, lint fence) are aligned. No missing guards, no stale state, no dropped side effects. The previous thread concerns (global buf lint suppression, missing Transport re-export) are both addressed in this revision.

No files require special attention.

Important Files Changed

Filename Overview
packages/compass-client/src/index.ts Introduces createCompassWebClient, re-exports Transport type and new proto types; clean consolidation of the gRPC-Web transport into the owned client package.
biome.json Adds noRestrictedImports fence for @connectrpc/connect* packages with an override that exempts packages/compass-client; both paths (exact) and patterns (subpath globs) are configured correctly.
crates/compass-proto/proto/compass/v1/compass.proto Adds SubscribeEvents server-streaming RPC with since_seq cursor, SubscribeEventsResponse with oneof payload, and DaemonState enum — well-designed proto contract.
packages/compass-client/src/gen/compass/v1/compass_pb.ts Generated protobuf bindings for new messages and DaemonState enum; SubscribeEventsResponse correctly typed with bigint for uint64/int64 fields and a discriminated-union payload.
crates/compass-proto/src/gen/compass/v1/compass.v1.rs Generated Rust types for new proto messages; Copy + Hash derives are valid since all payload variants (DaemonStatus with i32, empty ResyncRequired) are themselves Copy.
crates/compass-proto/tests/contract.rs Adds compile-time and value-level tests for new proto types; covers seq/payload structure, enum wire values, and the since_seq = 0 default.
apps/ui/tsconfig.json Removes the exclude for test files and drops tsconfig.test.json; safe because all test files in apps/ui/src/ were deleted in this PR.
apps/ui/moon.yml Simplifies typecheck to single tsc --noEmit, adds --pass-with-no-tests, and extends cache inputs to include compass-client/package.json.

Reviews (4): Last reviewed commit: "fix(ui): track tsconfig.json in test cac..." | Re-trigger Greptile

Comment thread buf.yaml Outdated
Comment thread packages/compass-client/src/index.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cubic analysis

2 issues found across 17 files

Linked issue analysis

Linked issue: SEA-1024: compass.v1 gRPC contract crate + generated clients (CI drift-gated)

Status Acceptance criteria Notes
Add SubscribeEvents server‑streaming RPC and Event message (seq, at_unix_ms, oneof payload with DaemonStatus and ResyncRequired) and DaemonState enum The proto, generated Rust, and generated TS all include the SubscribeEvents RPC, SubscribeEventsRequest, Event message with seq/at_unix_ms/payload variants, DaemonStatus, ResyncRequired, and DaemonState enum.
Expose a single web entrypoint that bundles the gRPC‑Web transport (createCompassWebClient) and re‑export new types from @compass/client createCompassWebClient was added to the client index, the transport is constructed there, and the package re-exports Event/DaemonStatus/ResyncRequired/SubscribeEventsRequest and DaemonState.
Consolidate UI to use @compass/client (remove direct @connectrpc/connect-web usage and local client module) apps/ui no longer depends on @connectrpc/connect-web, the local client.ts and its test were removed, and package.json and build/test scripts were updated to use the client package.
Enforce lint rule banning direct imports of @connectrpc/connect and @connectrpc/connect-web except inside packages/compass-client biome.json now defines noRestrictedImports for those packages with an override turning the rule off for packages/compass-client.
Check in generated clients and add compile/usage tests that verify the generated schema surface Generated Rust and TS artifacts were updated/checked in, and tests were added/updated to exercise the new types and client surface (Rust contract tests, TS client test).
Suppress the buf RPC response name lint for this stream (SubscribeEvents) buf.yaml now excludes the RPC_RESPONSE_STANDARD_NAME lint with a comment referencing SubscribeEvents semantics.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread buf.yaml Outdated
Comment thread biome.json Outdated
…ransport export

- Rename the streamed `Event` to `SubscribeEventsResponse` (buf's standard
  `<Rpc>Response` name), removing the module-wide RPC_RESPONSE_STANDARD_NAME
  except so every RPC stays lint-gated with no per-RPC suppression.
- biome fence: add `patterns` banning `@connectrpc/connect{,-web}` subpaths so
  the owned `@compass/client` door can't be bypassed via deep imports.
- Re-export `Transport` from `@compass/client` so non-web consumers can type a
  custom transport without importing the fenced connect package.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ui/moon.yml`:
- Line 26: The Moon cache inputs for the UI tasks are missing
`packages/compass-client/package.json`, so changes to that package’s exports or
dependencies can be missed and stale `build` or `typecheck` results reused.
Update the relevant input lists in the moon config for the affected tasks to
include `packages/compass-client/package.json` alongside the existing `src/**/*`
and other project files, so resolution/bundling changes invalidate the cache
correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 958c7c05-f096-42d5-acb9-70c321ad163a

📥 Commits

Reviewing files that changed from the base of the PR and between 8f88a4e and 1341d72.

⛔ Files ignored due to path filters (4)
  • bun.lock is excluded by !**/*.lock
  • crates/compass-proto/src/gen/compass/v1/compass.v1.rs is excluded by !**/gen/**
  • crates/compass-proto/src/gen/compass/v1/compass.v1.tonic.rs is excluded by !**/gen/**
  • packages/compass-client/src/gen/compass/v1/compass_pb.ts is excluded by !**/gen/**
📒 Files selected for processing (12)
  • apps/ui/moon.yml
  • apps/ui/package.json
  • apps/ui/src/client.test.ts
  • apps/ui/src/client.ts
  • apps/ui/tsconfig.json
  • apps/ui/tsconfig.test.json
  • biome.json
  • crates/compass-proto/proto/compass/v1/compass.proto
  • crates/compass-proto/tests/contract.rs
  • packages/compass-client/package.json
  • packages/compass-client/src/index.test.ts
  • packages/compass-client/src/index.ts
💤 Files with no reviewable changes (4)
  • apps/ui/package.json
  • apps/ui/src/client.ts
  • apps/ui/tsconfig.test.json
  • apps/ui/src/client.test.ts

Comment thread apps/ui/moon.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ui/moon.yml`:
- Line 35: The test cache inputs for the `test` task do not include
`tsconfig.json`, so config-only changes can reuse stale `bun test` results.
Update the `inputs` list in the `moon.yml` test layer to track `tsconfig.json`
alongside the existing entries, keeping the cache invalidation aligned with the
main TypeScript config.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ec733174-3a2a-46bf-a50b-890fdff5584e

📥 Commits

Reviewing files that changed from the base of the PR and between 1341d72 and b70887b.

📒 Files selected for processing (1)
  • apps/ui/moon.yml

Comment thread apps/ui/moon.yml Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread apps/ui/moon.yml Outdated
@mattwilkinsonn
mattwilkinsonn merged commit a24137e into main Jun 29, 2026
4 checks passed
seal-agent added a commit that referenced this pull request Jul 30, 2026
Two review-loop test additions on the durable sink-ack handler (PR #43),
both defending an invariant the first-round suite left to inference:

- runnerhub/commit_frame_test.go: a hub UPDATE-arm test symmetric to the
  posted happy path. The ConversationUpdated dispatch arm was proven only at
  the comms layer + via the fake recorder, never through Hub.commitFrame
  itself; this asserts the arm forwards under the bound account with the key
  threaded and returns the UPDATE's own row id (m-99) — a mis-wire that
  returned the posted id or the wrong frame now fails here (verified red).
- runnerhub/auth_test.go: TestAccountTokenRejectedOnEveryRPCPath gains a
  commit_conversation_frame subtest, replacing two dead duplicate
  relay_comms_call slots (Go suffixed #1/#2, so they ran but covered
  nothing new). The new RPC's door-interceptor wiring is now asserted
  Unauthenticated for an account token, closing the door-coverage gap.

Refs SEA-1364

Co-Authored-By: seal <noreply@sealedsecurity.com>
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