You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bot turn counting, channel gating, warning emission, and business logic are all mixed in message(). This caused #529 (warning sent to non-allowed channels) and makes #530 (dedup) hard to fix cleanly.
Both Discord and Slack adapters have this problem. The warning-before-gating pattern exists in both discord.rs and slack.rs.
Proposed Architecture
message() arrives
→ resolve_context() // build ResolvedMessageContext (shared, cross-adapter)
→ record_turns() // pure counting, no side effects (#483 invariant)
→ evaluate_gating() // channel/user/bot permission check
→ evaluate_throttle_effects() // decide: Continue | Stop | StopWithEffect(Warning)
→ execute_effects() // single place for side effects (say, react, etc.)
→ dispatch_business_logic() // handle_message, streaming, etc.
Design Requirements
Shared ResolvedMessageContext — channel_id, parent_id, is_bot, allowed_here, etc. computed once, shared across all stages. No duplicate resolution.
Decisions, not side effects — each stage returns a decision enum (Continue, Stop, StopWithEffect(Effect::Warning(...))). Side effects executed by a single coordinator, not inside the stage.
Counting before gating, emission after gating — the key insight: counting and emission must be decoupled. Counting runs early (all bot messages), emission runs after gating (only allowed channels).
Cross-adapter design — the pipeline must apply to both Discord (discord.rs) and Slack (slack.rs). Both have the same warning-before-gating bug pattern today.
Affected Code
discord.rs line ~258-290: bot turn counting + warning say() before channel gating
slack.rs line ~678-697: same pattern — classify_bot_message + send_message before allow_bot_messages gating
Motivation
Bot turn counting, channel gating, warning emission, and business logic are all mixed in
message(). This caused #529 (warning sent to non-allowed channels) and makes #530 (dedup) hard to fix cleanly.Both Discord and Slack adapters have this problem. The warning-before-gating pattern exists in both
discord.rsandslack.rs.Proposed Architecture
Design Requirements
Shared
ResolvedMessageContext—channel_id,parent_id,is_bot,allowed_here, etc. computed once, shared across all stages. No duplicate resolution.Decisions, not side effects — each stage returns a decision enum (
Continue,Stop,StopWithEffect(Effect::Warning(...))). Side effects executed by a single coordinator, not inside the stage.Throttle state abstracted behind store/policy — don't let stages directly operate on
HashMap. Enables Bug: Multiple allowed bots each post their own turn limit warning in the same thread #530 dedup and future shared state without re-splitting.Counting before gating, emission after gating — the key insight:
countingandemissionmust be decoupled. Counting runs early (all bot messages), emission runs after gating (only allowed channels).Cross-adapter design — the pipeline must apply to both Discord (
discord.rs) and Slack (slack.rs). Both have the same warning-before-gating bug pattern today.Affected Code
discord.rsline ~258-290: bot turn counting + warning say() before channel gatingslack.rsline ~678-697: same pattern — classify_bot_message + send_message before allow_bot_messages gatingIncremental Rollout
resolve_message_context()andevaluate_turn_policy()as minimal first step (both adapters)Related