docs(design): fold channels into the agent tree (RIG-1622) - #984
Open
rigel-mintaka wants to merge 1 commit into
Open
docs(design): fold channels into the agent tree (RIG-1622)#984rigel-mintaka wants to merge 1 commit into
rigel-mintaka wants to merge 1 commit into
Conversation
|
Merging to
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 |
|
Compass engineering docs preview: https://compass-ui-rig-1622-channels.compass-eng-docs.pages.dev Deployed from Changed pages: |
rigel-mintaka
force-pushed
the
compass-ui/rig-1622-channels-in-agent-tree
branch
5 times, most recently
from
September 7, 2026 23:10
926a383 to
e1c7371
Compare
rigel-mintaka
force-pushed
the
compass-ui/rig-1622-channels-in-agent-tree
branch
from
September 7, 2026 23:15
e1c7371 to
e74ecab
Compare
rigel-mintaka
added a commit
that referenced
this pull request
Sep 8, 2026
…621) Adds the design record for RIG-1621: a persistent center-of-top-bar search input alongside the D5-frozen Cmd+K palette, covering agents, issues, PRs and chat messages. Both surfaces feed ONE provider set, so neither can drift from the other, and the corpus stays server-side per Matt's ruling that the client cannot hold the full text. Scope is the whole board, not the caller's assigned slice. Chat search is nearly free: the server already ships `rpc SearchMessages` with a tsvector index, and no UI code references it. Issue search is the real new work — a generated `search_tsv` column, a GIN index, and a `SearchIssues` RPC mirroring the messages pipeline. Two schema findings, both measured against PostgreSQL 18.4 rather than reasoned about, and both of which would have shipped a broken gate: The obvious spelling of the column does not compile: ERROR: generation expression is not immutable A STORED generation expression must be IMMUTABLE, and `array_to_string` is only STABLE (`labels::text` fails the same way — `array_out` is STABLE too). The cause is polymorphism, not arrays: `anyarray` must stay conservative for element types whose output reads a GUC. So labels route through a `compass_labels_text` wrapper declared IMMUTABLE with a pinned `search_path` — honest, because for TEXT[] the concrete element output function `textout` is itself IMMUTABLE. The one alternative that both compiles and is genuinely immutable, `array_to_tsvector`, bypasses the parser: labels land as raw lexemes, so a search for `triage` against a `Needs-Triage` label matches NOTHING. It fails silently, which is worse than the error. T1 therefore requires a label-only test. And the column must weight its fields with `setweight`. Unlike the messages column it spans a 40-character title and a multi-kilobyte body, and `ts_rank` applies no length normalization by default: flat concatenation scores a title hit and a hit buried in 10 KB of body EXACTLY equal (0.06079 vs 0.06079; weighted 0.60793 vs 0.24317). The task list already asserted 'title hit above body hit', which was unsatisfiable as specified. The column is STORED, so deferring this would cost a table rewrite. PR results are scoped honestly as fixture-only at v1: `Issue.prs` has zero Go writers, so PR search looks complete against fixtures and returns nothing in production. Not worse than today's PRs tab, but no live-mode PR assertion may gate the release. Review found three executability gaps, all fixed here rather than left for an executor to hit: providers cannot reach an RPC client at all today (the `AppStore` exposes none, and hanging one on it is forbidden by DL-128), so the seam is now OQ-7; the message destination cannot navigate through `store.openTopic`, which no-ops on any topic outside the client-held set, so it routes on wire data; and the debounce moved from T6 to T4, where the effect it wraps is written, removing a T4-T6 ordering knot. Ledger citations dropped their line numbers — DECISIONS.md is append-only, so a line number into it rots, and four were already off by three rows. Mints DL-346 (DL-344/345 were already claimed by open PR #984, six hours ahead of this one — allocated, not merged, so main's max would not have shown them). Leaves DL-233's assigned-issue scope for Matt as OQ-6, and whether the palette itself re-scopes as OQ-8: this design reverses a frozen decision, and frozen decision prose is never edited in place.
This was referenced Sep 9, 2026
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.
Design record for RIG-1622 — folds comms channels into the agent tree, so a
channel can hang off an agent as a child node instead of living in the
separate folder hierarchy that PR #91 removed.
Docs-only:
+1807 / -0across two files. No code changes, no behaviourchange. The record is the contract that T1–T8 execute against, frozen on
merge per
skill://design.docs/designs/ui/compass-channels-in-agent-tree/design.md(new, 1805 lines)docs/designs/DECISIONS.md(+2 — ledger rows DL-344/DL-345)Two forks Matt ruled, now settled in the record
Both were asked mid-pass and are recorded as DECIDED in the record and the
ledger, so a later reader does not reopen them:
ChannelMembershipMode(proto field 12, column
channels.membership_mode):EXPLICIT = 0keepshand-managed members,
TREE = 1derives the member set from the subtree.Deliberately not a
ChannelKindvalue — kind is the DM-vs-channel axis —and not implied by
parent_agent_id IS NOT NULL, which would foreclose ahand-membered channel that lives in the tree.
can read that owner's channels. Recorded as a product decision rather than
as reuse of an existing precedent, because no such precedent exists for
channels — the owner-set
viewerCTE appears only in the two groupqueries (
channels.sql:93,:118), never in the three channel predicates.A later ACL system is named as the successor, with its insertion point
stated.
Review history
Five review rounds (
skill://review), each one blocking on a real defect theprevious fix pass introduced or missed. The record grew 445 → 1805 lines
across them. The substantive finds, all driver-verified against code:
representation. Adding tree-derived membership was first fixed only at the
post gate (
messages.go:59); the identical defect then reappeared at sixmore sites, every one of them
FROM channel_members— the delivery fan-out(
SubscribedAgents,ChannelAgentMembers,SeedChannelDeliveryCursors,SweepChannels), three missed membership-probe callers (topics.go:23,channels.go:550,channels.go:765), and the wire, where an emptymember_account_idsmakesderiveMembershipreturn"none". Channel-keyedsites need subtree descent; account-keyed sites need ascent.
0001_init.sql:939-950enables row-levelsecurity by iterating a hardcoded
tenant_tablesarray, so a table addedoutside that list ships with RLS off. The record calls the array edit out
explicitly in T2.
CreateChannelreturned ahand-written
Channel{}literal after commit (channels.go:206-213),bypassing
channelFromRow— so both new columns were silently dropped on thecreate path. Enumerated properly: 49
return Channel{minus 47return Channel{}= exactly two field-populating sites. Fixed by re-readingthrough
getChannelafter commit, collapsing it to one, so no future columncan miss create. The two-line shortcut is explicitly forbidden in the record,
because the extra site is the defect.
One accepted limitation, stated rather than papered over: the post-commit
re-read is fallible where the literal was not. A fallback literal would
reintroduce the site the fix eliminated, and both siblings
(
UpdateChannelMembers,SetChannelPolicy) already propagate this way.Plan
T1 proto (attach edge, membership mode,
ReparentChannel) · T2–T6compass-server (schema + RLS, participant probe, visibility predicates and
read paths, subscriptions and delivery, comms RPC edge and events) · T7–T8
compass-ui (sidebar tree, live adapter and fixtures). Cross-lane: only T7–T8
are mine.
Five open questions remain in the record, each marked load-bearing or not.
One is load-bearing (whether the owner-set read grant extends to
OWNER-grouped channels) and is flagged for a decision before T4 starts.
Gates
bun tools/design-ledger-gate/index.ts—OK — 310 ledger row(s), 130 record header(s) validmoon run root:markdownlint— 207 files, 0 errorsRebased onto
main13a9e8f5. TheDECISIONS.mdconflict was resolved as theunion with my rows renumbered DL-338/339 → DL-344/345 (main had taken 338), and
the one prose citation of the old id updated with them.
RIG-1622