Problem
Every time a new adapter is added, all existing adapter test files must be updated to initialize the new fields — even though they never use them. This is because AppState is a single flat struct containing every adapter's state:
┌─────────────────────────────────────────────────────────┐
│ AppState (God Struct) │
├─────────────────────────────────────────────────────────┤
│ discord: Option<...> │
│ telegram: Option<...> │
│ line: Option<...> │
│ feishu: Option<...> │
│ google_chat: Option<...> │
│ wecom: Option<...> │
│ teams: Option<...> │
│ vtuber: Option<...> <-- new adapter │
│ vtuber_pending: Arc<Mutex<..>> <-- new adapter │
│ vtuber_ws_clients: Option<..> <-- new adapter │
│ ws_token: Option<...> │
│ event_tx: ... │
│ reply_token_cache: ... │
└─────────────────────────────────────────────────────────┘
Adding vtuber forces changes in unrelated test files:
New adapter (vtuber)
│
├──► line.rs tests → add vtuber: None, vtuber_pending: ..., vtuber_ws_clients: None
├──► teams.rs tests → add vtuber: None, vtuber_pending: ..., vtuber_ws_clients: None
├──► telegram tests → add vtuber: None, ...
└──► every future adapter test → same
Proposed Solution
Refactor to a registry/trait-object pattern so adapters are decoupled:
┌─────────────────────────────────┐
│ AppState (slim) │
├─────────────────────────────────┤
│ adapters: AdapterRegistry │ <-- dynamic dispatch
│ event_tx: ... │
│ shared_config: ... │
└─────────────────────────────────┘
│
v
┌─────────────────────────────────┐
│ AdapterRegistry │
│ HashMap<Platform, Box<dyn │
│ ChatAdapter>> │
└─────────────────────────────────┘
│ │ │
v v v
┌──────┐ ┌──────┐ ┌────────┐
│ Line │ │Teams │ │ VTuber │ <-- independent, no cross-knowledge
└──────┘ └──────┘ └────────┘
Benefits:
- Adding a new adapter does NOT touch any existing adapter code or tests
- Each adapter test only initializes its own state
- Cleaner separation of concerns
Context
Observed during PR #1234 (vtuber adapter) where line.rs and teams.rs test fixtures had to add #[cfg(feature = "vtuber")] fields just to compile.
Notes
This is a non-blocking architectural improvement — not urgent, but will reduce maintenance overhead as more adapters are added.
Problem
Every time a new adapter is added, all existing adapter test files must be updated to initialize the new fields — even though they never use them. This is because
AppStateis a single flat struct containing every adapter's state:Adding vtuber forces changes in unrelated test files:
Proposed Solution
Refactor to a registry/trait-object pattern so adapters are decoupled:
Benefits:
Context
Observed during PR #1234 (vtuber adapter) where
line.rsandteams.rstest fixtures had to add#[cfg(feature = "vtuber")]fields just to compile.Notes
This is a non-blocking architectural improvement — not urgent, but will reduce maintenance overhead as more adapters are added.