# TUI 通知チャネル: Warn/Error をユーザーに可視化 ## 背景 Pod/Worker 層は現在、通知すべき事象(compaction 失敗、AGENTS.md 読み取り失敗、ツール出力の切り詰め、将来追加される様々な前処理エラー等)をすべて `tracing::warn!` で出している。TUI はこのログを受け取る仕組みを持たないため、**ユーザーは何も気づかないまま Pod が縮退動作している状態**になりうる。 tracing は開発者向けログで、ユーザー向け通知とは目的が違う。Pod 層が「これはユーザーに見せるべき」と判断した事象を、専用チャネルで TUI に届ける仕組みが必要。 ## 関連するチケット・機能 - `tickets/agents-md-ingestion.md`: AGENTS.md の切り詰め / 読み取り失敗の警告を現在 `tracing::warn!` だけに出している - `crates/pod/src/pod.rs`: compaction 失敗を `tracing::warn!` で済ませている - `crates/llm-worker/src/worker.rs`: ツール出力の切り詰めを `tracing::warn!` で済ませている これらはすべて本チケットの完成後に通知チャネル経由に載せ替えることで、ユーザーに可視化される。 ## 要件 ### チャネルの所在と型 - Pod(または Controller 層)が「ユーザー向け通知」をストリームできるチャネルを持ち、TUI が subscribe する。 - `tracing` とは**別系統**とする。開発者向けログと混ぜない。 - 通知は構造化された型で、少なくとも以下を持つ: - **レベル** (`Warn` / `Error` 以上。`Info` を含めるかは設計時に判断) - **発生源** (Pod 名 / Worker / Compactor / Tool 実行境界 等の列挙) - **メッセージ本文**(人間可読の1〜2行) - **タイムスタンプ** ### TUI 側の表示 - 新着通知はユーザーが見落としにくい位置に**一時的**に表示される(トースト / ステータスバー等、設計時に選択) - **履歴が見られる**こと(キーバインドで通知ペインを開ける等)。履歴はセッション単位で保持。 - 複数通知が短時間に来た場合の重ね合わせ挙動を決める。 - Error と Warn を視覚的に区別する。 ### 既存 warn 発生箇所の置換 - 本チケット完了時点で、既存の `tracing::warn!` のうち**ユーザーに伝えるべきもの**を新チャネルに移行する。`tracing::warn!` 自体は並行して残して良い(デバッグ用途)。 - 移行対象(現時点で確認済み): - compaction 失敗 (`pod.rs`) - ツール出力切り詰め (`worker.rs`) - AGENTS.md 切り詰め / 読み取り失敗 (AGENTS.md 取り込みチケット完了後) ## 設計で決めること - **チャネル実装**: `tokio::sync::broadcast` / `mpsc` / 独自 `NotificationBus` のどれにするか - **tracing subscriber でフックするか、明示的 API を生やすか**: 前者は既存 warn をほぼ無改修で流せるが、レベルや発生源の構造化が難しい。後者は呼び出し側の書き換えが必要だが型が強く出る。 - **UI の提示方法**: トースト / ステータスバー常駐 / 通知ペイン / その組合せ - **ペルシステンス**: 通知履歴を session-store に載せるか、TUI 起動中だけ保持するか ## 完了条件 - Pod 層が型付き通知を発行する API を持つ。 - TUI がその通知を受信して表示・履歴保存する。 - 既存の「ユーザーに伝えるべき `tracing::warn!`」が新チャネル経由で届き、手動テストで TUI 画面上に現れることを確認できる。 ## 範囲外 - tracing ログ基盤そのものの再設計。 - 通知への対話的応答(通知から操作を起こす等)。表示・蓄積のみに集中する。 - 通知の集計・分析・外部送信(Sentry 等)。