Skip to content

docs(ADR-016): close a residual #797 fixed, and add the writer row that was missing - #824

Merged
lilyshen0722 merged 3 commits into
mainfrom
docs/adr-016-close-residual-and-writer-row
Aug 4, 2026
Merged

docs(ADR-016): close a residual #797 fixed, and add the writer row that was missing#824
lilyshen0722 merged 3 commits into
mainfrom
docs/adr-016-close-residual-and-writer-row

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

Found by reading ADR-016 §1–75 — the item three seats have listed as unread all day. Docs-only, based on main.

1. A gap the ADR still lists as open was closed three days ago

The Residual divergence, not a leak (open, low priority) paragraph said the agent discovery route composes COMMUNITY_LISTING_QUERY (flags only) while human Discover also excludes invite-only — "the route's own comment says it reuses the flag so this route cannot drift … and it does still differ."

It doesn't. #797 (b2fc6cde) landed DIRECTLY_JOINABLE_QUERY at routes/agentsRuntime.ts:2470 — listing flags plus joinPolicy: { $ne: 'invite-only' } — and the handler comment now reproduces this ADR's own per-clause table, including why members: { $ne: callerId } is deliberately not adopted.

Rewritten as CLOSED, dated, with the old text quoted rather than deleted — because the staleness is the point. It was accurate on 2026-08-01, has read as current for three days, and nothing on the page marked it. An ADR that records live gaps needs its entries dated and closed, or it becomes the confident-and-wrong surface it exists to prevent.

2. The gap table has no row for membership writers

That table enumerates read surfaces and visibility writers. Invariant 2 — self-joinable ⇒ listed — is a join rule, and the only join path in it is joinPod (human).

The agent-side join path isn't joinPod. It's POST /api/agents/runtime/pods, whose dedup branch does a global Pod.findOne({ name }) and, on a hit, pushes the caller into members, installs them (which is what grants posting — auth goes through AgentInstallation.find, not pod.members), and installs commonly-bot with context:read. It gated on none of the tier logic, so a guessed pod name was a credential for joining any non-DM pod in the instance — including private + joinPolicy:'open', the dormant-declaration state at §46 that a joinPolicy-only check waves straight through.

Closed by #817 (DM types) and #821 (isDirectlyJoinable for the rest) — #821 is literally an encoding of this ADR's §44 biconditional.

The rule the omission earns: the gap table must enumerate every writer that can change who is in a pod, not only the writers that change its tier. The ADR argues a per-surface enumeration catches an absent predicate where no grep can — true, and only for the surfaces it enumerates.

🤖 Generated with Claude Code

…at was missing

Two defects found by reading §1-75, which three seats had flagged as unread.

1. The "Residual divergence, not a leak (open, low priority)" section
described the agent discovery route composing COMMUNITY_LISTING_QUERY while
human Discover also excluded invite-only. #797 (b2fc6cd) adopted
DIRECTLY_JOINABLE_QUERY at routes/agentsRuntime.ts:2470 — flags plus
joinPolicy $ne invite-only — and the handler comment now carries the
per-clause reasoning, including why the members clause is not adopted. The
paragraph has read as current for three days with nothing marking it stale.
Kept and dated rather than deleted, because that staleness is the lesson.

2. The enforcement-gap table enumerates read surfaces and visibility
writers. It has no row for membership writers — so invariant 2
(self-joinable => listed) was tracked only at the human joinPod path, while
the agent-side join path is the pod-create dedup branch, which gated on
nothing and made a guessed pod name a credential for joining any non-DM pod.
Closed by #817 and #821; recorded here with the rule the omission earns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One conflict, in the residual-divergence section. This branch and #802 both
closed it; #802 merged first and carries the fuller treatment — the
merged-is-not-deployed window, the retiring predicate, and the record of that
predicate firing. Took main's side wholesale rather than interleaving two
accounts of the same closure.

What survives from this branch is what #802 did not have: the membership-writer
paragraph and the rule it earns — the gap table must enumerate every writer
that can change who is in a pod, not only the writers that change its tier.
That omission is why the #821 bypass survived a per-surface audit, so the rule
is now load-bearing rather than editorial.

Net effect on main: purely additive, 4 lines.
@lilyshen0722
lilyshen0722 merged commit c79765a into main Aug 4, 2026
10 checks passed
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