Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/designs/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ check enforces the mechanical half. Full rationale:
| DL-226 | A message owed to an OFFLINE channel agent member is never silently stranded: the server wakes the member by RESUMING its most recent session (a system-authorized internal sibling of the public resume path, via a new `LatestSessionForAccount` read; fresh start only for a never-started agent; per-agent singleflight + not-live pre-check as cost control — agent-triggered starts are a core product capability, and `StartAgentSession`'s adminOnly PUBLIC door is untouched). Durability split: a mentioned member outside the sweep set (unsubscribed, non-home, non-mandatory) gets a durable owed-mention row `(agent_account_id, message_id)` written at the settle edge before the wake and swept subscription-independently on session start AS A STEER (D5 mention→steer preserved; steer-only precedence intact), cleared on the frozen message_id ack; a subscribed/home/mandatory member gets no owed row — the D2 cursor sweep is its durable backstop and the wake (both the mention arm and the plain-deliver arm) is pure latency. Broadcast mentions (`@everyone`/`@agents`) wake too; N-start amplification accepted. The residual pre-settle window is accepted for MVP (RIG-2490). Amends D5/OQ-3's offline clause by citation | Active (Matt, 2026-08-21); residual pre-settle window closed by DL-240 (RIG-2490, 2026-08-23) | [mention offline redelivery §Decisions](product/compass-mention-offline-redelivery.md#decisions-ruled-by-matt-2026-08-21) |
| DL-240 | The RIG-1641 OQ-5 residual pre-settle mention-loss window (a mention to an offline out-of-sweep-set member, lost when a crash or bus overrun drops `MessagePosted` before the settle-edge `routeMentions` pass) is closed by a per-message delivery marker, NOT a high-water cursor: a nullable `messages.mentions_routed_at BIGINT` (unix ms) set by the consumer after the settle-edge pass, with a recovery scan at consumer start + the `Lagged()` overrun re-subscribe reading `WHERE mentions_routed_at IS NULL` (skipping message_ids in `c.held`), replaying the ONE shared `routeMentions` body, then marking. The killed cursor could advance past a LOWER in-flight seq (`messages.seq` is `BIGSERIAL` assigned at INSERT but the bus event publishes post-commit, `comms.go:361-375`) whose crash-dropped event then stranded the mention forever — a new silent loss the marker cannot express. Seed-forward on first deploy (no historical backfill; compass pre-live). Extends DL-226's no-loss invariant from the settle edge back to the message-post commit; DL-226's wake+owed-mention mechanism is unchanged | Active (Matt, 2026-08-23) | [mention offline pre-settle closure §Resolved decisions](product/compass-mention-offline-redelivery-pre-settle-closure.md#resolved-decisions) |
| DL-241 | The agent forge native toolset is ten single-purpose tools, one per `ForgeCallRequest` arm (`forge_get_issue`, `forge_get_pull_request`, `forge_list_issues`, `forge_comment_on_issue`, `forge_comment_on_pull_request`, `forge_submit_review`, `forge_create_issue`, `forge_create_pull_request`, `forge_subscribe`, `forge_unsubscribe`), each a native `AgentTool` over a thin `ForgeBroker` on the `RunnerTransport.forge()` seam; `forge_subscribe`/`forge_unsubscribe` ship the complete surface now but return the server's in-band `unimplemented` until the poll-driver lane lands the `agent_forge_subscriptions` writer (DL-163). Multi-forge is exposed: every tool takes an optional forge selector (`forge_provider` + optional `forge_host`, unset = the configured default GitHub forge, DL-202) so an agent targets Linear (issues-only, `repo` = team key, DL-051; PR/review arms return in-band `unimplemented`) as well as GitHub. Mirrors DL-212's comms-toolset count row; the tool-count claim is load-bearing for future toolset-refresh rows | Active (Matt, 2026-08-24) | [forge tools §Tool set and shape](product/compass-agent-forge-tools/design.md#tool-set-and-shape--ten-native-tools-one-per-arm) |
| DL-283 | Agents and client UIs address channels and topics by NAME, not id — request-input channel/topic fields on the agent tool surface are name-typed, resolved viewer-scoped at the service edge (`ChannelByNameForViewer`: miss ≡ invisible ≡ merged `not_found`; a multi-hit errors `invalid_argument`, never auto-picks); response/stored/event fields stay id-typed. Extends DL-269/DL-270 from accounts to channels + topics. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-284 | Steer/deliver control ops denormalize the source channel name + topic name (server-resolved at wrap in `deliverOp`/`steerOp`, the `from_handle` pattern; a name-resolve miss degrades like a handle miss, never blocks delivery); the agent renders `Channel <name> › topic <name>:` and must name both on every post — `comms_post_message` has NO home-channel default and never auto-picks a reply target. The dogfood reply-mis-routing fix (RIG-2956 T0). Proto: `DeliverControl.channel_name = 5`, `SteerControl.topic_name = 4`/`channel_name = 5`. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-285 | Creating a topic requires `create_topic: true` on the post, in every channel including DMs (`PostMessageRequest.create_topic = 6`; `TopicRef.Create` gates the store name path) — amends DL-098's topic get-or-create clause (the Zulip threading model stays live; only auto-mint-on-miss is gated). A gated miss errors in-band `not_found`, never mints and never drops the message. Escape hatch (Matt): may revert for DMs only if it proves a blocker. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-286 | Agent↔agent DMs are auto-created (resolve-if-exists) by a single server-side `OpenDM` op — deterministic name `dm--<handleLo>--<handleHi>` in a per-owner reserved DM group — exposed publicly on `CommsService.OpenDM`, to agents as `comms_open_dm` (by peer handle) and the `comms_dm` direct-send composite (open + post in one call), and auto-opened manager↔peer at spawn (`SpawnPeerResponse.dm_channel_name = 4`). Generalizes DL-190's per-pair manager↔peer DM to any same-owner agent pair. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-287 | The reserved per-owner DM group is server-enforced: `CreateChannel` refuses any create targeting it (merged `not_found`) — only the OpenDM path writes there (primary squat defense); the resume/upsert path additionally verify-reconciles DM invariants (kind=DM ∧ mandatory ∧ both parties ⊆ members) as belt. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-288 | A peer-DM is born `kind=DM`, exactly two agent parties, `post_policy=OPEN` (ownerless), `mandatory_subscription=true`, members = both agents + pulled-in owner(s) (every member a delivery target from birth). A genuine member ADD converts it in the same tx to a named `kind=CHANNEL` (`UpdateChannelMembersRequest.convert_channel_name = 6`, required; leaves the reserved group, freeing the DM name); a remove below two agent parties errors. `CHANNEL_KIND_GROUP_DM = 2` is retired reserve-not-delete (enum number stays, deprecated, never produced; deleting it is buf-breaking). The only kinds are CHANNEL and DM. | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |
| DL-289 | Peer-DM scope is same-owner for MVP (the wave-shares-one-owner frame); a cross-owner peer handle is the merged in-band `not_found`. Cross-owner DMs are deferred to the bilateral owner-peering authz edge (RIG-2796-class). | Active (Matt, 2026-08-30) | [peer-DM §Ledger delta](product/compass-agent-peer-dm/design.md#ledger-delta) |

## Agent roles & prompts

Expand Down
22 changes: 11 additions & 11 deletions docs/designs/product/compass-agent-peer-dm/design.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Compass agent peer-DM — name-addressed comms + auto-created two-way agent↔agent DMs

Status: Draft
Status: Active
Owner: agents
Amends: compass-agent-org-mgmt-tools, compass-manager-comms-substrate,
compass-zulip-threading-model (two explicit amendments, §Approach), and extends
Expand Down Expand Up @@ -852,45 +852,45 @@ Interfaces: none new — consumes T0-T3.

## Ledger delta

Ledger-impact: deferred to freeze. Do not edit DECISIONS.md in this PR; the
caller applies these rows at freeze:
Ledger-impact: applied at freeze (2026-08-30) as DL-283..289 in
`docs/designs/DECISIONS.md` §Comms & tools:

- **DL-new-1 (name addressing):** Agents and client UIs address channels and
- **DL-283 (name addressing):** Agents and client UIs address channels and
topics by NAME; request-input channel/topic fields on the agent tool
surface are name-typed, resolved viewer-scoped at the service edge
(unknown ≡ invisible ≡ merged `not_found`; ambiguous errors, never
auto-picks); response/stored/event fields stay id-typed. Extends
DL-269/DL-270 from accounts to channels + topics.
- **DL-new-2 (reply routing):** Steer/deliver control ops denormalize the
- **DL-284 (reply routing):** Steer/deliver control ops denormalize the
source channel name + topic name (server-resolved at wrap, the
`from_handle` pattern); the agent renders both and must name both on every
post — `comms_post_message` has NO home-channel default and never
auto-picks a reply target.
- **DL-new-3 (topic gate):** Creating a topic requires `create_topic: true`
- **DL-285 (topic gate):** Creating a topic requires `create_topic: true`
on the post, in every channel including DMs — amends the
zulip-threading-model get-or-create ruling; a gated miss errors in-band,
never mints and never drops the message. (Escape hatch per Matt: may be
reverted for DMs only if it proves a blocker.)
- **DL-new-4 (DM path):** Agent↔agent DMs are auto-created
- **DL-286 (DM path):** Agent↔agent DMs are auto-created
(resolve-if-exists) by a single server-side `OpenDM` op — deterministic
name `dm--<handleLo>--<handleHi>` in a per-owner reserved DM group —
exposed publicly on `CommsService`, to agents as `comms_open_dm` (by peer
handle), as the `comms_dm` direct-send composite (open + post in one
call), and auto-opened manager↔peer at spawn
(`SpawnPeerResponse.dm_channel_name`).
- **DL-new-5 (DM namespace defense):** The reserved DM group is
- **DL-287 (DM namespace defense):** The reserved DM group is
server-enforced: `CreateChannel` refuses any create targeting it (merged
`not_found`) — only the OpenDM path writes there; the resume path
additionally verify-reconciles DM invariants (belt-and-braces).
- **DL-new-6 (DM shape):** A peer-DM is born `kind=DM`, exactly two agent
- **DL-288 (DM shape):** A peer-DM is born `kind=DM`, exactly two agent
parties, `post_policy=OPEN` (ownerless), `mandatory_subscription=true`,
members = both agents + pulled-in owner(s); every member a delivery target
from birth. A member ADD converts it — same tx — to a named `kind=CHANNEL`
(caller MUST supply the name; the channel leaves the reserved group,
freeing the DM name for a fresh pair-DM). `CHANNEL_KIND_GROUP_DM` is
retired reserve-not-delete: the enum number stays, deprecated, never
produced. The only kinds are CHANNEL and DM.
- **DL-new-7 (scope):** Peer-DM scope is same-owner for MVP (the F2
- **DL-289 (scope):** Peer-DM scope is same-owner for MVP (the F2
wave-shares-one-owner frame); a cross-owner handle is the merged in-band
`not_found`. Cross-owner DMs are deferred.

Expand All @@ -903,7 +903,7 @@ red-team (OQ-1, 2, 4, 6, 7, 8, 9) is now a Matt-ruled decision recorded in
### OQ-3 (non-load-bearing, deferred) — Cross-owner DMs

Different-owner agents cannot DM under this record (same-owner gate,
DL-new-7). `expandOwnerMembership` would already pull both owners in, so the
DL-289). `expandOwnerMembership` would already pull both owners in, so the
mechanism generalizes — the missing piece is an authz policy for cross-owner
contact (the bilateral owner-peering edge the handle-cutover record files as
RIG-2796-class scope). Deferred; the record is correct without it
Expand Down
Loading