Skip to content

ClickGap: ClickHouse のための自律型 QA

image 512x512 10
2026年8月25日 · 38分で読む

ClickHouse は、通常の稼働日に50〜100件のプルリクエストをマージします。その一つひとつが、本番で動く性能重視の C++ データベースに入ります。どのマージも、誤った結果をもたらしたり、テストされていない機能の組み合わせでクラッシュを引き起こしたり、クエリを気づかれないまま30パーセント遅くしたりしうるのです。

この問題に AI エージェントを向けるのは当然の発想に見えますが、それは反面教師になる近道でもあります。

curl は最近、2019年から運営してきたバグバウンティを、AI が生成したレポートの洪水を受けて終了しました。メンテナーはそれを「slop(粗製濫造)」と呼びました。もっともらしいバグレポートを作るのはほぼ無料ですが、それをトリアージするにはエンジニアの手がかかります。私たちのメンテナーは、チャットボットの世話をするために参加したわけではありません。

それでも私たちは作りました。ClickHouse におけるエージェンティックコーディングでは1行だけ顔を出しましたが、この記事はその長い版です。

ClickGap は、ClickHouse にマージされるすべてのプルリクエストをレビューする自律型の QA エージェントです。実際のビルドに対してテストを設計して実行し、リグレッションを持ち込んだコミットを二分探索(bisect)で特定し、人間が送信を承認しなくても、公開トラッカーに Issue とプルリクエストを起票します。

ローンチから5か月で、ClickGap の GitHub アカウントはおよそ500件の Issue を起票し、約200件のプルリクエストを開いて、カバレッジのないままマージされていたコードパスにテストを追加しました。Issue の半数以上はすでにクローズされており、その大半は却下ではなく完了としてのクローズで、200件以上はリンクされた修正 PR とともにクローズされました。ClickGap がプルリクエストをマージ後にレビューするのは、出荷されるのはマージされたコードだからです。指摘は数時間以内に届きます。欠陥がリリースに乗ってユーザーの手元へ届くよりずっと前です。

この記事では、ClickGap を構築するうえでの課題と、このボットが「これは壊れています」と言ったときにメンテナーがそれを信じるところまで、どうやってたどり着いたかを見ていきます。

すでに徹底的にテストされているデータベース

ClickHouse の CI は毎日、数千万回のテストを実行します。ステートレスな SQL スイート、統合クラスター、サニタイザービルド、ストレステスト、ファザー、統計的な性能比較です。人間のメンテナーの承認なしには何もマージされず、すべてのプルリクエストは社内のレビュアー clickhouse-gh[bot] にも検査されます。このボットは差分を読み、ファイルと行を示した指摘とともに変更を要求します。マージ前に相当な割合の欠陥を捕まえています。

それでも、人間のレビュアー、機械のレビュアー、テストの壁をすり抜ける欠陥があります。CI が証明するのは、書かれたテストが引き続き通ることだけです。どのテストも動かしていない振る舞いについては何も語りません。新しくマージされたコードは特に露出しています。プルリクエストは、テストスイートが一度も到達しない変更行を日常的に持ち込むからです。こうした隙間が、ClickGap のおよそ200件のカバレッジ PR の由来です。

別の種類の欠陥は、正しさは変わらないまま実行コストだけが上がるため、結果のアサーションには見えません。スキップインデックスは、構築され、ディスクを消費し、しかし1行もスキップしないことがありえます。すべてのクエリは正しい結果を返し続けながら、インデックスが節約するはずだった資源を無駄にします。

ClickHouse で見つけたもの

公開トラッカーには、クエリアナライザや MergeTree からレプリケーションまで、およそ35のコンポーネントラベルがあります。ClickGap の指摘は、繰り返し現れる次のカテゴリに集まります。

こっそり持ち込まれたセマンティクスの変更 (#113763)。gini 集計関数を追加するプルリクエストが、既存の <agg>If<Combinator>(x, NULL) の形をとる広範な式群についても、結果型と結果値を変えていました。タイトル、説明、changelog のどこにもその影響は書かれていませんでした。この種の欠陥は、レビューがプルリクエストの宣言した目的の範囲にとどまっていると見落としやすいものです。変更は宣言したことを正しく実装しながら、言及していないものを静かに壊しているかもしれないのです。

リソース安全性の穴 (#114987)。新しい適応型アグリゲータの学習フェーズが、外部スピルの分岐に到達する前に戻っていました。影響を受ける設定では、以前はディスクへスピルしていたクエリが、代わりにメモリ制限に達する可能性がありました。このレポートは OOM の可能性を推測しただけではありません。3種類の設定でスピルされたパートの数を測り(46、次に7、そして0)、旧パスと新パスのメモリ消費を比較しました。

続いて起きたのは、ボット2体のリレーでした。ClickHouse のもう一つのボットである groeneai がカウンターを再現し、影響範囲を絞り込みました。この失敗には既定の設定ではなく、引き上げたチューニング閾値が必要だったのです。ClickGap は当初の深刻度を弁護するのではなく、その訂正を公に受け入れ、修正は1日以内にマージされました。

静かな性能バグ (#114990#114105)。どちらの欠陥もサーバーをクラッシュさせず、結果も壊しません。どちらも、気づかれないままクエリのコストを押し上げます。

#114990 では、スキップインデックスが構築され、ディスクに保存され、そして無視されていました。以前は16個のグラニュールのうち1個を読んでいたクエリが、同じ結果を返しながら16個すべてを読むようになったのです。結果のアサーションではこの失敗を検出できません。同じ答えは見えても、今は16倍の仕事をしていることは見えないからです。

#114105 では、無条件の std::adjacent_find がホットなコンストラクタにもう1回の走査を追加し、配列を多用するクエリを14.6〜30.9パーセント遅くしていました。CI の計測時間は自然に揺れるため、性能に関する主張にはより強い証拠が求められます。このレポートは信号と雑音を分けました。1000回を超える計測にわたって、master の変動は1パーセントにも満たない幅にとどまる一方、この変更は2桁のリグレッションを生んでいました。さらに、正確なコードパスを特定し、計測結果と矛盾するソースコードのコメントを引用しました。「正しいが遅い」はそれ自体が1つの欠陥クラスであり、それを捕まえるにはアサーションではなく統計が必要です。

カバレッジという仕事 (#114766、およそ200件のうちの1つ)。機械が書いたテストがよく失敗する形は決まっています。新しいコードを実行はするものの振る舞いが壊れているかを検出しないか、既存のスイートがすでに提供しているカバレッジを重複させるかです。

ClickGap のカバレッジに関する指摘は、どちらの基準も満たさなければなりません。分析では、新しいテストを失敗させるソースコード1行の変異を正確に特定し、さらに、レビュー対象のプルリクエスト自身のテストでは押さえられていない何をこのテストが押さえるのかを説明しなければなりません。どちらかに答えられなければ、その指摘は捨てられます。

最も強い主張については、ClickGap は実験を走らせます。テスト対象の振る舞いを意図的に壊し、変更したサーバーをビルドし、新しいテストは失敗する一方で元のプルリクエストとともに提出されたテストは引き続き通ることを実証します。

仕組み

ClickGap はマージストリームを監視する単一のデーモンです。対象かどうかは受け入れ時に一度だけ判定されます。リバート、すでにレビューした変更の再移植、分析するには大きすぎるプルリクエストはスキップされ、それ以外はすべてパイプラインに入ります。対象となる各プルリクエストについて、デーモンはソースを同期し、マージコミットを含むことを検証済みのバイナリを用意し(可能なら新しい CI アーティファクトをダウンロードし、そうでなければソースからビルドします)、ウォームアップ済みのサーバーを備えた分離ワークツリーを準備します。

その環境に対して、2種類のアナリストが走ります。バグアナリストは仮説を立てますが、各仮説は実行されるテストに変換されなければなりません。仮説が次の段階に進むのは、観測された振る舞いが期待される契約と食い違ったときだけです。続いてカバレッジアナリストが走ります。その起点は、変更されたコードの行レベルのカバレッジです。それらの行がすでにカバーされていればスキップされます。

候補となる各指摘は、まず、それを退けることだけを仕事とする敵対的レビュアーに向き合います。ここを通ったものは、次にパイプラインが強制する10のゲートを通過しなければなりません。

  1. 具体的な結果。 欠陥は観測可能な影響を生まなければなりません。誤った結果、データ損失、クラッシュ、セキュリティ上の欠陥、正当な入力の拒否、計測された速度低下、あるいは CI シグナルの喪失です。「このコードは死んでいる」では足りません。
  2. 有効な引用。 参照するすべてのファイルと行は、現在のソースツリーに存在しなければなりません。
  3. ファイル全体のレビュー。 アナリストは差分だけでなく、変更された各ファイルを全文読まなければなりません。
  4. 呼び出し元の分析。 アナリストは、変更されたコードを呼び出すコードパスを調べなければなりません。
  5. 既存テストの探索。 テストスイートを少なくとも3種類の異なる方法で探索しなければなりません。すでに存在するテストを「欠けている」と報告する間違いは、信頼を最も速く失わせるものの一つです。
  6. 実行された再現コード。 証明となるテストは実際のバイナリに対して走らなければなりません。
  7. 証拠と主張の一致。 バグの指摘には観測された失敗を含めなければなりません。カバレッジの指摘は、提案するテストをディスク上の実際のファイルとして生成しなければなりません。
  8. カバレッジのキルテスト。 カバレッジの主張には的を絞った検証が課されます。その隙間は本物か、提案するテストは守ると主張する振る舞いを検出するか、という問いです。
  9. レビュアーの承認。 敵対的レビュアーの判定が合格として記録されていなければなりません。
  10. 既知の偽陽性に一致しないこと。 各指摘は、メンテナーが訂正した過去の間違いと比較されます。一度学んだ誤りを二度起票することはできません。

ゲートのうち8つは、完全に通常のコードとして実装されています。モデルの判断を必要とするのは、カバレッジのキルテストと敵対的レビュアーの判定だけです。

10のゲートをすべて通過した後、パイプラインは外部へのアクションを選びます。カバレッジの隙間はテストだけのプルリクエストになります。ローカルで再現されたバグは Issue になります。実行可能なテストはあるがローカルでは確認できないバグは、ClickHouse の CI に証明役を任せる証明用プルリクエストになります。候補の大半は、外部へのアクションを何も生みません。

起票の後も責任は続きます。ClickGap はすべての提出物について CI を監視し、各失敗を、自身のテスト、既知の不安定なテスト、インフラのいずれかに分類します。ClickGap 自身が失敗の原因なら、ログを読んで修正をプッシュします。最大5回試み、それでもだめなら人間へエスカレーションします。すべての修正は、ローカルで2回連続して通ることを含む自身のゲートを通過します。1回通っただけでは、不安定さを示しているだけかもしれないからです。

レビューのフィードバックも同じ閉じたループに入ります。レビュアーが変更を要求すると、ClickGap は提出物を更新し、検証を再実行し、証拠を添えて返答します。その後、デーモン側の別の検証器がテストを独立して実行します。どのアナリストも、自身の成功を自身で認定することはできません。

マージされた PR から起票される成果物まで。すべての指摘は、Issue やプルリクエストが起票される前に、実行、敵対的レビュー、コードで強制される10のゲートを通り抜けなければなりません。大半の指摘が終わる場所は、トラッカーではなくアーカイブの箱です。

指摘は実際にどこから来るのか

ゲートを見れば、メンテナーが ClickGap の起票を信頼できる理由は分かります。しかし、起票に値するものをどう見つけるかは分かりません。検出を支えているのは次の強みです。

第一に、差分の先まで読みます。 ゲートは、アナリストが変更された各ファイルを全文読み、各呼び出し元を調べ、同等のロジックを隣り合う同種のコードパスまで追うことを要求します。ここまで読み込むことで、先の gini のリグレッション(#113763)が明るみに出ました。根本原因には、同種のオーバーライド6件と、元の差分が一切触れていない利用側が関わっていたのです。同じパターンはトラッカーの至る所で繰り返されます。プルリクエストがある分岐の不変条件を修復しながら、隣にある同等の分岐を手つかずで残すのです。

第二に、直感ではなくチェックリストで動きます。 レビュー用プロンプトには、JOIN のエッジケース、並行処理の危険、寿命(ライフタイム)の誤りといった領域を扱う、およそ20の ClickHouse 固有の欠陥パターンが含まれています。各パターンは、何を調べ、どこを探すかを指定します。このリストは証拠から育ちます。別のプロセスが、確認済みの ClickHouse のバグを2000件近く分析し、その教訓を今後のレビューのためのメモリへ変換しました。バグが既存のどのパターンにも一致しないとき、システムは新しいチェックリスト項目を起草します。

第三に、カバレッジの隙間は推測ではなく計測します。 LLVM の行カバレッジが、どのテストも実行しない変更行を正確に特定します。それでも、カバーされていない行が数に入るのは、提案するテストが殺す変異をアナリストが名指しでき、ユーザーに見えるリスクを説明できる場合だけです。

第四に、経済性が幅の広さを後押しします。 仮説は安く、1回の完全なレビューにかかるモデル利用料は数ドルで、ローカルの検証は数分で済みます。アナリストはプルリクエストごとに多くの候補を探索し、実行したテストが期待される振る舞いと食い違ったものだけを残せます。また、すべてのレビューは、過去の指摘から想起したおよそ30の教訓とともに始まります。

検出そのものも継続的にテストされています。ベンチマークは、ClickGap が過去に見つけ、メンテナーが確認した実際のバグから始まります。それぞれについて、リポジトリをレビュー対象のプルリクエストがマージされた時点、つまり欠陥がまだ存在していた時点へ巻き戻し、アナリストがその状態を最初からもう一度レビューします。問いは二値です。そのバグを再発見できるか。

プロンプトを短くするといった効率化の提案はすべて、同じコーパスに対して旧設定と新設定の両方で実行されます。安い設定が、既存の設定なら捕まえるバグを見逃すなら、それは採用されません。

意図して安く、そのために測る

レビューするプルリクエストあたり数ドル。先の再現率ベンチマークがそのガードレールです。バグ検出を弱めるコスト削減は採用されません。何も捕まえない安いレビュアーは効率的なのではなく、単に低コストな雑音です。この制約の中で、節約は次の場所から生まれます。

通常のコードはモデルの時間を消費しません。 契約が正確に決まっている作業は通常のコードとして走ります。Issue 本文を上流のテンプレートに合わせて修復する、ファイルと重複するタイトルを ClickGap の履歴と比較して二重起票を検出する、セルフレビューのチェックリストを描画する、といった作業です。これらの操作はトークンを消費せず、挙動がぶれることもありません。

やり直しがきく作業は小さなモデルに任せます。 1つは、主アナリストが読む前に長い CI ログを要約します。もう1つは、カバレッジの主張に対して変異テストを走らせます。さらに別の1つは、誰かが公に名指しされる前に、二分探索で特定したコミットがその失敗を引き起こしたとしてもっともらしいかについてセカンドオピニオンを出します。いずれの場合も、誤った結果が出ても下流で捕まるか、設計上許容できるようになっています。拡張推論を備えた高価なモデルは、システムの要となる2種類の判断、すなわちバグを見つけることと弱い指摘を退けることにだけ使います。

コストを正当化できそうにない作業はスキップします。 十分にカバーされた変更はカバレッジアナリストを通りません。対象外のプルリクエストはパイプラインに入りません。メンテナーが一貫して無視する指摘のクラスは自動的に抑制されます。

すべての最適化は再現率を保たなければなりません。 アナリストのプロンプトを短くしたとき、候補版は、同じ確認済みバグの種を使って完全版プロンプトとの対比較ベンチマークに合格する必要がありました。結果はベースラインと同等でした。対比較で唯一見逃したバグは2回の再実行の両方で再発見され、繰り返し起きるリグレッションではなく実行ごとの揺らぎだと分かりました。さらに、完全版プロンプトが見逃した1件のバグを見つけながら、コストを11パーセント、セッション時間を17パーセント削減しました。そうしてはじめて、それが既定になりました。

ここにはもう一つ、ボット自身の請求額よりはるかに大きな経済性があります。欠陥を早く捕まえることで回避されるエンジニアリングコストです。マージから数時間以内に報告されたバグは、通常は後続のコミットで修正されます。差分はまだ作者の頭に新しく、何も出荷されておらず、影響を受けるユーザーはおらず、修正は master にだけ入ります。

同じ欠陥がリリースに到達すると、コストは何倍にもなります。誰かが、どのリリース版が影響を受けるかを判定し、リグレッションを持ち込んだコミットを二分探索で特定し、影響を受けるすべてのリリースブランチへ修正をバックポートしなければなりません。マージとリリースの間で捕まえたバグ1件ごとに、その請求書全体が回避されます。それが、マージ時にレビューすることの本当の見返りです。

間違った PR を名指ししない

「これは 26.4 でリグレッションし、このコミットが持ち込み、サポート中のこれらのブランチにまだ残っています」と言うレポート1本は、「これは壊れています」としか言わないレポート10本分の価値があります。

影響を受けるバージョンのマトリクスは決定論的なコードで作ります。サポート中のすべての ClickHouse リリースについて、実際のバイナリをダウンロードし、再現コードを実行し、結果を記録します。再現コードは意図的に狭く作られています。小さなスクリプトがバイナリを受け取り、バグが現れれば 1、現れなければ 0 で終了します。タイムアウトはどちらの結果にも数えません。また、環境にシークレットを持たずに実行します。再現コードは Issue の報告者が形作るものであり、完全に信頼できるものとして扱えないからです。

二分探索は、正常と分かっている地点と異常と分かっている地点の間のビルドをテストして、問題を持ち込んだコミットを特定します。ClickGap はそれらのビルドを3種類のソースから入手します。およそ 25.8 までさかのぼる公式リリースバイナリ、master のコミットごとの CI アーティファクト、そして隙間が残る場所でのソースビルドです。

候補となる各ビルドは最大3回テストし、タイムアウトは票に数えません。1回の不安定な結果では探索の向きは変わりません。最終的な境界では、疑われるコミットが依然として失敗し、その直前のテスト可能なビルドが通らなければなりません。信頼度は、範囲内のテスト不能なコミット1つごとに下がり、それを埋め合わせて上がることは決してありません。

プルリクエストが名指しされる前に、最後の因果チェックが、その変更が観測された失敗を引き起こしたとしてもっともらしいかを問います。答えが明らかにノーのときだけ、帰属を却下します。基本となる規則は単純です。間違ったプルリクエストを名指しするのは、何も名指ししないより悪い。台帳は ClickGap がこの規則に従っていることを示しています。二分探索器が、欠陥が古すぎるか証拠の隙間が広すぎるために棄権する回数は、犯人を特定する回数のおよそ3倍です。

誰も計画に入れない部分: 信頼を得ること

この部分は、どんな振り返りよりもコミット履歴がよく語ってくれます。

初日には「Increase filing limits to 10 (PRs, issues, daily, concurrent)」というタイトルのコミットがあります。私たちはスループットがボトルネックになると思い込んでいました。最初のクラッシュレポートと最初のカバレッジプルリクエストが届くまでの3日間は、証拠すらそれを裏付けているように見えました。その後の5か月は、その逆を教えてくれました。

底は6週間ほど経った頃に訪れました。ClickGap が、実際のプルリクエストに回答を投稿する代わりに、自身の内部の推論をコメントとして公開したのです。修正は履歴に「Stop bot from posting LLM-reasoning-as-reply spam」として現れます。同じ日にもう1件のコミットが続きます。「refuse to post LLM-meta-reasoning-as-reply spam (final layer)」。案の定、最初の層は最終ではなかったのです。

それから私たちは「Close residual spam vectors」の下で、メッセージを公開しうるすべての経路を監査しました。この監査で、重複したアラートが自分たちの Slack を溢れさせていることも分かりました。翌日、最初から存在すべきだった制御を作りました。過去30日間に起票した Issue を追跡し、メンテナーから何らかの反応があったものが25パーセントに満たなければ、関与が回復するまで ClickGap は信頼度の低い指摘の起票を止めます。

起票の量は、私たちが制御する設定値ではなくなりました。メンテナーが継続的に与えてくれる特権になったのです。

計測は次の屈辱を強いました。ある30日間の窓を取り、単純な問いを立てました。ボットが提案した指摘のうち、メンテナーが実際に受け入れたのはどれだけか。カバレッジの指摘は3分の1、バグレポートは半分でした。この数字が、結果ゲートが存在する理由であり、ボットが起票するバグレポートが現在、アナリストの提案よりはるかに少ない理由です。

最も厄介な失敗の一部は、有用な仕事を何もしていないのに正当に見える答えを返すコンポーネントから来ました。影響バージョンのチェックは、最初はエージェント駆動でした。それが選んだダウンロードヘルパーは amd64 しか対応していないのに、ClickGap は aarch64 で動いていました。すべての取得が失敗し、すべてのバージョンが unknown として返ってきました。ビルドを本当に取得できないときには unknown は正当な値なので、この失敗はカバレッジの完全な喪失ではなく、控えめな報告のように見えました。私たちはこのチェックを、テスト済みのバージョンと取得失敗を区別する決定論的なコードに置き換えました。

似た失敗は CI ログの要約でも起きました。ClickHouse のテストランナーは、テストごとに ✅ か ❌ を出力します。小さなモデルがそのパターンをコードレビューのプロンプトだと解釈し、Final Verdict: ✅ Approve を出力したのです。下流のパーサーは Approve を合格したテスト結果として扱い、本物の失敗が処理されずに残りました。レビューの形をした要約は、今ではパーサーに届く前に拒否されます。

どちらの出来事も同じ規則を裏付けました。もっともらしい状態は、実行が成功した証拠ではない。現在は常駐の照合器が、進行中のすべての項目を巡回し、記録された状態を背後の成果物や外部システムと照らし合わせています。

メンテナーに向けた出力も、パイプラインと同じだけ変わりました。コミット履歴はその過程を記録しています。「issue bodies to maintainer spec — TLDR, code links, folds, author cc, no banner」に続いて、「Trim every remaining maintainer-facing surface to the point」、そして「Stop silencing human maintainers behind CI-bot churn」です。

新しい Issue は現在、既定ではおよそ10行だけを表示します。太字の症状、疑われる根本原因へのパーマリンク、1コマンドの再現手順、そして期待される振る舞いと実際の振る舞いです。補足の分析は折りたたみブロックに収められ、その中には検証済みの事実と未解決の仮定を分ける「Open risks」のセクションも含まれます。

返信はスレッドあたり5件までに制限され、投稿前にレビューされます。レビュアーは返信を書き直せますが、メンテナーへの返信を破棄することはできません。この制限があるのは、不完全な答えを握りつぶすことが、問題を報告した人を無視することと見分けがつかないからです。

ClickGap の Issue が開いたときにメンテナーが実際に目にするもの: 症状、根本原因のパーマリンク、1コマンドの再現手順、そしてそれ以外はすべてワンクリック先です。

そして、ボットが間違っていたときの応答もプロダクトの一部です。自己参照的な system.processes クエリに関する偽陽性を示されたとき、ボットはこう答えました。「You're right, and thanks for the precise diagnosis... I'll add self-referential system.processes.query reads to the oracle's exclusion list so this class doesn't get filed again(おっしゃるとおりです。正確な診断をありがとうございます。自己参照的な system.processes.query の読み取りをオラクルの除外リストに追加し、このクラスが再び起票されないようにします)」(#110141)。その除外は実装され、反映されました。こうした判定はすべて不一致台帳に記録され、ボットが学ぶのはその台帳です。

メモリ、そして Loom が存在する理由

ClickGap は経験を3段階で保存します。ケースメモリは個々の指摘の経緯と結果を記録します。レッスンは、自動化された学習フローまたは運用者のレビューを通じて、それらのケースから再利用可能な規則を抽出します。ドクトリンファイルは、すべてのアナリストとレビュアーの実行が必ず受け取るべき、より少数の規則を保持します。それ以外のメモリは関連するときにだけ取り出されます。

ドクトリンファイルは150行に制限されています。その全内容がすべての指摘に付いて回るからです。採録は厳密に証拠に基づきます。各規則は人間のメンテナーの判定を引用しなければなりません。ボット自身の結論は対象外です。レビュアー個人の好みは、実際のレビューフィードバックで裏付けられる場合にだけ含められます。

各レビューは、取り出したメモリのキーを記録します。指摘が終端状態に達すると、良い結果はそれらのメモリの今後の順位を押し上げ、その効果は90日の半減期で減衰します。悪い結果は保持されますが、個々のメモリをすぐに罰することはありません。1回のレビューは通常およそ30のレッスンを取り出すため、1つの悪い結果だけでは、どのメモリが(もしあるとして)それに寄与したかを判定する証拠として不十分だからです。

メモリ層は、ローカルの SQLite ストアとして始まりました。数か月後、ClickHouse 社内で AI エージェント向けに構築されたメモリサービス Loom へ移行しました。Loom は型付きでタグ付きのメモリを ClickHouse に保存し、検索、来歴(プロベナンス)、結果のフィードバックを API 経由で公開します。

この移行は、本番投入前に検索ベンチマークを通過する必要がありました。その成果は2点ありました。第一に、私たちの直感の誤りが分かりました。想起を、バグと同じサブシステム(JOIN、レプリケーション、ストレージといったコードベース上の領域)のタグを持つメモリに限定するのは筋が良さそうに見えました。ブラインド評価では、それは検索品質を22パーセント下げました。最も強いレッスンは、しばしばサブシステムの境界をまたいでいたからです。同じタグを代わりに緩やかな順位付けの信号として扱うと、品質は12パーセント向上しました。

第二に、Loom はメモリの影響を計測可能にしました。すべての取り出しは痕跡を残し、それをメンテナーが最終的にその指摘をどう扱ったかと結合できます。「このレッスンは役に立ったことがあるか」は直感の問題ではなくなり、1本のクエリになりました。

次に来るもの

ClickHouse の開発は公開リポジトリと非公開リポジトリの両方にまたがっています。最近、完全に分離された2番目のインスタンス clickgap-private が非公開リポジトリに対して稼働を始め、1日以内に最初の Issue を起票しました。それはすぐにコールドスタート問題に直面しました。メンテナーの判定の履歴がなければ、新しいボットは、公開インスタンスがすでに学び終えたあらゆる間違いを繰り返しかねません。

非公開インスタンスは、空の状態から始まった自身の名前空間へ書き込み、公開名前空間への一方向の結合を通して読み取ります。クエリ時には、数千の公開メモリに符号化された経験を継承しつつ、自身が学んだことはすべて非公開のまま残ります。

難しかったのは、「一方向」を絶対にすることでした。ClickGap は、結果の強化と来歴リンクのために、想起したメモリに対して書き込みを発行します。しかし結合の後では、想起したキーが公開名前空間に属していることがあります。そのため、すべての書き込みはキーの所有権でフィルタされ、サーバーも独立して名前空間の境界を強制します。公開側の検索が非公開のキーを返すことは決してありません。2重の安全装置を使うのは、この種の漏えいは無音で起きるからです。

経験がコードベースをまたいで引き継がれるかどうかは、まだ答えの出ていない、しかし計測はできる問いです。想起から結果までを追う同じ計測が両側で動いています。1四半期後にまた聞いてください。

clickgap-private が 0 ではなく N から始まる仕組み。読み取りは名前空間をまたいで一方向に連合し、書き込みはキーの所有権でフィルタされます。何もコピーされず、非公開のものは何も戻りません。コピーではなく、クエリ時の継承です。

自分のコードベースにも欲しいなら

これらの原則の大半は、ボットを作らなくても当てはまります。ソフトウェアの形に落とし込み、機械的に守らせる、規律ある QA の文化を述べているからです。

  1. 1つのコードベースに絞り、それを本気で守る。 ClickGap の精度の大半は、モデルではなく ClickHouse 固有の知識から来ています。
  2. 外部に何かが起きる前に、証拠の通行料を課す。 実行されたテスト、検証済みの引用、そしてユーザーが気づく結果を要求します。
  3. 決定論的に書ける場所はどこでも決定論的に書く。 エージェントの挙動はぶれますが、for ループはぶれません。
  4. 自信に満ちた否定を、最も危険な出力として扱う。 偽陽性は午後の時間を無駄にします。偽陰性は欠陥を次の防御線に残し、その次の防御線がユーザーであることもあります。
  5. 未確認の容疑者を決して名指ししない。「範囲が不完全」のほうが、間違った作者よりましです。
  6. すべてのレポートを10秒で読み取れるように設計し、結果に基づいて絞る。 人間が関与しなくなったら、自動的に起票を減らします。
  7. 人間の判定だけをドクトリンにする。 メモリが結果を改善するかどうかを、そうだと仮定するのではなく計測します。
  8. 地道な作業の予算を取る。 機能1つにつき修正3つを見込みます。修正が集中するのは、信頼、状態の復旧、そして自身の CI を正しく解釈することです。

要点

私たちが ClickGap を作ったのは、マージストリームが人間のレビュー能力を超えて育っていたからです。結果は、この賭けが報われたことを示しています。およそ500件の Issue を起票し、200件以上がリンクされた修正 PR とともにクローズされ、約200件のテストカバレッジ PR を出しました。すべて公開の場で、すでに徹底的にテストされているコードベースに対してです。

この仕組みの大半は、ボットを賢くするために作ったものではありません。ボットの言うことに耳を傾ける価値を持たせるために作ったのであり、それこそが本当のプロダクトだと分かりました。そのレポートは他の全員と同じトラッカーに入り、同じ基準の証拠で採否が決まります。

この記事の数字は意図的に丸めています。公開されている件数は、ボットのアカウントに対する GitHub 検索で再現できます。

公の場で信頼を勝ち取らなければならないシステムを作ることが自分向きの問題だと思うなら、ClickHouse は採用中です

今すぐ始める

ClickHouse が自分のデータでどう動くか見てみたいですか?ClickHouse Cloud なら数分で始められ、300ドル分の無料クレジットを受け取れます。

サインアップ

この記事をシェア

  • Y Combinator icon
  • X icon
  • Bluesky icon
  • Facebook icon
  • LinkedIn icon

Subscribe to our newsletter

Stay informed on feature releases, product roadmap, support, and cloud offerings!