Skip to content

Handoff reliability + read_output screen view (plan 3712ddc) - #42

Merged
nananek merged 4 commits into
masterfrom
plan/handoff-reliability-read-output
Aug 11, 2026
Merged

Handoff reliability + read_output screen view (plan 3712ddc)#42
nananek merged 4 commits into
masterfrom
plan/handoff-reliability-read-output

Conversation

@nananek

@nananek nananek commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Implements the two plans in tmp/:

  • handoff-reliability-plan.md: handoff events must never be lost between handoff_to_orchestrator and wait_for_handoff.
    • takeHandoff is now connection-aware: an event is only dequeued when the waiting connection is alive (isAlive guard), a superseded waiter reclaims any event it had already claimed (re-queue instead of loss), superseded/stale waiters settle as {timedOut:true} (the documented shape, not the old undocumented {orphaned:true}), and onOrchestratorExit settles pending waiters instead of leaving 15-minute zombies.
    • The broker now builds control/handoff servers with per-connection deps (connectionIsAlive), threaded into waitForHandoff.
    • repo_info: the production broker facade previously lacked getGroup, making repo_info fail in production with "deps.groupManager.getGroup is not a function" while full-module unit tests stayed green. Since then master (PR Fix copilot --mcp-config injection and repo_info facade mismatch #39) fixed this with a better design (getGroupCwd -- cwd only, no group internals exposed); this branch merged master and adopted that design, keeping the facade-completeness test seams (getGroupManagerApi + wire-level repo_info test) so the mismatch class cannot recur.
  • read-output-screen-plan.md: read_output cannot reconstruct a TUI's current screen from raw bytes (spinners redraw in place via cursor moves/line erases), so the server now keeps a lightweight virtual screen per session (screenModel.js).
    • read_output gains screen (current visible rows), screenAlt, screenTruncated, screenIdleMs (ms since the screen last visibly changed -- the reliable busy/idle signal); get_tab_status gains screenIdleMs.
    • text is now cut at a boundary that never splits an escape sequence (no bare control bytes leak past the 16KB cap), and dangling escapes at the end of the stream are trimmed.

Includes a merge of the current master (BUN_TMPDIR fix, notify attribution/discipline).

- handoff: groupManagerApi の getGroup 欠落 (repo_info 失敗の確定原因) と、
  takeHandoff のウェイターが接続死活を知らないことによるイベント喪失レースを修正する計画。
- read_output: 生バイト連結では復元できない TUI 差分描画を、軽量仮想画面モデルと
  画面変化ベースの idle 時間 (screen / screenIdleMs) で観測できるようにする計画。
…2ddc)

handoff (問題1):
- groupManagerApi に getGroup を追加 (repo_info の TypeError 確定原因の修正)。
  facade とツールの対応をコメントで明示し、テストは実 facade
  (getGroupManagerApi) 経由に変更 -- 本番/テストの deps 形状ズレの再発を防止。
- takeHandoff に opts.isAlive (接続死活) を追加: 死んだ接続のウェイターは
  イベントを dequeue しない。mcpBroker が接続ごとの死活クロージャを注入
  (SocketTransport 生成後に buildServer(identity, connectionIsAlive))。
- supersede 時に stale が消費済みのイベントをキューの先頭へ戻す再キュー化
  (参照一致で二重 re-queue 防止)、stale への返値を {orphaned:true} から
  {timedOut:true} へ統一。onOrchestratorExit で pendingTakes を settle
  (15 分のゾンビウェイターを残さない。イベントはキューに残る)。
- テスト: facade 経由 deps 化、supersede 再キュー / isAlive 非消費 /
  onOrchestratorExit settle、wire レベルの接続死後イベント到達 + repo_info
  (isError なし) を追加。

read_output (問題2):
- 軽量仮想画面モデル server/ws/screenModel.js を新設 (ANSI サブセット解釈、
  200x80 有界、chunk 跨ぎエスケープ保持、TextDecoder stream で UTF-8 跨ぎ対応)。
- sessionManager が出力 chunk ごとに screen を並行維持し、
  screenLastChangeAt (画面変化ベース) を更新。read_output に screen /
  screenAlt / screenTruncated / screenIdleMs を追加、get_tab_status に
  screenIdleMs を追加 (idleForMs は互換のため残す)。
- text の 16KB キャップをエスケープシーケンスを割らない境界でカット
  (plan の chunk 粒度案より厳密: 途中切断による制御文字漏れを除去)。
- テンプレート/ツール説明/README を新 API と handoff 保証に更新。

検証: npm test 318 tests / 317 pass / 0 fail (1 skipped)、
npm run build --workspace=client 成功。実シェルセッションで screen が
スピナー最終フレームを表示し screenIdleMs が増加することを確認。
E2E (playwright) はこの環境でブラウザバイナリが取得できず起動不可
(MS CDN ゲートウェイエラー、全失敗がブラウザ起動エラー) のため未実施。
cleanTextCut cut at a sequence-safe boundary, but a stream that ends
mid-sequence (a pty chunk boundary split the last escape) still leaked
the bare partial sequence through stripAnsi into the text view. Trim
the dangling escape from the tail in both the capped and uncapped
paths; regression tests cover both.
@nananek nananek closed this Aug 11, 2026
@nananek nananek reopened this Aug 11, 2026
master が PR #39 で同一の repo_info facade 問題を別設計 (getGroupCwd:
group 内部を露出せず cwd のみ返す) で先行修正済みのため、マージでその
設計を採用。facade への getGroup 追加を撤去し、plan のフェーズ1を
追記更新。BUN_TMPDIR (PR #41) / notify 属性・規律 (PR #37-40) も取り込み。
@nananek
nananek merged commit b67d4e7 into master Aug 11, 2026
4 checks passed
@nananek
nananek deleted the plan/handoff-reliability-read-output branch August 11, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant