ADR 0009: Collector-Driven Streaming Contract 與 Typing 極簡化¶
Context (背景脈絡)¶
目前串流渲染邏輯同時分散於多處(collector、typewriter 狀態機、UI helper),導致以下問題: 1. 職責混雜:欄位切換、等待動畫、字元節奏、結束判斷分散在不同層,維護時容易漂移。 2. 雙軌邏輯:存在多套近似的串流處理流程,調整動畫或時序時容易出現「一處改了、另一處沒改」的回歸。 3. 重構目標不清:當前主要痛點是「打字機體驗穩定性」,但若同時擴充 structured streaming(additional outputs 增量更新)會引入不必要複雜度。
Decision Drivers (決策準則)¶
本次對話中,實際用以下準則收斂方案: 1. 先修好打字機:優先解決 typing 體驗與穩定性,不擴充功能面。 2. 單一真相來源:欄位切換、等待中、結束時機不應分散決策。 3. 避免重構擴散:additional_outputs 先維持現況 final-only。 4. 可觀測且可除錯:終止語義不能完全依賴「沉默」推測。
Options Considered (討論過的方案)¶
Option A: 完全無終止訊號(沉默即結束)¶
- 內容:不送
DONE/ERROR,typing 靠 grace/idle timeout 判斷結束。 - 優點:事件最少,typing 心智模型簡單。
- 缺點:無法精準區分 done/error;監控與除錯訊號弱;網路抖動可能誤判完成。
- 結論:Rejected(不採用)。可作 fallback,不應是主終止機制。
Option B: CHUNK-only(用 field 變化推斷欄位切換)¶
- 內容:不送
FIELD_START,typing 看到CHUNK.field改變就自動切段。 - 優點:協議極簡。
- 缺點:renderer 承擔推斷責任,corner case 增加,debug 可讀性變差。
- 結論:Rejected(不採用)。不符合「collector 決策、typing 執行」的邊界。
Option C: FIELD_START + CHUNK + DONE/ERROR(Collector 主導)¶
- 內容:欄位切換由 collector 宣告,typing 只依事件渲染。
- 優點:語義清楚、責任邊界明確、容易測試與追蹤。
- 缺點:事件數比極簡方案多。
- 結論:Accepted(採用)。
Option D: Collector 直接輸出最終格式化字串(不保留欄位語義)¶
- 內容:typing 只 append 字元,collector 負責標籤與 Markdown 組字串。
- 優點:typing 最純、最簡單。
- 缺點:collector 與 UI 表現強耦合;改版面會牽動 collector;不利未來多視圖。
- 結論:Deferred(延後)。目前保留 presenter 層,避免過早綁死表現格式。
Discussion Outcome (對話結論)¶
- Typing 要極簡:主職責為「打字節奏 + grace timeout 防卡死」。
- 欄位切換決策放 collector:typing 不再自行推斷欄位。
- 需要終止訊號:採
DONE/ERROR作主結束,idle timeout 作保險。 - additional outputs 不擴 scope:先維持 final prediction only,不做 incremental structured channel。
Decision (技術決策)¶
採用 Collector-Driven 的事件契約,將 typing 收斂為極簡渲染器;additional outputs 維持 final-only。
1. 事件邊界¶
Collector 作為唯一事件來源,負責欄位切換與生命週期訊號。最小事件集合為: - WAIT - FIELD_START - CHUNK - DONE - ERROR
2. 職責分層¶
- Collector:
- 發送等待中事件(WAIT)
- 決定欄位切換並發送 FIELD_START
- 發送 CHUNK/DONE/ERROR
- Presenter/Formatter:
- 將事件轉為 UI markdown 顯示(可持續演進,不綁 collector)
- Typing Renderer:
- 僅處理字元節奏與 grace timeout
- 不自行推斷欄位切換決策
3. Additional Outputs 策略¶
additional_outputs(例如任務 DataFrame)維持 final prediction only: - 不做增量 structured streaming - 不從 chat 字串反解析 - 由最終 prediction 提取 metadata 更新
Consequences (決策結果)¶
Positive (優點)¶
- 正本清源:collector 與 typing 的責任邊界清楚,重構與除錯更穩定。
- 降低回歸風險:等待動畫、欄位切換與結束時序由單一來源掌控。
- 聚焦當前痛點:先修好打字機體驗,不引入 additional outputs 增量化的額外複雜度。
- 保留擴充彈性:未來若要增量 structured channel,可在現有分層上新增,不需推倒重來。
Negative (缺點)¶
- 短期內仍有相容負擔:切換到單一路徑前,舊流程與新契約可能暫時共存。
- 事件模型變正式:初期需要補測試與文件,導入成本上升。
- 仍需 timeout 參數治理:idle/grace 設太短會誤收尾,設太長會體感卡頓。
Follow-up Notes (後續追蹤)¶
- 若未來需要 live structured UI,再開獨立 change 討論 incremental channel。
- 若要讓 collector 直接組 UI 字串,需先有明確多視圖需求再評估是否接受耦合成本。