Skip to content

fix(polling): 一括移行で abandoned の poller の停止が、移ってきた dedup の状態を消さないようにする (#3553) - #3657

Merged
Kewton merged 3 commits into
developfrom
feature/3553-worktree
Oct 13, 2026
Merged

Kewton merged 3 commits into
developfrom
feature/3553-worktree

Conversation

@Kewton

@Kewton Kewton commented Oct 13, 2026

Copy link
Copy Markdown
Owner

整合性レビューの指摘(前のコミットによる悪化)への対応。

事象: A:x が paused、B:x が稼働中で CLI ツールが解決できない(abandoned)、移行が
A→B・B→C のとき、前のコミットは A:x の paused の状態を B:x へ書いた後に abandoned の
B:x を stopPollingByKey で止めていた。停止は B:x のキャッシュをすべて消すため、B:x には
pause の印だけが残り、ハッシュ・連続の数・再照会が失われ、/respond で再開すると保存済みの
画面を再保存しうる。前のコミットより前は、B:x の停止の後に paused の状態を書いていた。

直し方: abandoned の停止を Phase 1 の直後、paused の chain の収集と dedup の一括書き込みの
前へ移した。abandoned のキーは move の移送元にならない(moves から外している)ので、
先に止めても退避すべき移送元は消えない。paused の chain は停止の後に集める(前のコミット
より前と同じ順)ため、停止が終わらせた pause は運ばない。

前のコミットの本文の訂正: 「同じキーが稼働中と paused の両方にある場合だけ結果が変わる」は
誤り。上のように、paused の移送先が別キーの abandoned の poller と重なるだけで状態が失われて
いた。この順の入れ替えで、同じキーの場合の振る舞いも前のコミットより前に戻る。また前のコミットの
「本文に無い指摘」の 1 件目(abandoned の停止が移ってきた状態を消す)は、このコミットで直した。

テスト(response-poller-migrate-batch-3553.test.ts に追加):

  • 陽性: 上の組み合わせで B:cx に A:cx の元のハッシュ・連続の数・再照会と pause の印がそろって
    残り、B の解決できる稼働中の poller(B:claude)の状態は C へ移る。response-poller-core.ts の
    修正だけを外した状態で落ちることを確認(14 件中 1 件失敗)、戻して通る。
    なお abandoned の B:cx 自身の状態は従来どおり停止で消え、C へは移らない(poller を止めるため)。
    「B の元の稼働中の状態は C へ移る」は、同じ worktree の解決できるインスタンスで確かめた。
  • 陰性: abandoned の無い A↔B・A→B→C の既存テストは変更なしで通る。abandoned の旧キーで
    移送先にならないものは今どおり消える。
  • npx vitest run tests/unit/lib/polling tests/unit/lib/session/worktree-session-reconcile.test.ts
    tests/unit/guards tests/unit/docs: 90 files / 1428 tests 通過。npm run lint / npx tsc --noEmit 通過。

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

Refs #3553

Kewton and others added 2 commits October 13, 2026 13:49
migrateResponsePollerWorktreeIds は Phase 1 でタイマーをバッチ全体で止めていたが、
dedup の Map の付け替え(renamePromptHashCacheKey / renameResponseHashCacheKey /
renamePromptDedupSkips、paused の chain の renameResponseHashCacheKey)は移送元ごとに
1 件ずつ行っていた。A↔B では A に A の元の状態が戻って B が空になり、A→B→C では
B の状態が上書きされていた(Issue の記述どおり。新しいテストで直す前に 5 件落ちることを確認)。

決めたこと:
- 退避の形: Map ごとに「バッチ API」を足した。renameResponseHashCacheKeys /
  renamePromptHashCacheKeys / renamePromptDedupSkipsBatch は、全移送元の状態を
  take(読んで消す)してから put する。状態を 1 レコードにまとめて順に移すだけでは
  上書きは防げないため、2 段(全件退避→全件書き込み)にした。
- 共通化: 単独の rename は同じ take/put の 1 件版にした(prompt 側と #1695 は
  バッチ API に 1 件を渡すだけ)。単独の振る舞いは変えない — response の単独 rename
  では移送先にあった再照会を残す従来の動きを、put の引数で保っている。
- 稼働中と paused の chain は 1 回の renameResponseHashCacheKeys にまとめた。
  paused の chain の収集を Phase 1 の後・書き込みの前へ移し、pause マークも全件
  消してから全件足す。
- #2399 の再照会はハッシュ無しでも移し、旧キーに残さない。バッチではハッシュが
  着いた移送先の再照会を、移送元のもので置き換えるか消す(別ターンの再照会を混ぜない)。
  連続数は #3552 の規則(ハッシュを置き換えたら移送元のもので置き換え、無ければ消す)のまま。
- 移送元が何も持たない・同じキーへの rename は移送先に触らない。

確かめたこと:
- 新規 tests/unit/lib/polling/response-poller-migrate-batch-3553.test.ts:
  陽性(A↔B、A→B→C、稼働中×paused、paused×paused、ハッシュ無しの再照会)は直す前に
  落ち、直した後に通る。陰性(同じキー、状態の無いキー、単独 rename の従来どおり、
  移送先の別ターンの再照会を混ぜない)は通る。実ファイルは触らないため tmpdir は不要。
- npx vitest run tests/unit/lib/polling tests/unit/lib/session/worktree-session-reconcile.test.ts
  tests/unit/guards tests/unit/docs: 90 files / 1426 tests 通過(既存テストは変更なし)。
- npm run lint / npx tsc --noEmit / node scripts/changelog-fragments.mjs check: 通過。

対になる場所を探した結果:
- rename の呼び出し元は src/lib/polling/response-poller-core.ts のみ(src 全体を grep)。
  response-poller.ts は単独 rename を再エクスポートするだけで、変更不要。
- src/cli/types/ に該当型なし。docs/ には module-reference.md 以外の記述なし(断片で追記)。
- 古い動きを固定しているテストは無かった。

本文に無い指摘:
- src/lib/polling/response-poller-core.ts: abandoned(CLI ツールが解決できない)poller の
  stopPollingByKey は dedup の書き込みの後に走るため、ある移送先キーが abandoned の旧キー
  と同じだと、移ってきた状態をその場で消す。並び順は今回変えていない(未再現)。
- src/lib/polling/pending-scraped-response.ts: #2436 の保留中の取り込みは pollerKey で
  持つが、migrate では移しも flush もしない(abandoned だけ stopPollingByKey 経由で flush)。
  影響は未確認。
- 一括移行で paused の chain の収集が abandoned の停止より前になった。同じキーが稼働中と
  paused の両方にある場合だけ結果が変わるが、通常は両立しない。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#3553)

整合性レビューの指摘(前のコミットによる悪化)への対応。

事象: A:x が paused、B:x が稼働中で CLI ツールが解決できない(abandoned)、移行が
A→B・B→C のとき、前のコミットは A:x の paused の状態を B:x へ書いた後に abandoned の
B:x を stopPollingByKey で止めていた。停止は B:x のキャッシュをすべて消すため、B:x には
pause の印だけが残り、ハッシュ・連続の数・再照会が失われ、/respond で再開すると保存済みの
画面を再保存しうる。前のコミットより前は、B:x の停止の後に paused の状態を書いていた。

直し方: abandoned の停止を Phase 1 の直後、paused の chain の収集と dedup の一括書き込みの
前へ移した。abandoned のキーは move の移送元にならない(moves から外している)ので、
先に止めても退避すべき移送元は消えない。paused の chain は停止の後に集める(前のコミット
より前と同じ順)ため、停止が終わらせた pause は運ばない。

前のコミットの本文の訂正: 「同じキーが稼働中と paused の両方にある場合だけ結果が変わる」は
誤り。上のように、paused の移送先が別キーの abandoned の poller と重なるだけで状態が失われて
いた。この順の入れ替えで、同じキーの場合の振る舞いも前のコミットより前に戻る。また前のコミットの
「本文に無い指摘」の 1 件目(abandoned の停止が移ってきた状態を消す)は、このコミットで直した。

テスト(response-poller-migrate-batch-3553.test.ts に追加):
- 陽性: 上の組み合わせで B:cx に A:cx の元のハッシュ・連続の数・再照会と pause の印がそろって
  残り、B の解決できる稼働中の poller(B:claude)の状態は C へ移る。response-poller-core.ts の
  修正だけを外した状態で落ちることを確認(14 件中 1 件失敗)、戻して通る。
  なお abandoned の B:cx 自身の状態は従来どおり停止で消え、C へは移らない(poller を止めるため)。
  「B の元の稼働中の状態は C へ移る」は、同じ worktree の解決できるインスタンスで確かめた。
- 陰性: abandoned の無い A↔B・A→B→C の既存テストは変更なしで通る。abandoned の旧キーで
  移送先にならないものは今どおり消える。
- npx vitest run tests/unit/lib/polling tests/unit/lib/session/worktree-session-reconcile.test.ts
  tests/unit/guards tests/unit/docs: 90 files / 1428 tests 通過。npm run lint / npx tsc --noEmit 通過。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Kewton Kewton added the bug Something isn't working label Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant