feat(trust): Phase 1 (discord) — L3 identity via shared gate [DRAFT: canary before merge]#1270
Conversation
Routes Discord ingress through AdapterRouter::gate_incoming for the L3 (identity) layer, keyed under "discord" in the trust registry. - registry "discord" entry: L2 open + allow_dm=true (Discord's richer channel/thread/DM logic stays in the adapter — the flat allowed_channels model can't express thread-by-parent admission); L3 mirrors resolved [discord].allow_all_users/allowed_users - gate call added at the Discord dispatch spawn, redundant-but-matching with Discord's existing pre-dispatch user check → non-regressive by construction (cannot deny what already passed) Behavior-preserving. Phase 1c makes the gate authoritative and removes the scattered user check; richer Discord L2 modeling + dispatch privatization tracked in #1269. Refs #1264 #1269
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…F1/F2) F1 (blocker): Discord's is_denied_user has a !is_bot bypass (bot admission is handled by allow_bot_messages + trusted_bot_ids). The shared L3 gate is human-identity only, so running it on bots wrongly dropped trusted bot-to-bot messages when allow_all_users=false (multi-agent). Guard the gate with !sender.is_bot. F2: pass the in-scope is_dm instead of hardcoded false (benign today with the L2-open discord entry, but avoids latent risk). Note: #1267 (gateway) is unaffected — should_skip_event's user check never had a bot bypass, so the gateway gate already matched it for bots.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Extract the gate's bot-skip into l3_gate_applies(is_bot) and add a regression test (l3_gate_skips_bots_admits_humans) locking in that bots bypass the shared L3 gate (mirrors is_denied_user's !is_bot), so trusted/mode-admitted bots aren't denied when allow_all_users=false.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
LGTM ✅ — Clean, minimal wiring of the shared trust gate (L3 identity) for Discord ingress. Non-regressive by construction and canary-verified. All reviewer findings are migration items for Phase 1c, not current-PR blockers. What This PR DoesAdds Discord to the shared How It Works
Findings
Finding Details🟡 F1:
|
Phase 1 for Discord (#1264, #1269). Routes Discord ingress through
AdapterRouter::gate_incomingfor the L3 (identity) layer. Draft — to be canary-verified on one bot before merge (Discord is prod-critical).Design (why L3-only for Discord)
Discord's L2 is richer than the flat
allowed_channelsmodel: threads are admitted by parent channel and DMs byallow_dm. A flatsurface_allowed(thread_channel_id)would wrongly deny thread messages whenallow_all_channels=false. So:discordregistry entry is L2-open + allow_dm=true → the gate enforces L3 only; Discord's own channel/thread/DM logic stays in the adapter.[discord].allow_all_users/allowed_users.Non-regressive by construction
The gate call sits at the dispatch spawn, after Discord's existing pre-dispatch user check already ran with the same config. So the gate can only agree — it cannot deny a message that was already admitted. (Empty
sender_idfail-closed can't trigger — Discord messages always have an author.)Canary plan (before marking ready)
Deploy to one bot (e.g. a test bot) and confirm identical admit/deny:
Deferred
Testing
--features unified -D warningsclean; 92/92 Discord unit tests passRefs #1264 #1269