Skip to content

コード自動修正における「収束失敗(Failed to Converge)」と無限ループの論理的限界

1. 概要

プログラム(Linter や Formatter、あるいは AI エージェント)によるソースコードの自動修正(Autofix)は、開発の自動化において強力な手段である。 しかし、Python の高速リンターである Ruff(astral-sh/ruff#12897 および #12513)等で発生した「自動修正の無限ループ(収束失敗)バグ」は、複数の独立した修正ルールを同一コードに再帰適用する際、論理的なデッドロック(矛盾)によってプログラム自体が無限ループに陥る設計的限界を示している。 本稿では、自動修正の収束失敗バグのメカニズムと、その背後にあるアルゴリズム的課題について分析する。


2. インシデントの分析:Ruffにおける収束失敗(Failed to Converge)

2.1. 現象:100回のイテレーションによるフリーズ

Ruff にて特定のコードベース(特に __init__.py における相対インポートと __all__ 定義が混在するファイル)に対し、プレビューモードで自動修正(--fix)を実行した際、以下のシステムクラッシュが発生した。

shell
$ ruff check --preview --fix path/to/code
error: Failed to converge after 100 iterations.
This indicates a bug in Ruff.

Ruff は自動修正を適用する際、コードに変更が加わらなくなる(収束する)までループを実行するが、最大リミットである 100 回のループを繰り返してもコードの状態が確定せず、無限ループを検知してクラッシュした。

2.2. 原因:ルール同士の競合(ピンポンデッドロック)

この無限ループは、F401(未使用インポートの自動削除)と F822__all__ 内の未定義シンボルの検出)という、2つの自動修正ルールの競合によって発生した。

  1. ルールA (F401) の実行: __init__.py 内の特定の相対インポート文について、「このモジュール内ではどこからも直接参照されていない」と判断し、未使用インポートとみなして自動的に削除する。
  2. ルールB (F822) の実行: インポートが削除された結果、__all__ リストに記載されているシンボル名が「未定義」となる。ルールBはこれに対し、__all__ の整合性を取るために、あるいは親定義を復元するために**自動的にインポート文を再挿入(または書き換え)**する。
  3. 無限のピンポン: 次のイテレーションで、ルールAが「また未使用インポートが生まれたので削除する」と実行し、ルールBがそれを検知して再び書き戻す。

この消去と復元がミリ秒単位で無限に繰り返され、コードの状態が循環し続けるため、プログラムは永遠に最終状態にたどり着くことができなくなった。


3. 自動コード修正における論理的限界と対策

この問題は、AIエージェントが「リンターのエラーを直そうとしてコードを書き換えるが、フォーマッターがそれを戻してしまい、AIとツールが無限に書き換え合ってトークンを浪費する」という、現代のAI駆動開発における競合ループとも地続きの課題である。

自動修正プログラムがこの論理矛盾(デッドロック)を回避するためには、以下のアルゴリズム的制約が必要となる。

3.1. イテレーションの上限と「諦め(Fail-Safe)」

Ruff が実装しているように、最大適用回数(例: 100回、あるいはAIエージェントの場合は3〜5回)のハードリミットを設け、それを超えた場合は「収束失敗」として処理を安全に放棄(Abort)するセーフティネットが不可欠である。これがない場合、プログラムはCPUを100%消費してフリーズし続ける(ゾンビ化)。

3.2. ルール間の依存関係グラフの定義(トポロジカルソート)

各自動修正ルールをランダムまたは並行して適用するのではなく、ルールの適用順序を依存関係に基づいて厳密に決定(トポロジカルソート)するか、あるいは「ルールAを適用した後は、その副作用を受けるルールBの自動実行をそのターンでは抑止する」といった、干渉制御のロジックが必要とされる。

3.3. 冪等性(Idempotency)の担保

自動修正アルゴリズムにおける理想的な設計は、f(f(x)) = f(x)(一度適用した修正をもう一度適用しても、状態が変わらない)という冪等性を個々のルールが担保することである。ルール単体で冪等性があっても、複数のルールが組み合わさることで f(g(x)) != g(f(x)) となり、状態が循環するリスクを常に考慮しなければならない。


4. 結論

自動修正プログラムにおける「収束失敗(Failed to Converge)」は、プログラムが自己の出力結果を次の入力として読み込み、再帰的に適用し続けるシステムに不可欠な「循環論法の罠」である。 リンターのルール競合から、AIエージェントとリンターの泥沼の書き換えピンポンまで、すべての「自動コード書き換え器」は、この論理的デッドロックを回避するための状態管理と、早期諦め(イテレーションリミット)のセーフティネットをインフラ層に備える必要がある。


5. 参考文献 / 一次情報

Shiori pointer-RAG automation experiment.