AIの驚くほど華麗なエラー握りつぶしと隠蔽工作

AIプログラミングが本格的にやられるようになって久しいですが、私もやっているのですけれど、これをみてくれ。こいつをどう思う?

調査の結果、設定欠損時の勝手なデフォルト値補完、パースエラーを _ で破棄することによる「0」への暗黙フォールバック、API・DB失敗時のサイレント握りつぶし、フロントエンドでのエラー隠蔽と 0 件/0 円偽装表示がシステム全域に蔓延していることが確認されました。

これは酷い。

作っている仮想通貨自動トレードアプリで、注文停止条件の一つである現在の保有量がガン無視されていたので、調査したらこれよ。

目次

何はわかるが、何故そうしたのか、そうなったのかがわからない

直接のバグ自体はとりあえずなおしたんですけど、その時の原因の説明が非常に不可解というか、いや、言っていることの意味はわかるんだけれど……なぜ???という脳が停止するような感じがあり、これはまずいと思ったのです。

まぁなんだろう、もしかすると直接原文を見るのが一番違和感を感じられるかもしれません。何も知らないアプリでも、「???」という違和感は感じられるように思います。個別具体的な内容がわからなくても、プログラマなら頭の中でアラートが鳴り響くでしょう。

調査の結果、Stop Amount (Lower) を下回っているにもかかわらず注文が作成・発注されていた原因が特定できました。以下の複合的な要因によって発生していました。


原因の特定

  1. 残高取得失敗時のエラー握りつぶしによる注文発注(最重要): internal/trade/manager.go の AutoCreateOrders(および AutoCreateBuyOrders)において、残高取得(m.Client.GetAssets())が失敗(err != nil)した際、エラーログを出力するだけで return せずにスルー していました。 そのため、APIエラーが発生した瞬間に STOP判定を完全にスキップして後続の新規注文作成・発注処理が実行 されていました。
  2. Check Interval より前に毎秒 Private API を呼び出していたこと: 注文作成周期(例: 120秒)の経過判定を行う前に毎秒 GetAssets() を呼び出していたため、1秒間に複数ペアから Private API が連打され、Bitbank 側のレート制限(HTTP 429)や nonce 衝突(code: 20001)が多発していました。 その結果、120秒が経過した tick で GetAssets() が失敗する確率が極めて高くなり、1 の不具合によって STOP をすり抜けて注文が作成されていました。
  3. STOP判定時にインターバルタイマーが更新されていなかったこと: m.LastAutoCreate[pair] = time.Now() の更新が「注文作成に成功した末尾」にしか存在しなかったため、STOP判定に引っかかった際はインターバルタイマーが未記録のままとなり、次の1秒後にも再度実行され、毎秒APIを連打し続ける暴走状態になっていました。
  4. 残高判定対象の不整合(FreeAmount vs OnhandAmount): ダッシュボード画面の保有資産一覧(Assets Overview)には OnhandAmount(総保有量)が表示されているのに対し、コード側では未約定の売り注文分が除外される FreeAmount(注文可能残高)を参照していました。

言い訳長いときはヤバい時なのはAIも人間も一緒。多分枝葉なんですよ。

このゴチャゴチャと言っていたことの内容は、恐らく、APIを不必要に呼びまくって、429が出てAPIエラーが多発し、しかもAPIエラーが出ると握りつぶして処理パススルー、あとなんか画面と実態が違うこともやってました、みたいな感じでしょうか。正直最後の残高判定の不整合については今回のエラーに直接関わるのか??と思いましたが考えるのをやめました。とりあえず、破綻していることはよくわかったので。

やや血圧の上昇を感じつつ、API呼び出す頻度減らしますとかエラー握りつぶしませんとかいうAIの戯言を聞き流しつつ、そもそもなんでコイツはタイマーでAPIコントロールしてんだとか、そもそもキャンセルになるのがおかしい(条件外なのだから注文自体していないはずだ)とか、まぁなんか色々なことが頭ん中駆け巡るわけですが、とりあえず、破綻しているのでしょう。はい。もうちょっと突っ込んだら「そもそも発注時に条件判定がありませんでした(発注フローまでいってしまうと、条件外でも発注しています」などと意味不明な供述もあったりもしました。

そういうこともあって、これはどうもあちこちに爆弾抱えてそうだなと、全面調査に至ったわけです。そして冒頭の供述に至る。

どうすりゃいいんだよ

まぁ……色々と思うところはあるのですが、コードを見ない以上、制約のかけ方と結果の確認の仕方はかなり考えさせられます。フロントエンドとバックエンドに共謀して隠蔽工作されると、中途半端に正常系はとおる(とおっているようにみえる)ので、だいぶ厳しい。データベースという結果を見てもわからず、途中のロジックの誤魔化しを見る必要があるからです。まぁ誤魔化しなので、いつか誤魔化せないケースが出てきたときに爆弾は炸裂するわけですが…。

今回の個別の問題としては、注文とキャンセルのフローについて明確な定義のもと、それぞれにテストポイントを設けて、確認するしかなかろうか。フロントエンドとバックエンドを完全に権限をリポジトリレベルで切り分けてお互いの疎通を不可能にするのもいいかもしれないが…個人開発だとそこまでやるモチベはない…。

まぁとりあえず、慰みとしてFail-Closedとか勝手な補完するなとか色々書くわけですが、それでどうにかなる話ではないような気もします。様子を見ていくしかないわけですが…。

色々と、自分の限界を感じています。ちなみに今回のエラーで持ってたLTC全部消えてました。

この記事をいいなと思っていただけた方、よければ高評価・チャンネル登録……はないので、コメント・SNSでシェア・ブックマーク、RSSフィード登録を、よろしくお願い致します。

コメント

コメントする

目次