D8: scope connector relays by per-pod gates - #1550
Conversation
eb0770b to
6c99add
Compare
|
Gate read at The plan's §2 items are all genuinely implementedChecked each against the code rather than the summary:
One finding: the gate now governs inbound, which D3 says it does not
(integration.scope === 'user'
? integration.config?.gates?.[String(podId)]?.enabled === true
: String(integration.podId) === String(podId))Inbound calls it as The divergence is reachable without anyone doing anything unusual:
There is no It fails closed, so this is not a leak and I am not blocking on security. It is REVIEW rule 19: it fails silently and nobody hears it. Two ways out, and the choice belongs to the design note rather than to a patch here:
Non-blocking
|
…1550 already sends (Vera) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Re-gate at What's correct now. 1. Seed 6b's first half is not satisfied — both bridgesThe new membership branch returns silently: const pod = await PodModel.findById(podId).select('type createdBy members').lean();
if (!pod || !isPodMember(pod, linkedUserId)) {
console.warn('[slack-bridge] inbound dropped — linked user is no longer a pod member');
return { relayed: false };
}
Seed 6b is explicit that this is the case to answer:
Today only the post-sweep half replies. Both branches need 2. The copy is not the agreed copy#1551 D3 gives the sentence literally:
Shipped in both bridges: const NO_ACTIVE_POD_REPLY = 'This connector has no active pod. Choose one in Commonly first.';That is the string from the One constant, both bridges, both branches. Nothing else in the delta since |
|
Final gate at The last change, described accurately
The two changes before it were substantive: the limiters sit at the route sinks ahead of Closing a gap in my own readI had reviewed every source file in this PR except
One ordering property worth stating because the whole of D3 rests on it: Cumulative verdictAll seven items from the TASK-010 plan's §2 are implemented and tested at this head, the D3 ruling from #1551 is carried in both directions (inbound compares Nothing outstanding from this seat. |
…n switch, leaving it is heard, the page writes podId (#1551) * docs(d8-phase-2): inbound never reads the gate — the active pod is its own switch, leaving it is heard in the chat, and the page writes podId Vera's #1550 review (63797): isRelayableIntegration decided inbound by the gate, so a pruned gate silently dropped every message the owner typed while the page still read "linked to A". D3 now says inbound compares podId with membership checked at receive, the prune unsets podId with the gate, and an unrelayable message is answered in the chat. /pod was never built, so D4's gate list gains the active tag and Make active; D2 gains the not-linked row; seed 6b covers the walk. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(d8-phase-2): the no-active-pod reply reuses the command string #1550 already sends (Vera) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(d8-phase-2): the gate list's only rule is membership, and it is the server's — the picker's community/showcase filter matches no pod type (Vera) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(d8-phase-2): publicIntegration projects adminPause to { reason, at } — the moderated never learns who (Vera) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
03489f5 to
f5b582d
Compare
Summary
Verification
npx jest --runInBandfocused D8 suites: 131 passingnpm run tsc:checknpm run lint:ts(0 errors; pre-existing repository warnings)Full backend suite remains blocked by the existing Node 26 /
jsonwebtokenSlowBuffercompatibility failure outside this change.