Skip to content

feat(store): attach channels to agents with tree or explicit membership (RIG-4186) - #1762

Open
rigel-mintaka wants to merge 4 commits into
mainfrom
compass-comms/rig-4186-channel-tree-store
Open

rigel-mintaka wants to merge 4 commits into
mainfrom
compass-comms/rig-4186-channel-tree-store

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

This PR is part of a stack containing 5 PRs:

  1. main
  2. "feat(store): attach channels to agents with tree or explicit membership (RIG-4186)" (this PR)
  3. feat(store): authorize channel writes and reads by tree participation (RIG-4187) #1764
  4. feat(store): owner-set visibility and derived TREE members on channel reads (RIG-4188) #1772
  5. feat(store): TREE subscriptions and delivery over derived participants (RIG-4189) #1778
  6. feat(comms): wire ReparentChannel and attached CreateChannel (RIG-4190) #1779

Summary

Store half of channels-in-the-agent-tree, task T2 (docs/designs/ui/compass-channels-in-agent-tree/design.md § Plan).

  • Migration 0002_channel_tree.sql (rebased onto the 0001 fold; renumbered in its own commit):
    • Adds channels.parent_agent_id (FK agent_accounts) and membership_mode (IN (0, 1)).
    • Adds channels_group_xor_agent and channels_tree_mode_needs_agent, channels_parent_agent_idx, and the partial unique channels_agent_name_key.
    • Adds channel_subscriptions with its account index, its own ENABLE/FORCE RLS, the tenant_isolation policy and grants. A later table inherits none of these from 0001.
    • squawk flagged the FK and the two CHECKs on channels. Each has a per-clause squawk-ignore: channels is small, the new column is all NULL, and lock_timeout bounds the wait. The 0004 FK precedent is the same.
  • CreateChannel:
    • New input-only refusals run before the tx: unknown mode; both group and agent; an agent anchor on a non-CHANNEL kind; TREE without an anchor; TREE with mandatory subscription; TREE with OWNER_ONLY.
    • requireAgentAttachAuthz checks that the actor is the agent's owner or a same-owner agent. An unknown or foreign agent gets ErrNotFound.
    • Insert FK errors are now mapped by constraint name.
    • A TREE create writes no member rows and returns no members, so it matches what ListChannels reports until T4 swaps the return for the getChannel re-read.
  • ReparentChannel:
    • The participant probe (ChannelParticipant, the design's sketch) runs before the row lock, so a non-participant never takes the lock.
    • It runs again after FOR UPDATE, against committed membership, so a concurrent member removal cannot be bypassed.
    • The destination same-owner check runs next. All of these return ErrNotFound.
    • Only then come the refusals (grouped, non-CHANNEL kind, home channel, TREE detach), each ErrInvalidArgument. A name clash at the destination is ErrConflict.
  • ChannelMembershipMode type; NewChannel.ParentAgentID / .MembershipMode.

Out of scope here (later stack PRs): rebinding requireChannelMember onto the probe (T3); carrying the new columns through Channel reads and the getChannel re-read (T4); delivery and subscription toggles (T5); the RPC edge (T6).

Tests

  • New channel_tree_pgtest_test.go, 12 tests:
    • create under an agent in both modes; cross-owner attach by a user and by an agent, and unknown agent → NotFound; seven input refusals including DM-kind attach; unknown owner-account FK; name namespace per agent;
    • reparent shape refusals, with non-participant and foreign/unknown-destination cases → NotFound before any InvalidArgument;
    • descendant re-anchors its ancestor's channel; EXPLICIT detach to root; duplicate name at destination; converted DM attached by each owner;
    • membership mode never changes after create;
    • tenant B reads 0 channel_subscriptions rows written under tenant A;
    • a reparent racing a concurrent member removal (event-gated on pg_blocking_pids) → NotFound.
  • TestRLSCatalogEnabledAndForced now lists channel_subscriptions.
  • Mutations, each failing a named test:
    • skipping the participant gate;
    • dropping the post-lock re-check;
    • dropping RLS ENABLE/FORCE.
  • Full store pgtest suite: ok. go vet -tags pgtest, sqlc-drift, and sql-migration-gate:check all pass. golangci-lint (untagged and pgtest) reports no new findings.

Spec-impact: none
Ledger-impact: none

Refs RIG-4186, RIG-1622

Co-authored-by: Matt Wilkinson matt@rigel.build

@trunk-io

trunk-io Bot commented Oct 6, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@linear-code

linear-code Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RIG-4186

RIG-1622

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-comms-rig-4186-chann.compass-eng-docs.pages.dev

Deployed from compass-comms/rig-4186-channel-tree-store at 1a144e8.

rigel-mintaka and others added 4 commits October 6, 2026 01:56
…ip (RIG-4186)

Migration 0009 adds channels.parent_agent_id and membership_mode with
their CHECKs and indexes, plus channel_subscriptions with its own RLS,
tenant_isolation policy and grants. CreateChannel accepts an agent
anchor and a mode, authorizes the attach against the owner set, and
writes no member rows for a TREE channel. ReparentChannel runs the
participant gate before every shape refusal.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
… (RIG-4186)

ReparentChannel now takes the channel row lock before the participant
and destination checks, so a concurrent member removal is seen. Create
refuses an agent anchor on a DM kind and names the owner-account FK.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
… (RIG-4186)

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…001 fold (RIG-4186)

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@trunk-io

trunk-io Bot commented Oct 7, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 1779, which will merge 1762, 1764, 1772, 1778, 1779.

This branch has not been deployed

No deployments
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.

2 participants