OpenHands、ランタイム API の競合状態を Quint で検証し修正
本文の状態
日本語全文を表示中
詳細モードで約10分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
OpenHands Engineering
OpenHands Engineering は、ランタイム API の競合状態バグを解決するために形式検証ツール Quint を活用し、本番環境での再発を防ぐ確実な修正コードの提出に成功したと発表した。
AI深層分析を開く2026年8月4日 14:32
AI深層分析
キーポイント
競合状態によるアラート問題
OpenHands のオンコールエンジニアは、ランタイム API の競合状態により「複数の有効なポッド」のアラートが頻発し、手動削除のリスクから待機せざるを得ない状況に陥っていた。
Quint による形式検証の活用
開発者は DataDog ログで原因を特定した後、初期修正案が不完全であることを Quint のモデル解析によって事前に検出し、本番環境でのバグ再発を回避した。
確実な解決策の実装と完了
Quint を用いて次の修正版を検証し、2026 年 5 月 5 日までにアラートが完全に解消され、長年のアラート疲労の原因が除去されたことを確認した。
Quintによる不十分な修正の特定
Quintは既存のモデルを更新した結果、提案された修正が不完全であり、依然としてrace conditionが発生する可能性があると予測した。
終了ポッドにおけるエッジケースの発見
修正には終了中のポッドや削除タイムスタンプを持つポッドを除外するフィルタが含まれていたが、Quintは依然として特定の条件下で問題が発生すると指摘した。
重要な引用
The race condition caused duplicate Kubernetes pods to spin up for the same conversation runtime.
Quint's model of the Runtime API proved critical, catching an incomplete fix in a version of the software.
As of May 5, 2026, the multiple valid pods alert is gone, ending a longstanding source of alert fatigue.
Next, Quint updated its model and told us that the fix was incomplete. That there would still exist some variation of the race condition.
編集コメントを表示
編集コメント
本番環境でのバグ再発を事前に検出する形式検証ツールの実用性は、AI エージェントの信頼性向上において極めて重要である。開発プロセスにこのような検証を組み込むことで、より堅牢なシステム構築が可能になるだろう。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
OpenHands チームのオンコールエンジニアたちは、長年にわたり Runtime API における競合状態(race condition)が原因で発生する「複数の有効なポッド」アラートに悩まされていました。Runtime API は OpenHands の内部サービスであり、コーディングエージェントの実行用サンドボックスを管理しています。この競合状態により、同じ会話ランタイムに対して重複した Kubernetes ポッドが起動してしまう問題が発生していました。
私たちは DataDog のログを用いて状況を調査し、修正案を作成しました。そして最終的に、Quint を使用してこれらの修正案が実際に問題を解決できるかを確認しました。Quint が作成した Runtime API のモデルは決定的な役割を果たし、不完全な修正が含まれたソフトウェアのバージョンでもバグを検出しました。実際、Quint の予測通り、「修正済み」バージョンにも本番環境で同様のバグが発生しているのを確認できました。
次のバージョンをリリースする前に、私たちは再度 Quint を使用して次の修正案を確認し、確信を持って導入できる解決策にたどり着きました。2026 年 5 月 5 日現在、「複数の有効なポッド」アラートは解消され、長年のアラート疲労の原因がなくなりました。
本稿では、競合状態の診断プロセス、なぜ最初の修正案が不十分だったのか、そしてどうやって Quint が確信を持って問題を解決するソリューションをリリースできる根拠を与えてくれたのかについて詳しく解説します。
アラートを待機して
OpenHands チームのオンコールエンジニアとして、最も頻繁に鳴るアラートの一つが「複数の有効なポッド」です。Kubernetes において、ポッドはサービスの実行インスタンスであり、このケースでは各会話ランタイムごとに独立したポッドが割り当てられています。
このアラートが発生すると、波のように連続して表示されます。アラートに記載された推奨アクションは、OpenHands の会話ランタイムに対して重複する Kubernetes ポッドを見つけ、そのうちの一つを削除することです。しかし、本番環境で手動でポッドを削除するのはリスクが高いと感じます。もしログイン中のアクティブなユーザーの会話体験に悪影響を与えてしまったらどうでしょうか。
結局のところ、アラートは自然に沈静化することが多いため、私や他のオンコールエンジニアたちはアラートを放置して様子を見る選択をしていました。残念ながら、対応できないアラートが鳴り続けるのは良い兆候ではありません。これはアラートシステムへの信頼を損ない、アラート疲労 を悪化させる要因となります。しかし、この問題は解決が難しいものでした。以前から複数の人が同様のバグの修正を試みていましたが、いずれも失敗に終わっていたからです。
OpenHands が発見した競合条件
私たちは原因を再調査することにしました。最初のステップとして、OpenHands エージェントに DataDog のログを確認させ、アラートの原因を探りました。その結果、以下のような競合条件(race condition)が報告されました。

その後、OpenHands エージェントに修正案の草案を作成させました。それは、Runtime API(カスタム Kubernetes コントローラー)でスケールアップを行う前に、Resume 関数内で既存のアクティブなポッドが存在しないか確認するというものです。
しかし、問題は私がその修正に自信を持てなかったことです。OpenHands チームの多くにとって Runtime API はブラックボックスであり、その仕組みを真に理解しているのはごく一部のメンバーだけです。
Quint の登場
Quint は分散システムをモデル化する仕様言語であり、さまざまな形式手法を適用するためのツールセットを提供します。Quint を使えば、システムが取りうるさまざまな状態において、特定の性質が常に成り立つことを証明できます。なぜこれが重要なのかというと、競合状態(race condition)とは、システムが陥るべきではない危険な状態だからです。Quint はシステムのモデルを作成し、マージ前のコード変更も組み込むことで、その変更を加えた後にシステムが危険な状態に陥らなくなることを証明できます。
Quint LLM Kit とは何か?
Quint LLM Kit は、Claude Code と Quint ツールをコンテナ化したパッケージです。これにより、Quint のセットアップが非常に簡単になります。
幸いなことに、当社のチーフアーキテクトである Ray Myers 氏はすでに Quint llm-kit を活用して Runtime API を Quint でモデル化しており、その仕様ファイルを私に共有してくれていました。
不十分な修正と Quint の予測
エージェントが提案した修正に自信を持てなかったため、既存の Quint モデルを使って問題の調査を行うことにしました。Quint LLM Kit を起動し、ローカルマシンの Runtime API リポジトリを指してエージェントを開始します。まず、Quint の仕様ファイルを確認できるか尋ねました。
OpenHands エージェントの修正(再開前にアクティブなポッドが存在するか確認するもの)をマージする前に、私は Quint にレース条件とそれに対するプルリクエストの内容を伝えました。既存の Runtime API に関するモデルを更新する前に、Quint はまずレース条件の特定を試みました。そして、あっという間に問題を発見しました。
レース条件は理解も再現も難しく、 notoriously 厄介な問題として知られています。しかし、Quint のモデリングを通じて Runtime API の仕組みを学び、かつその上でレース条件について推論できる道筋を示してくれたのは非常に心地よい体験でした。

次に Quint はモデルを更新し、「修正は不十分だ」と告げました。まだ何らかの形でレース条件が残っているというのです。

具体的には、ポッドの終了処理におけるエッジケースを指摘しました。興味深いことに、私たちの OpenHands エージェントによる修正には、終了中のポッドや削除タイムスタンプを持つポッドを対象とした除外フィルタが含まれていました。

この時点では、これ以上調査を続けるのをやめることにしました。現状の改善(長年悩まされてきたノイズの多いアラートへの対処)に比べれば、この修正でも十分マシだと感じたからです。これで競合状態が解決することを期待していました。
Quint による本格的な修正の発見と検証
ご想像の通り、私は引き続き「複数の有効なポッド」のアラートを観察し続けました。つまり、競合状態は未だに存在しているということです。そこで OpenHands エージェントに対し、DataDog のログを再調査し、これがマージされた PR で試みた修正と同じ問題なのかを確認するよう依頼しました。

OpenHands エージェントの分析によると、マージされた PR の修正は、停止中のポッドを誤ってフィルタリングしてしまっていました。過去の Quint による分析でも、この修正が不完全であることと、停止中のポッドに関するケースについての記述が含まれていることが指摘されていました。当時、Runtime API の再開機能では、停止中のポッドをアクティブなポッドとして認識しておらず、重複した新しいポッドを作成していました。そこで OpenHands エージェントは、停止中のポッドに対する 1 行のフィルタリングを取り除くための新たな PR 修正を作成しました。
私は Quint に、この新しい PR 修正で競合状態が完全に解消されるかどうかを尋ねました。すると、Quint は「いいえ」と答えました。

ランタイム API は終了するポッドをアクティブとしてカウントするようになりましたが、依然として spec_replicas=1 を維持するように Kubernetes に指示を出しています。Kubernetes はその目標に向かって動作する際、終了中のポッドは無視します。その結果、アクティブなポッドがゼロと認識され、新しいポッドが起動して重複が発生します。Quint によるとこの PR の修正では競合状態を完全に解消できないことを確認したため、私はこの PR をクローズしました。

その後、競合状態を完全に解消する解決策を Quint の LLM キットに問い合わせました。Quint が提案した解決策は、1 行の修正で終了した PR に含まれる「ターミネート中のポッドをアクティブなポッドとして扱う」というアプローチに加え、スケーリングアップを行う前にターミネート中のポッドが完全に消滅するまで待機するというものです。


以下の表に示す通り、最初にマージされた修正とクイントが提案した最新の解決策を組み合わせることで、Runtime API のモデルにおける noDuplicatePods プロパティが成立する唯一のケースとなります。

この分析により、最新の解決策に対する確信がさらに強まりました。私は修正をマージしました。
現在の状況
修正をマージした後、次のステップを計画しました。具体的には、私自身が「Multiple Valid Pods(複数の有効なポッド)」というアラートが再発しないか監視します。もし再発した場合、OpenHands エージェントに DataDog のログ分析を依頼し、これが最新の PR で修正を試みたのと同じ競合状態なのかを確認します。
もし同じ競合状態だった場合、ランタイム API を正確に反映した解決策を導き出すために、Quint モデルをさらに更新する必要があります。そうでない場合は、その競合状態が解消された可能性があります。あるいは、Quint モデルが単純化されすぎていることが原因で検出できていない、別の競合状態が存在している可能性も否定できません。
しかし、嬉しい報告があります。本日現在、「Multiple Valid Pods」のアラートはもう表示されていません。多くの人々が何度も修正を試みてきたこの長年の問題は、ついに解決しました。
結論
Quint がなければ、私たちは修正をリリースした後にアラートが継続するのを眺め、なぜそうなるのかを知る術もなかったでしょう。Quint は分散システムのデバッグにおいて稀有な価値をもたらします。本番環境に投入する前に、正しさについて推論できる手段を提供してくれるのです。
信頼性の高いアクションが取れないノイジーなアラートに悩まされている場合、それはシステム自体が推論しにくい状態にあることのサインであることが多いです。Quint と llm-kit は、単に「あなたの修正は間違っている」と告げるだけではありません。あなたが信頼できる修正を見つけるのを助けてくれます。予測が成功したのを見たことで私の考え方は変わりました。今では形式手法(formal methods)の信者です。
「チューリングが初めて紙の上でプログラムの証明を行ったのが 77 年前のことですが、ついにそれが実用化されました。」——レイ・マイヤーズ
原文を表示
On-call engineers on the OpenHands team had long been plagued by a noisy "multiple valid pods" alert due to a race condition in the Runtime API. The Runtime API is an internal service within OpenHands that orchestrates execution sandboxes for our coding agents. The race condition caused duplicate Kubernetes pods to spin up for the same conversation runtime. We used DataDog logs to investigate the situation, drafted fixes, and eventually used Quint to check whether those fixes would actually solve the problem. Quint's model of the Runtime API proved critical, catching an incomplete fix in a version of the software. Indeed we observed the bug of the “fixed” version in production, as predicted by Quint. Before shipping the next version, we used Quint to check the next fix to arrive at a solution we could be confident in. As of May 5, 2026, the multiple valid pods alert is gone, ending a longstanding source of alert fatigue. In this post, we walk you through how we diagnosed the race condition, why our initial fixes fell short, and how Quint gave us the confidence to ship a solution that fixes the issue.
Waiting Out the Alert
As an on-call engineer on the OpenHands team, one of our noisiest alerts has been "multiple valid pods". In Kubernetes, a pod is a running instance of a service, and in this case, each conversation runtime gets its own pod. When this alert fired, it would show up in waves. The suggested action on the alert is to find duplicate Kubernetes pods for an OpenHands conversation runtime and delete one pod. However, it feels risky to delete pods in production manually. What if we negatively impact the conversation experience for an active logged in user? Eventually, the alerts would quiet down on their own, so I and other on-call engineers would opt to wait out the alert. Unfortunately, having unactionable alerts is not a good sign. It reduces confidence in our alerting and instead increases alert fatigue. However, this issue seemed to be a hard one to solve as multiple people had unsuccessfully tried to fix this bug before.
OpenHands Finds a Race Condition
We decided to investigate the cause once more. As the first step, I had the OpenHands agent look at DataDog logs to investigate the alert. It reported a race condition as follows.

I then had the OpenHands agent draft up a fix: check for existing active pods in the resume function before scaling up in our Runtime API (a custom Kubernetes controller).
The problem, however, was that I did not have confidence in the fix. Runtime API is a black box to most of us here on the OpenHands team with only a select few truly understanding how it works.
Enter Quint
Quint is a specification language that models distributed systems and a set of tools that apply different formal methods to them. Quint can prove that properties hold across the various states your system can be in. Why is this important? A race condition is a bad state your system can get into. Quint can model your system and also unmerged code changes to prove that your system can no longer get into that bad state with those changes.
What is the Quint LLM Kit?
Quint LLM Kit packages Claude Code with Quint tools into a container. It is an easy-to-use Quint setup.
Fortunately, our chief architect Ray Myers had already used the Quint llm-kit to model the Runtime API with Quint and shared the spec files with me.
An incomplete fix and Quint’s prediction
As I didn’t have confidence in the fix proposed by the agent, I decided to investigate the issue using the existing Quint model: I started an agent with Quint LLM Kit and pointed the setup at the Runtime API repository on my local machine. I asked the agent if it could see the Quint spec files. Before merging the OpenHands agent fix to check for existing active pods before resume, I told Quint about the race condition and the pull request with the fix. Before updating its existing model of the Runtime API, Quint tried to find the race condition. It found the race condition quickly. Race conditions are notoriously tricky as they are difficult to understand and reproduce, so it was neat to have a tool like Quint teach me how the Runtime API worked via its modelling which also presented a way to reason about the race condition.

Next, Quint updated its model and told us that the fix was incomplete. That there would still exist some variation of the race condition.

Specifically it called out an edge case with terminating pods. Interestingly, in our OpenHands agent fix, there was an exclude filter for terminating pods or pods with a deletion timestamp.

At this point, I decided to not investigate this any further. I put the fix in as-is because it felt like it would already be better than the status quo (the noisy alerts that we have already been dealing with for a very long time). I hoped the race condition was resolved.
Finding a real fix and confirming it with Quint
As you might have guessed, I continued to see the multiple valid pods alert. This meant that the race condition was still around. I asked the OpenHands agent to investigate DataDog logs again and to check if this was the same issue that the merged PR tried to fix.

The OpenHands agent analysis shows the merged PR fix incorrectly filtered out terminating pods. Prior Quint analysis had already mentioned the fix was an incomplete fix and included a snippet about the case around terminating pods. At this point in time, the resume functionality in the Runtime API did not see terminating pods as active pods and created new duplicate pods. The OpenHands agent created a new PR fix to remove the one line filter of the terminating pods.
I asked Quint if the new PR fix would fully close the race condition. It told me no.

While the Runtime API would now count terminating pods as active, it still instructed Kubernetes to maintain spec_replicas=1. Kubernetes, when working toward that target, ignores terminating pods. As a result it sees zero active pods and spins up a new one, creating a duplicate. Seeing that the new PR fix would not fully close the race condition according to Quint, I closed the PR.

I then asked the Quint llm-kit for a solution that would fully close the race condition. Quint came up with a solution that incorporates the one line closed PR fix to view terminating pods as active pods and also waits until terminating pods are gone before scaling up.


The combination of the initial merged fix and the latest solution that Quint came up with is the only one where the noDuplicatePods property holds in Quint’s model of the Runtime API as is shown by the following table.

This analysis gave us more confidence in the latest solution. I got it merged.
Current situation
After merging the fix, we planned out the next steps. The plan is that I would observe if we get any more Multiple Valid Pods alerts. If so, I would ask the OpenHands agent to analyze DataDog logs and if this was the same race condition that the latest PR fix tried to address. If yes, we would need to update the Quint model further to come up with a solution that accurately reflects the Runtime API. If not, it could mean the race condition is closed. Or it could mean there are other race conditions that are not visible in the Quint model (potentially because the model is too simplistic).
However, I’m happy to report that we no longer see the Multiple Valid Pods alert as of today. This longstanding issue that multiple people have tried to fix many times is finally solved.
Conclusions
Without Quint, we would have shipped a fix, watched the alerts continue, and never known why. Quint gave us something rare in distributed systems debugging: a way to reason about correctness before committing to production.
If you're dealing with noisy alerts you can't confidently act on, that's often a sign of a system that's hard to reason about. Quint and the llm-kit doesn't just tell you your fix is wrong. It helps you find one you can trust. Seeing the successful predictions changed my point of view; I’m a believer in formal methods now.
“In 77 years since Turing first did program proofs on paper, we've finally made it practical.” — Ray Myers
AI算出
技術分析ainew評価高い
AI エージェント運用におけるインフラ課題(ランタイム API の競合状態)に対し、Quint という形式検証ツールを用いて解決策を検証・実装した具体的なケーススタディであり、再現可能な手法と技術的含意が含まれている。
6つの評価軸を見る
- AI関連度
- 75
- 情報源の信頼性
- 100
- 新規性
- 75
- 調べる価値
- 75
- 重複の少なさ
- 100
- 日本での有用性
- 25
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み