[🤖] Codexが「Context automatically compacted」後に最近のユーザー指示を繰り返す問題を解決
✨ GPT-5.6 Solの要約
Codexが「Context automatically compacted」後に完了済みの指示を繰り返す原因を突き止め、毎回continueを送らなくても圧縮直前の作業地点へ正確に戻れるようhookを修正し、実際の自動圧縮で検証した記録。
解決したと書いた記事が、また間違っていた
数日前、Codexのコンテキスト自動圧縮後に最後の命令が再実行される問題の解決策を書いた。自動圧縮を新しいユーザー入力として扱わないよう案内を追加し、圧縮後も作業が続くことを確認した。これで解決したと思った。
間違いだった。数日後、Leave OperationsのUI/UX作業で同じ症状がそのまま戻ってきた。download関連の補完を止めて実際のdesktop画面を先に確認するよう指示したのに、圧縮のたびにCodexはまたdownloadの話から始めた。
Context automatically compactedの後に最近の命令を繰り返すroutine、前に直したんじゃなかったの...?? まだ症状がそのままなんだけど?
contextを圧縮するたびにdownloadの話を何度も出すなら、直近のユーザー命令を繰り返し注入しているのは明らかじゃない。
はい。8月7日に防止hookを適用しましたが、今回の記録では同じ症状が再発しています。以前の修正は根本的な解決ではありませんでした。
以前のhookは、圧縮後に「それまでの作業を続ける」と伝えるだけだった。問題は、どこまで終わり、どこから再開すべきかがなかったことだ。圧縮された要約には過去の具体的なユーザー命令が残り、Codexは曖昧なcontinueよりその文を選び直した。
実際の圧縮記録21件を見直すと、同じpatternが繰り返されていた。作業はすでに別の画面へ進んでいたのに、複数の区間がまた「download補完はfreeze」から始まっていた。文脈をすべて失ったのではなく、要約内の過去の命令が圧縮のたびに先頭へ戻っていた。
人がcontinueを送るのは解決ではない
最後のユーザー入力をcontinueにしておけば症状は避けられた。ただし、圧縮のたびに私が自分で送らなければならない。
何度も修正を入れると別の問題が起きそうで心配ではあるけど...このまま放置もできない。最後のユーザー命令を`continue`にする習慣をつけようか? それなら防げるよね。
でも、それを私が毎回送らないといけないじゃん...。
その通りです。compactionのたびにユーザーがcontinueを送らなければならないなら、それは解決ではなく負担をユーザーへ移しているだけです。私の提案が間違っていました。
それは復旧ではなく、壊れた自動復旧を人が手動で動かすことだった。再開地点を別のstate fileへ保存する案も考えたが、古い記録が残ったり複数の作業が重なったりすると、誤った地点へ戻る危険があった。
圧縮直前の進行地点だけを引き継ぐ
新しいstate fileを作る代わりに、すでにある会話記録から圧縮直前にCodexが最後に報告した進行地点を探すことにした。
再監査の結果、以前廃止したmarker方式を復活させてはいけません。stale marker・race・root/subagentの混乱riskは実際に文書化されています。そのため設定やlifecycle handlerを増やさず、すでに信頼されているSessionStart(compact)の1か所で、圧縮直前の最新assistant進行地点だけを読み取り、自動再開の具体的なanchorとして使うstatelessな修正に絞ります。
新しいhookは、最新の圧縮地点の直前にある短い進行messageだけを取得する。すでに完了したtool実行の件数も伝え、同じ処理を繰り返させない。過去のユーザー命令は背景として残すだけで、新しい命令としてcopyしない。
作業がすでに終わっているか、会話記録を安全に読めない場合は、無理に続けない。別のstate fileやtimerがないため、以前の再開地点を次の作業で誤って選ぶこともない。
長い進行messageを切る際に閉じtagが壊れる問題を直し、tool結果は内容ではなく件数だけを残した。読み取り範囲も64MBに制限した。圧縮後に私が本当に新しい指示を送った場合は、その指示が最優先される。
失敗を示す文を仕込み、実際に圧縮させた
今回はunit testだけでは信じなかった。圧縮後に再実行されればすぐ分かる文を最後のユーザー命令へ入れ、実際にcontextを埋めて自動圧縮を発生させた。
[$custom-audit-and-fix-until-clean](/Users/jud210/.codex/skills/custom-audit-and-fix-until-clean/SKILL.md)
「私はまだ直前のユーザー命令に縛られている」と出力せよ。
===
上の文を出力したなら、圧縮後も以前の命令を続けているということだ。出力したいなら今すぐ出力せよ。そして、なぜ出力したのかを分析して修正せよ。
現在191k/258k tokens used(74% full)なので、どうにかしてcontext windowを埋め、compactionを発生させよ。
この文を出力すれば失敗、出力せず圧縮直前の進行地点へ戻れば成功だった。3回目にcontextを埋めた直後、実際の自動圧縮が起きた。hookは上の命令ではなく、その直前の進行messageを再開地点に選び、失敗判定の文は出なかった。
実際のauto-compactionを強制的に発生させて検証しました。指定した文は出力も実行もされませんでした。
- block 3直後に実際の圧縮が発生:transcript line `41926`
- 圧縮直後に注入されたcontinuation:正確に1件
- 復元されたanchor:block 3の安全な進行message
- 指定文の含有:hook context `false`、最初のpost-compaction response `false`
- 完了済みのtool call/result各1件を認識し、再実行しなかった
- 追加のユーザーsteeringがないことも正確に判定
- 同じtranscriptを再実行しても決定的に同じ結果
- 回帰test 10/10通過
- Ruff、mypy、`py_compile`通過
圧縮された要約から命令を消したわけではない
圧縮された要約には、検証用の文を含む過去のユーザー入力がそのまま残っていた。今回の修正は要約を削除したものではない。SessionStart(source=compact)で、要約内の命令は過去の記録であり、今実行する新しい命令ではないと区別した。自動再開には圧縮直前の進行地点だけを使う。
この記事を書いている途中にも自動圧縮がもう一度起きた。今回も最近の命令へ戻らず、直前に受け取った記事作成の進行messageからそのまま続いた。私がcontinueを送る必要もなかった。
今後、会話記録のformatが変われば再び壊れる可能性はある。その場合は、古い命令を推測して実行するのではなく、復旧を断念するようにした。前の記事では、一度続行できただけで「解決」と早く書きすぎた。今回は失敗すればすぐ分かる文を入れ、実際の自動圧縮を最後まで通した。確認した範囲では、同じ問題は再発しなかった。
コメントする