Repository navigation
fix: Cockpit の真っ黒タイル・別エージェントへの誤送信・端末の大きさ + CI を 5 分予算へ - #36
Merged
Merged
Conversation
利用者からの報告 2 件を直す。どちらも「複数エージェントを起動したときだけ」出る。 ## 1. 4 体以上でタイルが真っ黒 (起動しているか分からない) ミニ端末は PTY を縮めない代わりに `grid_rect` が受け皿になっているが、 **グリッドの最終行**を枠の下端に合わせていた。代替画面をやめて出力を積む CLI は起動直後グリッドの上のほうしか使わないので、下端を合わせると **空行だけが映る**。 実測 (実 PTY・40 行のグリッド・下端の空き): claude 2.1.234 … 22 行 (中身 0〜17 行 / カーソル 14 行) codex … 31 行 (中身 0〜8 行 / カーソル 8 行) gemini … 0 行 (画面を埋めるので無事) タイルに 15 行しか入らないと映るのは 25〜39 行目 = 全部空行。 4 体以上でタイルが縮むと必ず出る。 `live_row_count` を新設し、最終行ではなく**生きている最下行**を下端へ 合わせる。カーソルは中身の 1 つ下までしか追わない (描き終えて隅へ寄せる CLI を追うと、結局は空行の下半分を映してしまう)。画面を埋める CLI では 1 ピクセルも変わらない。 ## 2. Codex を選んだのに Claude へ文章が行く egui 0.29 の `Button` / `SelectableLabel` は `allocate_*` の**自動採番**から ID を作る。エージェントのタブ列は `[● 印][タブ][◆ 未読][⏳ 制限]` の並びで、 **未読印は出力のたびに付いたり消えたりする**。egui は押した (press) フレームの ID を離した (release) フレームで照合するので、その 2 フレームの 間に印が増減すると**押したのとは別のタブが選ばれる**。 ヘッドレスで再現した (`e2e::widget_id_shift_tests`): **tab2 を押したのに tab3 が選ばれる**。選び直しは入力先そのものなので、 打った文章は隣のエージェントへ行く。 同じ形が Cockpit のタイル見出し (✕ を押して ⟳ が発火) と 💬 セッション 一覧にもある。さらに Cockpit のタイル枠の ID が**添字**由来だったため、 1 体閉じると添字がずれて別セッションの枠になる経路もあった。 タブ・タイル・サイドバー行の ID を**セッション ID から**作る。ボタンも 1 個ずつ ID を固定する (行の中の条件付きボタン 🛡 / ⊞ で同じずれが起きる)。 ## 番人 追加 6 本。**全部わざと壊して赤になることを確認した**: terminal::tests::空の下半分ではなく生きている最下行を下端に合わせる terminal::tests::生きている最下行はカーソルと中身の遠いほう e2e::widget_id_shift_tests::自動採番のままだと押したのと違うタブが選ばれる e2e::widget_id_shift_tests::行の中身が増減しても押したタブが選ばれる app::ui_wiring_tests::エージェントタブのidはセッションidから作る app::ui_wiring_tests::行ごとのボタンのidはセッションidから作る 再現テストだけだと実装が元へ戻っても緑のままなので、**実際の配線を読む 番人**と対にしてある。 検証: tools/verify.sh --all (4948 件緑) / --lint (clippy 緑・警告ゼロ) / tools/windows-check.sh 緑。Linux は Docker 未起動のため未確認。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
利用者から「テストが 13 分終わらない」。**測ってから直した。** ## 何が起きていたか (run 32078628866) 止まっていたのは cargo ではなく **`msrv` ジョブの apt が 13 分無反応**。 同じ瞬間に走っていた `fast (ubuntu)` の**同じ apt は 58 秒**で終わっている — ミラー 1 本が黙って詰まっただけだった。素の apt は HTTP に既定の時限を 持たないので、詰まったミラーを掴むと**ログに 1 バイトも出さずに**ジョブの 上限 (15 分) まで待つ。 同じ 2 行がワークフロー 3 本に**計 10 か所**複製されていたので、片方だけ 直しても次はもう片方で固まる。 ## 実測 (6 run ぶんの wall-clock) fast (windows) 321 / 387 / 387 / 389 / 470 / 496 秒 … **6 回とも 5 分超** fast (macos) 194 / 204 / 235 / 266 / 270 / 313 秒 fast (ubuntu) 209 / 218 / 219 / 221 / 227 / 244 秒 msrv (apt が詰まると 900 秒 = 上限) mobile screen (一度 900 秒 = 上限) Windows の内訳は**テストの段だけで 390 秒**、固定費 100 秒。nextest は テスト 1 件 = 1 プロセスなので、プロセス生成が高価な Windows では 4,950 件 ぶんの起動費が丸ごと効く。**1 台では削れない。** ## 直したこと 1. **Windows の fast を 3 分割** (`--partition count:M/3`)。固定費は各シャードに 残るが並列なので wall-clock は max であって sum ではない: 100 + 390/3 ≒ 230 秒。 ubuntu / macos は 1 台のままで予算内なので分けない (macOS は課金 10 倍)。 `vendored vt100 tests` は先頭シャードだけが回す。 2. **apt を道具 1 本に寄せて時限を入れる** (`tools/ci-linux-deps.sh`)。3 段: apt 自身の `Acquire::*::Timeout=15` + `Retries=3` / コマンドごとの外側の時限 / 試行回数の上限。`timeout(1)` が無い環境でも**素の sh だけ**で同じことをする (外部道具に頼ると、道具が無い環境で時限が黙って消える)。 ワークフロー 3 本・計 10 か所の複製を全部これへ差し替えた。 3. **`--self-test` でわざと固まらせ、時限が効くことを証明する。** 空回りする時限を残さない (実際に「時限切れ 124 を握り潰して rc=0 と出る」 バグがこれで見つかった — `if …; then return 0; fi` の後で `$?` を読んでいた)。 4. **timeout-minutes を実測の 2〜3 倍へ**: 15 分 → 6〜10 分。 15 分のままだと「5 分予算」と矛盾し、固まったときに 15 分待たされるだけ。 mobile screen は 3 段の順序 (`ZV_DEADLINE_MS < ZV_WALL_S < timeout-minutes`) を保ったまま 10/11/15 分 → 6/7/8 分。 ## 番人 (追加 3 本・全部わざと壊して赤を確認) cli::tests::ciのaptは時限つきの道具越しに呼ぶ cli::tests::ciのジョブ上限は予算の範囲に収まっている cli::tests::windowsのテストは分割して五分予算に収める 検証: actionlint 全ワークフロー緑 / tools/verify.sh --all 4951 件緑 / --lint (clippy) 緑・警告ゼロ。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
利用者からの報告 2 件。どちらも「端末の大きさを決める規則」1 か所が原因。 ## 1. 途中で全画面表示されなくなる `terminal::draw` に一方向のラッチ (`size_owned`) があった。ねらいは往復の リサイズを避けることだが、**一度でも下部パネルが低い高さで描くと、その 大きさが永久に固定される**。その後 Cockpit を全画面で開いても端末は 小さいままなので、`grid_rect` が最終行を下端へ合わせて**枠の上 3/4 が 空白**になる (変更タブの後に起きやすいのは、あちらが端末パネルを畳んで 高さを変えるため)。 ラッチが守っていた「縮めると CLI が会話を描き直して履歴が二重になる」は **実 PTY で計ると再現しなかった** (claude 2.1.234 / `CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1`、起動が落ち着いた後の再送回数): 動かさない … 0 回 (44B) / 50→15 行 … 0 回 (3.0KB) / 15→50 行 … 0 回 (4.1KB) Ink の静的出力は一度きりなので、描き直されるのは入力欄まわりだけだった。 広げる側と縮める側の費用もほぼ同じ。ラッチを外し、ライブ枠は**いつでも 広げてよい**ことにした。 ## 2. 看板を出していないときの幅が他のビューへ残る 看板のライブペインは `main_rects` の作りから**「全画面 = 窓幅いっぱい」と 「分割 = 細い」の 2 通りの幅**を持つ。従来はライブ枠が桁数も `cols.max(cur_c)` で持ち越していたので、片方の幅が Cockpit や下部パネルへ そのまま残り、文字が右へ見切れる。 **横は必ずいま描いている枠に合わせる。** 見切れは UI の原則 (「どの幅でも見切れない」) に反するので持ち越さない。縦は従来どおり ライブ枠からは広げるだけ — 足りないぶんは `grid_rect` が 「生きている最下行」を映して吸収する。 ## 規則は純関数 1 本に `terminal::next_pty_size(cur, frame, owner)` へ切り出し、表で固定した。 2 か所で計算すると、片方だけ直しても静かにずれる。 ## 番人 (追加 3 本・全部わざと壊して赤を確認) terminal::pty_size_tests::主は枠のとおりに持つ terminal::pty_size_tests::ライブ枠は縦を縮めない terminal::pty_size_tests::横は他のビューの幅を持ち越さない `app::deck_wiring_tests::ライブ枠は端末の大きさを持たない` も新しい規則へ 更新し、ラッチが戻ったら赤くなるようにした (見るのは `draw` の中だけ・ コメント行は除く — 範囲を広げると経緯の文章を拾って空回りする)。 検証: tools/verify.sh --all 4954 件緑 / --lint (clippy) 緑・警告ゼロ / tools/windows-check.sh 緑。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
前のコミットで Windows は 8m16 → 3m50〜4m36 に収まったが、 **macos が 5m23 で残っていた** (テストの段 282 秒)。この段は 173〜282 秒と ばらつきが大きく、1 台では予算をまたぐ。 macOS ランナーは課金 10 倍だが、**固定費が 40 秒しかない**ので 2 台にしても 合計時間はほぼ変わらないまま wall-clock が半分になる。 ubuntu は 1 台で 2m49 と余裕があるので分けない。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
利用者からの報告 4 件 + CI の待ち時間。すべて 測ってから 直した。
1. Cockpit のタイルが真っ黒 (4 体以上で発症)
ミニ端末は PTY を縮めない代わりに
terminal::grid_rectが受け皿になっているが、グリッドの最終行を枠の下端に合わせていた。代替画面をやめて出力を積む CLI は
起動直後グリッドの上のほうしか使わないので、最終行を下端に合わせると
空行だけが映る。
実測 (実 PTY・40 行のグリッド):
タイルに 15 行しか入らないと映るのは 25〜39 行目 = 全部空行。gemini だけ
無事だったのは画面を埋めるから。
直し方:
live_row_countを新設し、最終行ではなく 生きている最下行 を下端へ合わせる。カーソルは中身の 1 つ下までしか追わない (描き終えて隅へ寄せる
CLI を追うと、結局は空行の下半分を映してしまうため)。
2. Codex を選んだのに Claude へ文章が行く
egui 0.29 の
Button/SelectableLabelはallocate_*の 自動採番 からID を作る。タブ列は
[● 印][タブ][◆ 未読][⏳ 制限]の並びで、未読印は出力のたびに付いたり消えたりする。egui は押した (press) フレームの ID を離した
(release) フレームで照合するので、その 2 フレームの間に印が増減すると
押したのとは別のタブが選ばれる。
ヘッドレスで再現した (
e2e::widget_id_shift_tests) — tab2 を押したのにtab3 が選ばれる。選び直しは入力先そのものなので、打った文章は隣の
エージェントへ行く。同じ形が Cockpit のタイル見出し (✕ を押して ⟳ が発火) と
💬 セッション一覧にもあった。さらに Cockpit のタイル枠の ID が 添字 由来
だったため、1 体閉じると添字がずれて別セッションの枠になる経路もあった。
直し方: タブ・タイル・サイドバー行の ID を セッション ID から 作る。
行の中の条件付きボタン (🛡 / ⊞) でも同じずれが起きるので、ボタンも 1 個ずつ
ID を固定する。
3. 途中で全画面表示されなくなる
terminal::drawに一方向のラッチ (size_owned) があり、一度でも下部パネルが低い高さで描くと、その大きさが永久に固定される。その後 Cockpit を全画面で
開いても端末は小さいままなので、
grid_rectが最終行を下端へ合わせて枠の上 3/4 が空白になる。
ラッチが守っていた「縮めると CLI が会話を描き直して履歴が二重になる」は
実 PTY で計ると再現しなかった (claude 2.1.234 /
CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1、起動が落ち着いた後の再送回数):Ink の静的出力は一度きりなので、描き直されるのは入力欄まわりだけだった。
ラッチを外し、ライブ枠は いつでも広げてよい ことにした。
4. 看板を出していないときの幅が他のビューへ残る
看板のライブペインは
kanban::main_rectsの作りから 「全画面 = 窓幅いっぱい」と「分割 = 細い」の 2 通りの幅 を持つ。従来はライブ枠が桁数も
cols.max(cur_c)で持ち越していたので、片方の幅が Cockpit や下部パネルへそのまま残り、文字が右へ
見切れる。
横は必ずいま描いている枠に合わせる。 見切れは UI の原則 (「どの幅でも
見切れない」) に反するので持ち越さない。縦は従来どおりライブ枠からは広げるだけ。
規則は純関数
terminal::next_pty_size(cur, frame, owner)へ切り出して表で固定した(2 か所で計算すると、片方だけ直しても静かにずれる)。
5. CI が 13 分終わらない → 5 分予算へ
止まっていたのは cargo ではなく
msrvジョブの apt が 13 分無反応。同じ瞬間の
fast (ubuntu)は 同じ apt が 58 秒だった — ミラー 1 本が黙って詰まっただけ。素の apt は HTTP に既定の時限を持たないので、詰まったミラーを
掴むと ログに 1 バイトも出さずに ジョブの上限まで待つ。
実測 6 run の wall-clock:
直したこと
--partition count:M/N)。Windows はテストの段だけで 390 秒、固定費 100 秒。nextest はテスト 1 件 =
1 プロセスなので、プロセス生成が高価な Windows では 4,950 件ぶんの起動費が
丸ごと効き、1 台では削れない。
tools/ci-linux-deps.sh)。3 段:apt 自身の
Acquire::*::Timeout=15+Retries=3/ コマンドごとの外側の時限 /試行回数の上限。
timeout(1)が無い環境でも 素の sh だけ で同じことをする。ワークフロー 3 本・計 10 か所の複製を全部これへ差し替えた。
--self-testでわざと固まらせ、時限が効くことを毎回証明する。これで「時限切れ 124 を握り潰して rc=0 と出る」バグが実際に見つかった。
「5 分予算」と矛盾し、固まったときに 15 分待たされるだけ。
結果 (この PR の run):
番人 (追加 12 本)
全部わざと壊して赤になることを確認した。 空回りする検査は残していない。
terminal::tests::空の下半分ではなく生きている最下行を下端に合わせるterminal::tests::生きている最下行はカーソルと中身の遠いほうterminal::pty_size_tests::主は枠のとおりに持つterminal::pty_size_tests::ライブ枠は縦を縮めないterminal::pty_size_tests::横は他のビューの幅を持ち越さないe2e::widget_id_shift_tests::自動採番のままだと押したのと違うタブが選ばれるe2e::widget_id_shift_tests::行の中身が増減しても押したタブが選ばれるapp::ui_wiring_tests::エージェントタブのidはセッションidから作るapp::ui_wiring_tests::行ごとのボタンのidはセッションidから作るcli::tests::ciのaptは時限つきの道具越しに呼ぶcli::tests::ciのジョブ上限は予算の範囲に収まっているcli::tests::windowsのテストは分割して五分予算に収める再現テストだけだと実装が元へ戻っても緑のままなので、実際の配線を読む番人と
対にしてある。
検証
tools/verify.sh --all… 4954 件緑tools/verify.sh --lint… clippy 緑・警告ゼロtools/windows-check.sh… 緑actionlint… 全ワークフロー緑🤖 Generated with Claude Code