## Summary
Fix Slack `groupPolicy: "open"` to allow unlisted channels even when `channels.slack.channels` contains custom entries.
## Problem
When `groupPolicy` is set to `"open"`, the bot should respond in **any channel** it's invited to. However, if `channels.slack.channels` contains *any* entries—even just one channel with a custom system prompt—the open policy is ignored. Only explicitly listed channels receive responses; all others get an ephemeral "This channel is not allowed" error.
### Example config
```json
{
"channels": {
"slack": {
"groupPolicy": "open",
"channels": {
"C0123456789": { "systemPrompt": "Custom prompt for this channel" }
}
}
}
}
```
With this config, the bot only responds in `C0123456789`. Messages in any other channel are blocked—even though the policy is `"open"`.
## Root Cause
In `src/slack/monitor/context.ts`, `isChannelAllowed()` has two sequential checks:
1. `isSlackChannelAllowedByPolicy()` — correctly returns `true` for open policy
2. A secondary `!channelAllowed` check — was blocking channels when `resolveSlackChannelConfig()` returned `{ allowed: false }` for unlisted channels
The second check conflated "channel not in config" with "channel explicitly denied."
## Fix
Use `matchSource` to distinguish explicit denial from absence of config:
```ts
const hasExplicitConfig = Boolean(channelConfig?.matchSource);
if (!channelAllowed && (params.groupPolicy !== "open" || hasExplicitConfig)) {
return false;
}
```
When `matchSource` is undefined, the channel has no explicit config entry and should be allowed under open policy.
## Behavior After Fix
| Scenario | Result |
|----------|--------|
| `groupPolicy: "open"`, channel unlisted | ✅ Allowed |
| `groupPolicy: "open"`, channel explicitly denied (`allow: false`) | ❌ Blocked |
| `groupPolicy: "open"`, channel with custom config | ✅ Allowed |
| `groupPolicy: "allowlist"`, channel unlisted | ❌ Blocked |
## Test Plan
- [x] Open policy + unlisted channel → allowed
- [x] Open policy + explicitly denied channel → blocked
- [x] Allowlist policy + unlisted channel → blocked
- [x] Allowlist policy + listed channel → allowed