Skip to content

feat(store): owner-set visibility and derived TREE members on channel reads (RIG-4188) - #1772

Open
rigel-mintaka wants to merge 5 commits into
compass-comms/rig-4187-channel-participant-probefrom
compass-comms/rig-4188-channel-tree-reads
Open

rigel-mintaka wants to merge 5 commits into
compass-comms/rig-4187-channel-participant-probefrom
compass-comms/rig-4188-channel-tree-reads

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) #1762
  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)" (this PR)
  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

Channels-in-the-agent-tree, task T4 (docs/designs/ui/compass-channels-in-agent-tree/design.md § Plan): visibility predicates and read paths. Stacked on #1764.

  • Visibility (leg 2): the three channel predicate copies (ListChannels, ChannelVisibleTo, ChannelsByNameForViewer) gain the viewer CTE and the owner-set disjunct. The anchor's owner and every agent of that owner see an attached channel. Reading history still needs participation.
  • The carry, hops (i)–(iv): parent_agent_id and membership_mode move through the three projections, channelFromRow and all four of its call sites, store.Channel.ParentAgentID / .MembershipMode, and channelToWire.
  • Hop (v): CreateChannel returns the post-commit getChannel read instead of a hand-built literal. channelFromRow is now the only place a Channel is built.
  • Read gates: GetPageCursorSeq, ListMessages, SearchMessages, FindAskMessage, UpdateMessageBlocksAsAuthor and ResolveTopicForUpdate join one participating CTE (member rows UNION TREE channels on the actor's chain or owned by the actor) instead of a member-row JOIN. The SQL headers say the six copies must stay equal to ChannelParticipant.
  • Name resolve: ChannelByNameForViewer narrows several visible matches to the viewer's participant channels when there is at least one, so an owner-set sibling's same-named channel does not shadow an agent's own.
  • H3 materialization: ChannelMembersByChannelIDs runs one set-based descent over the TREE channels requested. It returns (channel_id, account_id) pairs, so each channel gets its own anchor's subtree plus the anchor's owner. subscribed comes from channel_subscriptions joined only to those participants, so a stale override from an agent reparented out is not on the wire.

Deferred to T6

The comms-boundary half of hop (v) is the CreateChannel RPC response plus exactly one ChannelChanged carrying parent_agent_id. That needs the RPC request fields T6 wires (parent_agent_handle, membership_mode). T4 asserts the store return value and the channelToWire / publishChannelChanged payload. T6 (same owner) adds the RPC assertion.

Tests

  • TestChannelVisibilityOwnerSetParity: owner and same-owner sibling see the channel; another user doesn't; ChannelVisibleTo agrees with ListChannels in every case.
  • TestChannelTreeParticipantReadsAndWrites: a subtree agent and the owner read history, search (scoped and unscoped), cursor and topic writes; an author reparented out cannot edit.
  • TestChannelTreeOwnerSetSiblingReadWriteDenials: an owner-set sibling sees the channel but gets nothing from list, search, cursor, UpdateTopic, edit or AnswerAsk; the subtree agent can answer the ask.
  • TestChannelByNameForViewerNarrowsOwnerSetDuplicatesToParticipants: an agent resolves its own standup; the owner and a non-participant sibling get the ambiguity error.
  • TestChannelTreeMembersAreAttributedAndSubscriptionsIntersect: two TREE channels at different anchors in one ListChannels, each with exactly its own subtree; 0 member rows; a stale override and a foreign override are on neither list.
  • TestChannelTreeProjectionCarriesAnchorAndMode (all three projection copies) and TestChannelTreeCreateUnderAgent (the CreateChannel return value).
  • TestChannelToWireCarriesTreeAttachment and TestPublishChannelChangedCarriesTreeAttachment.
  • Mutations, each failing one of the tests above:
    • dropping the disjunct from ChannelVisibleTo;
    • the old CreateChannel literal;
    • cross-attributed descent;
    • subscriptions not intersected;
    • ListMessages back on the member JOIN;
    • wire mode forced to EXPLICIT;
    • search TREE arm swapped for the owner set;
    • name narrowing removed, and its non-participant fallback removed;
    • FindAskMessage chain arm dropped.
  • Full store and comms pgtest suites: ok. vet, sqlc-drift and lint: clean.

Spec-impact: docs/specs/product/compass.md store scoping: attached channels are visible to the anchor's owner set; history, search and topic access need participation.
Ledger-impact: none

Refs RIG-4188, RIG-1622

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

… reads (RIG-4188)

The three channel predicate copies grant agent-attached channels to the
anchor owner set; projections carry parent_agent_id and membership_mode
to the wire; message and topic reads gate on participation; and
loadChannelMembers materializes each TREE channel subtree, with
subscribers intersected with it. CreateChannel returns the post-commit
getChannel read. The RPC response and event assertion lands with the RPC
wiring.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@linear-code

linear-code Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RIG-4188

RIG-1622

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

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

Deployed from compass-comms/rig-4188-channel-tree-reads at a265f91.

Changed pages:

rigel-mintaka and others added 4 commits October 6, 2026 04:16
…lves to participants (RIG-4188)

Message and topic reads join one participant-channel CTE instead of
per-row OR subplans, restoring the driving relation. ChannelByNameForViewer
narrows a multi-match to channels the viewer participates in, so a
same-owner sibling channel of the same name no longer makes an agent own
channel ambiguous. The product spec states that owner-set visibility does
not grant history.

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

A name that matches several visible channels narrows to the viewer's
participant channels only when that set is non-empty, so a non-participant
sibling gets the same ambiguity its channel list shows, not a not-found.
Message and topic doc comments go back to their full contracts, reworded
from membership to participation.

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

Restores the subtree-agent FindAskMessage/AnswerAsk positives and adds
unscoped search and owner ListMessages cases. The per-query participant
CTE is renamed participating, so it is not mistaken for channel visibility,
and both query files say the copies must stay equal to ChannelParticipant.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
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.

@trunk-io

trunk-io Bot commented Oct 7, 2026

Copy link
Copy Markdown

Stacked PR 1779 failed testing in the merge queue. Please investigate the failure and re-submit the stack.

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