mantis-pipeline-adapter について
Mantis Skills向けの決定論的なオーケストレーションハーネスの設計を、対話形式で支援するスキルです。技術スタック、規模、実行環境に応じて構成や実装を提案します。
主な機能
- 01対話型ハーネス設計
- 02プログラムによる決定論的オーケストレーション
- 03状態ストアとスキーマの指針
- 04並行処理と規模拡大の助言
- 05任意のスナップショット・検索方式
活用シーン
- 01独自のエージェント構成向けハーネス設計
- 02信頼性の高い多段ワークフローの計画
- 03ロックを用いたワーカーの拡張
- 04任意の検索・SASTステージの追加
MCP 対応
分離テストやハードウェア操作向けに、制限付きAPIを提供するカスタムMCPサーバーの利用を提案します。生のLLM APIを使うハーネスでは、MCPツールの登録と呼び出しの振り分けが必要です。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-pipeline-adapterインストール後、Claude Code で/mantis-pipeline-adapterを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/mantis-kb-query.mdmantis-sast-seed.mdmantis-structural-index.md詳細
Mantis Pipeline Designer(/mantis-pipeline-adapter)
システムの目標
対話型パイプライン設計コンサルタントです。ユーザーが独自の Mantis Skills 用決定論的オーケストレーターハーネスを設計、実装できるよう支援します。信頼性、トークン効率、カスタム環境との統合に関するベストプラクティスの適用を支援します。
コマンド定義
- コマンド:
/mantis-pipeline-adapter - 説明: カスタムの決定論的オーケストレーターハーネスの設計と実装を、対話形式でガイドします。
入出力コントラクト
- 読み込み対象:
workspace/.mantis_state.json(現在のループのパスを追跡するため)。workspace/.mantis_state.jsonのactive_snapshot、snapshot_history、およびvcs_info.snapshot_idフィールド。同期を選択した対象ハーネスでのみ存在する、パスごとのスナップショットピンです(現在の単一スナップショット実行では存在しません。「リファレンスアーキテクチャのガイドライン 5」を参照)。schema.json(パイプライン仕様の正規リファレンスとして)。workspace/findings/*.json(State Store として)。workspace/learnings.jsonl(メモリのローテーションを把握するため)。- ユーザーが対話形式で入力した設定。
- 書き込み対象:
- ユーザーがカスタマイズしたオーケストレーターハーネスのコード、設定、またはアーキテクチャドキュメントを出力します。
- 前提条件:
- ユーザーが対話型の設計セッションを開始していること。
- 冪等性の保証:
- コンサルティングエージェントとして、カスタムハーネスに次の 3 つの主要な仕組みを用いて冪等性を実装するよう、ユーザーに助言します。(1)State Store の同期、(2)アトミックなトランザクションファイル/VCS 操作、(3)適切なロック(例:データベース/ファイルレベルのロック)。
指示
Mantis Skills をラップする決定論的なパイプラインの設計と構築を、対話形式でユーザーに案内してください。
相談時は、次のガイドラインに従ってください。
01. ユーザーの状況を把握する: 対象とするプログラミング言語、エージェントフレームワーク(使用している場合)、実行環境(VM、ローカルコンテナ、物理ハードウェア)、および規模の要件について尋ねます。
02. 基本原則を提案する: 以下のリファレンスアーキテクチャのパターンを実装するよう案内します。特に、次の点を重視します。
- 決定論的なオーケストレーション:制御フローにはLLMではなくコードを使用します。
- 状態ストア:唯一の信頼できる情報源として、データベースまたは構造化ファイルシステムを使用します。
- トークン効率:UUIDベースの参照パターンを使用して、LLMにテキストを重複させないようにします。
- カスタム環境との統合:分離されたテスト(VM)やハードウェアとのやり取りには、カスタムMCPサーバーを使用します。
03. スキーマの一貫性を確保する: ハーネスを構築する際は、schema.jsonで定義されているステージ間のデータ契約を厳守するようユーザーに助言します。
04. 適応的な設計: 固定的なテンプレートを押し付けるのではなく、ユーザー固有のスタックに合わせたコードやアーキテクチャの草案作成を支援します。
05. 規模と並行処理について助言する: 大規模なニーズがある場合は、パイプラインの分割や、競合状態を防ぐロック機構の実装について案内します。
06. 評価を提案する: ユーティリティステージでより安価なモデルを選ぶ場合は、実証的な評価を行うよう促します。
07. パスのライフサイクル契約について助言する(変化する/同期されるコードベース): ユーザーが、対象コードの変更後もハーネスで実行を継続したい場合や、新しいパスの開始時に対象リポジトリを同期したい場合は、以下のリファレンスアーキテクチャガイドライン5にある、ハーネスに依存しないパスのライフサイクル契約について説明します。このサポートはオプトインであることを強調します。契約を実装しないハーネスでは、snapshot_pinnedを未設定のままにする必要があります。これにより、現在の単一スナップショットの動作がバイト単位で維持されます。--syncが指定された場合、ハーネスはPINステップでPINを行い、通常どおり--snapshot_root/--snapshot_idを渡します。Block A(ロケーター解決)は、すべてのコード読み取りステージに共通です。
08. 大規模環境でのセマンティック検索について助言する: ユーザーが大規模なコードベース(例:数千のソースファイル、複数パスにわたるキャンペーン、または複数チームが調査結果を持ち寄る環境)を対象としている場合は、以下のリファレンスアーキテクチャガイドライン6および7にある、オプションのセマンティック検索パターンについて説明します。これらはオプトインであることを強調します。専用のクエリスキルまたはMCPツールを通じてパイプラインを拡張しますが、既存スキル独自の決定論的ロジックやフェイルセーフ不変条件は決して変更しません。
09. SASTによるシード投入について助言する: ユーザーが外部のSASTツール(CodeQL、Semgrepなど)の検出結果でLLMベースの発見を拡張したい場合は、以下のリファレンスアーキテクチャガイドライン8にある、オプションのSASTシード投入パターンについて説明します。これはオプトインであることを強調します。外部の検出結果を候補として取り込みますが、判定を得るには変更されていない後続のゲートを通過する必要があります。また、RAGパターンとまったく同じく、来歴を追跡し、スナップショットを認識し、失敗時にはフォールバックします。
10. 構造的コードインデックスについて助言する: grepベースの呼び出し元検出の信頼性が低い大規模なコードベースを対象としている場合は、以下のリファレンスアーキテクチャガイドライン9にある、オプションの構造的コードインデックスステージについて説明します。これはオプションの第一級ステージであることを強調します。構造的なコンテキスト(関数境界、呼び出しグラフ)を提供してLLMの推論を改善し、スナップショットのPIN後、最初のコード読み取り分析ステージの前に実行されます。利用できない場合は、適切にgrepへフォールバックします。
11. 段階的な反復再現と複数会話でのリトライについて助言する: 単発の再現が不安定になりやすい複雑なサービスを対象としている場合は、リファレンスアーキテクチャガイドライン10にある、段階的な反復再現戦略と複数会話でのリトライパターンについて説明します。
リファレンスアーキテクチャのガイドライン
ユーザーに助言する際の技術的な参考として、以下のガイドラインを使用してください。
コア原則
- 決定論的なオーケストレーション: LLM にパイプラインの制御フローを決定させないでください。プログラムによるハーネスを使用して、スキルを順次または並列に呼び出してください。
- ディスク/データベース上の状態: ファイルシステム(
workspace/findings/*.json)またはデータベースを、唯一の信頼できる情報源として使用してください。スキルはこのストアから読み取り、書き込むようにします。水平スケーリングを行う場合は、集中管理型のデータベースを推奨してください。 - 決定論的なレポート作成: 検出結果は内部状態として扱ってください。JSON の検出結果を人が読める Markdown レポートに変換する際の LLM の使用は最小限に抑え、代わりに決定論的なスクリプトを作成して JSON をレポートにレンダリングするか、バグトラッカーにアップロードしてください。必要に応じてエグゼクティブサマリーを提供するなど、テキストの統合といった非決定論的な部分に限って LLM を使用してください。
- トークン効率と再利用可能な決定論的ツール: LLM の出力は、必要最小限の情報(UUID、ステータスコードなど)のみを返すように構成してください。JSON フィールドの追加や検出結果のマージといった定型作業のために、LLM にその場限りのスクリプト(Python や bash など)を書かせないでください。推論トークンが無駄になるためです。代わりに、テキスト操作や状態の更新を実行する際に LLM が呼び出すだけで済む、再利用可能で決定論的なツール(事前に作成したヘルパースクリプトや MCP エンドポイントなど)をハーネスから提供してください。
- 状態ストアとメモリのローテーション: トークンの肥大化や無限ループを防ぐため、一時キュー(
workspace/learnings.jsonlなど)はローテーションする必要があります。ナレッジベースの統合ステージが正常に完了し、検証された後、オーケストレーターはアーカイブディレクトリが存在することを確認し(例:mkdir -p workspace/archive/learnings/)、workspace/learnings.jsonlを番号付きのアーカイブに移動してください(例:${N}がループのパス、${X}がサブインデックスを表すworkspace/archive/learnings/learnings_pass_${N}_${X}.jsonl)。統合に失敗した場合、データ損失を防ぐため、アクティブなキューはそのままにしておく必要があります。
アーキテクチャの概要
graph TD
Harness[Programmatic Harness / Orchestrator] <--> DB[(State Store: Disk/DB)]
subgraph Stages [Decomposed Stages]
KB[KB Architect]
TM[Threat Modeler]
P[Plan]
R[Researcher]
D[Deduplicator]
V[Validator/Review]
C[Critic]
Rep[Reproducer]
Ch[Chainer]
Pat[Patcher]
Cal[Calibrator]
Ref[Reflector]
end
Harness --> KB
Harness --> TM
Harness --> P
Harness --> R
Harness --> D
Harness --> V
Harness --> C
Harness --> Rep
Harness --> Ch
Harness --> Pat
Pat -.->|Re-attack Bypass Loop| Rep
Harness --> Cal
Harness --> Ref
subgraph LLM Pool [Tailored LLMs]
ModelA[Frontier Model: Deep Reasoning]
ModelB[Flash/Lite Model: Fast & Cheap]
ModelC[Alternative Provider: Diversified Logic]
end
KB -.-> ModelA
TM -.-> ModelB
P -.-> ModelB
R -.-> ModelA
R -.-> ModelC
D -.-> ModelB
V -.-> ModelB
C -.-> ModelA
Rep -.-> ModelA
Ch -.-> ModelA
Pat -.-> ModelA
Cal -.-> ModelB
Ref -.-> ModelB
1. UUID ベースの参照パターン
LLM がテキストの大きなブロックを繰り返すのを防ぐため(これによりレイテンシーとコストが増加し、データを破損するリスクも高まります)、すべての検出結果の主キーとして UUID を使用してください。
A. 調査ステージ
- アクション: コードベースを調査し、潜在的な脆弱性を特定します。
- LLM の出力: 検出結果ごとに一意の UUID を生成し、詳細情報をすべて含む
workspace/findings/<UUID>.jsonを書き込みます(Mantis Researcher の標準スキーマに準拠)。
B. 重複排除ステージ(最適化)
LLM にすべての検出結果を読み込み、コンテキスト内でマージしてから書き戻すよう求める代わりに、以下のパターンを使用してください。
-
ハーネスのアクション: すべての
workspace/findings/*.jsonファイルを読み込み、キー識別子のみを含む要約リストを LLM 用に準備します。標準スキーマに合わせるため、code_paths配列("file:line"形式を使用)を、LLM 用の簡略化された要約にマッピングします。[ { "id": "UUID", "file": "path", "line": 12, "snippet": "..." } ]。 -
LLM のアクション: 要約を分析し、重複のマッピングを出力します。
{ "primary_uuid_1": ["duplicate_uuid_a", "duplicate_uuid_b"], "primary_uuid_2": [] } -
ハーネスのアクション(決定論的):
- 影響を受けるファイルの内容を読み込みます。
- Mantis Deduplicator のルールに従ってフィールドをプログラムでマージします(例:
code_pathsの和集合、最も高い深刻度の採用、履歴の連結)。 - ディスク上の
workspace/findings/primary_uuid_1.jsonを更新します。 - ゴミ箱ディレクトリが存在することを確認します(例:
mkdir -p workspace/findings/.trash/)。 workspace/findings/duplicate_uuid_a.jsonとworkspace/findings/duplicate_uuid_b.jsonを、ゴミ箱のステージングディレクトリ(workspace/findings/.trash/)に移動します。
C. 検証とレビューのステージ(レビュアー、批評役)
- ハーネスのアクション: 各指摘事項
workspace/findings/<UUID>.jsonについて、関連するコードコンテキストと指摘事項の説明のみを LLM に渡します。 - LLM のアクション: 構造化された検証結果のみを出力します(例:
{"valid": true, "reason": "..."})。 - ハーネスのアクション(決定論的): 検証ステータスと理由を使って、
workspace/findings/<UUID>.jsonファイルをプログラムで更新します。
2. カスタム MCP による適応可能なリプロデューサー
指摘事項を検証する際、エージェントは多様な環境(VM、物理ハードウェア)と やり取りする必要がある場合があります。**Model Context Protocol(MCP)**を 使って、制限された明確な API を公開します。
- アーキテクチャ:
[Reproducer Agent] <--- MCP ---> [Custom MCP Server] <--- API ---> [Target Env] - カスタム環境:
- VM:
reboot_vm()、execute_payload()などのツールを実装します。 - ハードウェア/USB:
power_cycle_device()(スマートプラグ経由)、send_usb_packet()などのツールを実装します。
- VM:
- 統合に関する注意: ユーザーのハーネスが MCP ネイティブのクライアント フレームワークではなく、生の LLM API(直接の Gemini API 呼び出しなど)を 使用する場合、ハーネスでこれらのツールを API のスキーマ形式に手動で登録し、 ツール呼び出しを MCP サーバーにディスパッチする必要があります。
3. 分解とマルチモデル戦略
A. パイプラインの分解と並行処理
パイプラインは独立したサービスに分割できます。水平方向にスケールする場合
(たとえば、複数のワーカーが Reproducer ステージを並行して実行する場合):
- 並行処理の制御: 2 つのワーカーが同じ指摘事項を同時に処理または更新しないよう、データベースロックまたはファイルロックを実装します。
- 並列軌跡探索: 深い推論を行うステージ(
Reproducer、Patcher)では、さまざまなロジック経路を使ってまったく同じ指摘事項の解決を試みる 複数のエージェントを並行して起動します。Reproducerステージでは、あるワーカーが 成功した時点で他のすべての軌跡を打ち切り、LLM の「諦める」ループから脱却しつつ、 計算コストを節約します。Patcherステージでは、すべてのパッチが生成されテストされるまで 待機し、その後、成功したものを評価して、最小限で慣用的かつ正確な修正を選択します。
B. 異種 LLM の選択(マルチモデル)
タスクの複雑さに応じて、適切なモデル階層を選択します。
- 最先端モデル:深い推論(調査、再現、パッチ適用)向けです。
- Flash/Lite モデル:構造化されたユーティリティタスク(重複排除、調整)向けです。
- 多様性:バグ検出の範囲を広げるため、調査ステージで異なるモデルを並行して実行します。
C. 評価の重要性
重複排除や調整などのユーティリティステージに低コストのモデルを使う場合は、 品質が低下していないことを確認するため、ベンチマークデータセットに対する 実証的な評価で検証する必要があることを強調します。
4. 計画ステージと workspace/plan.json
計画ステージは、セキュリティキャンペーンを構成するうえで重要な役割を果たします。
ストラテジスト(/mantis-plan)は workspace/plan.json を生成して、対象を絞った
調査、コンテキストへのポインター、監査担当者への具体的な質問を定義します。
リサーチャー(/mantis-researcher)は起動時に workspace/plan.json を読み込み、
調査の指針とします。この構造化された契約を介して戦略と実行を分離することで、
オーケストレーターはサブエージェントに簡単に指示を出し、調査を並列化し、作業を
繰り返すことなくパイプラインの実行間で過去のコンテキストを維持できます。
5. パスのライフサイクル契約(継続的に更新・同期されるコードベース)
独自のオーケストレーター(専用 CLI、ADK エージェント、MCP ネイティブのパイプライン、または決定論的なハーネス)は、mantis-meta-agent が実装する継続的なプロジェクトのライフサイクルを引き継ぎません。編集後の続行とオプトインによる境界同期を、誤った結果を気づかれないまま生み出すことなく(誤った VERIFIED_SECURE、誤った failed_to_reproduce、回帰の取りこぼし)サポートするには、ハーネスで以下のハーネスに依存しない契約を実装する必要があります。これは schema.json の Non-JSON Contracts に記録された契約と同じです。以下の Block A~Block G および SNAPSHOT_ID への参照は、各 Mantis ステージが独自の SKILL.md ですでに備えている仕組みを指しています。
Mantis は複数のハーネス(各種 CLI、ADK、カスタムの決定論的パイプライン)で動作するため、ライフサイクルを mantis-meta-agent だけに置いてはなりません。ハーネスは、各パスで以下を実行する場合に限り、準拠します。
- 最初に SYNC する(Block C)— 必ず最初のアクションとし、パスの途中では実行しません。
vcs_infoを検出し、SNAPSHOT_IDを計算する(Block D の手順 1~5)— 同期後にのみ実行します。- 不変のコピーを PIN し、センチネルを書き込み、
snapshot_historyに 追加 する(Block D の手順 5。RECORD ではありません)。 vcs_info(snapshot_idを含む)とactive_snapshotを 記録 する。同期前に ID を記録したり、PIN したりしてはなりません。- すべてのステージを
--snapshot_root=<SNAPSHOT_ROOT> --snapshot_id=<SNAPSHOT_ID> --state_root=<workspace parent>を指定して 実行 する。 - 既存の Stage 15 で アーカイブしてインクリメント する。再試行された検出結果では、元の
discovery_commitを保持します。
この契約を実装しないハーネスは、snapshot_pinned を未設定のままにする必要があります。これは現在の動作です。--sync が要求された場合、ハーネスは PIN の手順で PIN し、通常どおり --snapshot_root/--snapshot_id を渡します。Block A(Locator Resolution)は、すべてのコード読み取りステージに共通です。
ビルダーがこの契約を実装する際の注意事項
- オプトインで、デフォルトはオフです。 同期/ピン留めは、ビルダーが有効にする機能です。
snapshot_pinnedを一度も設定しないハーネスは、これまでどおり(実行ごとにライブスナップショットを1つ使用)動作します。下流のステージでは、active_snapshot/discovery_commitがない場合は保守的な分岐を選ぶため、アップグレードされていないハーネスも常に安全です。ただし、変化するプロジェクトの状態は反映されません。これらのフィールドがないことをエラーとして扱うよう助言してはいけません。 - スナップショットは
workspace/の外に保存します。 ピン留めされたコピー(SNAPSHOT_ROOT)は<state_root>/.mantis_snapshots/pass_<N>の下(またはVCSの状態がクリーンなworktree/アーカイブ)に置き、そのパスに/workspace/というセグメントを含めてはいけません。含めると、mantis-patchの状態とコードのパスガードが誤作動します。直近の2つのスナップショットを保持し、それより古いものは対応するティアダウン処理でガベージコレクションします(コピーの場合はrm -rf、worktreeの場合はgit worktree remove/prune)。 - 非破壊的な同期のみを行います。 同期はパスの最初の処理であり、パスの途中で行ってはいけません。また、ツリーがdirty、upstreamより先行、detached、またはupstreamがない場合はスキップする必要があります。ハーネスは
git reset --hard、git checkout -- .、git clean、hg update -Cを決して実行してはいけません。また、未コミットの状態、追跡されていない状態、ローカルコミットの状態を破棄するコマンドも実行してはいけません。ユーザーの編集内容や進行中の作業は、すべてのパスで保持されなければなりません。 - dirty/VCSなしの場合も、完全な情報を含む
SNAPSHOT_IDsを使用します。 IDはピン留めされたコピー全体を対象に計算します。cleanなgit/hgの場合はcommit_hash、dirtyなgit/hgの場合はcommit_hash + ":" + content_hash、複数のVCSがある場合はrevision + ":" + content_hash、VCSなし/不明だがコピー可能なツリーの場合は"content:" + content_hashです。埋め込まれたcontent hashがあることで、変更されていないdirtyまたはVCSなしのツリーはパスをまたいで一致し、検証と重複排除も実行できます。また、manifestのrevisionが変わらなくても、コミットを進めるrepo syncは不一致として判定されます。ブランチ名だけ、またはmanifestのrevision文字列だけをIDとして信頼してはいけません。 - 3つのルートをすべてのステージに渡します。 findingsのみを扱うステージ(report、calibrate、reflect)も含めます。これらのステージは対象コードを読みませんが、出所情報/注釈のために
active_snapshotを読み取ります。ハーネスがアーカイブを作成して番号を増やす場合、再試行されたfindingsには元のdiscovery_commitを維持する必要があります。
適合性シナリオ
以下のシナリオでは、スナップショットモデルにおけるほぼすべての問題が明らかになります。これらは参照チェックであり、機能ではありません。各環境でそれぞれを防止または処理する責任はハーネスにあります。表はクイックリファレンスです。各シナリオの詳細は後述します。State列では3-STATE RULE(active_snapshotの有無に応じたMODE-OFF/HALT/PINNEDの分岐)を使用します。schema.jsonのグローバルな後方互換性ルールと上記の注意事項を参照してください。SNAPSHOT_IDの形式は上記の注意事項の段階的なルールに従います(例:live:<ts>は、ピン留めされていない/HALT状態のパスを示します)。
不変条件の凡例(以下のラベルは、ブロックおよびschema.jsonのグローバルな後方互換性ルールによって適用される安全特性を示します):
| ラベル | 特性 | 適用箇所 |
|---|---|---|
| INV-1 | 誤ったVERIFIED_SECUREを防止 | ブロックG + HALT時の上限 |
| INV-2 | 誤ったfailed_to_reproduceを防止 | ブロックF + HALT時の上限 |
| INV-3 | 回帰の見落としを防止 | ブロックBのNOT_MATCHED + POSSIBLE REGRESSION |
| INV-4 | パス内の一貫性 | ブロックAのセンチネル + 単一のピン留めスナップショット |
| INV-5 | ユーザーデータの損失を防止 | ブロックCの非破壊的な同期 + ブロックAのステップ4 |
| INV-6 | データが欠落した場合に安全側に動作 | グローバルな後方互換性ルール |
クイックリファレンス表:
| # | シナリオ | 状態 | ハーネスの動作 | ステージの動作 | ブロック/INV | 主要フィールド |
|---|---|---|---|---|---|---|
| 1 | 状態の共配置 | PINNED | HALTして制御を返します(安全なデフォルト)。明示的に許可された場合(例:--auto_relocate_state)は、state_root を CODE_ROOT の外に移動します。SNAPSHOT_ROOT のパスに /workspace/ を含めてはいけません | mantis-patch の状態とコードのガードが誤作動します。Block A のステップ 3 では、SNAPSHOT 相対パスと STATE 相対パスを混同します | A:3, D:3; INV-5 | active_snapshot.root、snapshot_root、state_root |
| 2 | 古い active_snapshot(active_snapshot.pass != state.pass_number) | PINNED → STOP または HALT による劣化 | Block D のステップ 0:同一パスでの再エントリーのみ処理します。ディレクトリが存在しない場合は STOP し、ユーザーに制御を返します | Block A のステップ 2 のセンチネルは依然として MATCH する可能性があります(ディレクトリが保持されている場合)。CURRENT-PASS CHECK(active_snapshot.pass == state.pass_number)が必須です。不一致の場合は STOP または HALT による劣化とし、Block B は NOT_MATCHED(信頼できる判定なし)となります | A:2, D:0, B; INV-1, INV-3, INV-4, INV-6 | active_snapshot.{root, snapshot_id, snapshot_pinned, pass}、state.pass_number、discovery_commit |
| 3 | ピン留めの失敗 | HALT | Block D のステップ 2/4:ENOSPC/エラー時はコピーをスキップしてステップ 5b に進みます。それでも active_snapshot とパスのルートを書き込みます | 信頼できる判定は禁止です。Block B は常に NOT_MATCHED となります。再現結果は not_attempted とし、パッチは VERIFICATION_INCOMPLETE となります | D:2, D:4, D:5b; INV-1, INV-2, INV-6 | active_snapshot.{snapshot_id, snapshot_pinned} |
| 4 | パッチ適用済みシャドウ | PINNED(パス);--snapshot_pinned=false 引数 | 再攻撃サブエージェントに --target_root=<PATCHED_SHADOW_ROOT> と --snapshot_pinned=false を渡します | Block A のステップ 1a:CODE_ROOT=--target_root(信頼できる値)。ステップ 2 のセンチネルは SKIPPED(センチネル対象外) | A:1a, A:2; INV-4 | target_root、snapshot_pinned(引数)、snapshot_root、discovery_commit |
| 5 | 異なるスナップショット間の重複候補 | PINNED | 特別な対応は不要です。両方のパスで正しくピン留めされ、重複排除で処理されます | Block B のペアごとの判定:discovery_commit が異なる場合は NOT_MATCHED となり、ACTIVE と possible_duplicate_of を維持します。アーカイブ済みの候補が RESOLVED の場合は、POSSIBLE REGRESSION となります | B; INV-3, INV-6 | discovery_commit、possible_duplicate_of、status、patch_status |
| 6 | シンクの証拠がない | 任意 | 特別な対応は不要です。Block F はステージレベルの機械的なゲートです | Block F:証拠がない場合(ビルドエラー、終了コード 127、シンク未到達)は not_attempted(再試行可能)となり、failed_to_reproduce には決してなりません。HALT の上限によっても not_attempted が強制されます | F; INV-2, INV-6 | repro_status、reattack_status、repro_hints |
| シナリオごとの詳細: |
1. 同じ場所に配置された状態(state_root が CODE_ROOT/スナップショットルート内にネストされている)
— 固定する SNAPSHOT_ROOT は
<state_root>/.mantis_snapshots/pass_<N>(または VCS がクリーンな worktree/アーカイブ)配下に置く必要があり、そのパスに /workspace/ セグメントを含めてはなりません。含まれていると、mantis-patch の状態とコードのパスガードが誤作動します(状態ファイルが「CODE_ROOT 配下」にあるように見えます)。state_root 自体が CODE_ROOT 内にある場合、ハーネスは停止して制御を返す(安全なデフォルト動作)か、明示的に許可されている場合(例:--auto_relocate_state)は、固定する前にスナップショットの外へ移動する必要があります。ブロック A のステップ 3 では、スナップショット相対のパスフィールド(CODE_ROOT 配下から読み取る)と状態相対のフィールド(state_root/workspace から読み取り、CODE_ROOT を前置しない)を区別しています。同じ場所への配置はこの分離を損ないます。
2. 古い active_snapshot(active_snapshot.pass != state.pass_number — active_snapshot が Stage 15 のパス番号増加をまたいで保持されていた場合)— ブロック D のステップ 0(クラッシュ後の再開)が処理するのは、同じパスでの再入場ケース(active_snapshot.pass == N → 再利用)のみです。Stage 15 は pass_number を増加させながら active_snapshot を意図的に保持するため、Stage 15 のパス番号増加をまたいで引き継がれた古いスナップショットは検出しません(Stage 15 を参照)。次の 2 つのサブケースがあります。
(a) 以前のスナップショットディレクトリがすでに存在しない場合:ブロック D のステップ 0 は停止してユーザーに制御を返します(ドリフトした可能性のあるライブツリーを再固定することは決してありません)。(b) 以前のスナップショットディレクトリがまだ存在し(デフォルトの保持数 2)、そのセンチネルが保持された active_snapshot.snapshot_id と一致する場合:ブロック A のステップ 2 のセンチネルチェックは成功します(センチネルファイルと SNAPSHOT_ID のみを比較し、現在のパスとは比較しません)。ブロック B の discovery_commit のペアワイズチェックは、引き継がれた検出結果を、同じ古い SNAPSHOT_ID が付与された新しい検出結果と一致させ、誤った権威的判定として黙って DUPLICATE 扱いにして破棄します。
(b) を防ぐため、HARNESS は、コンシューマーステージが読み取る前に active_snapshot.pass == state.pass_number であることを保証する必要があります。リファレンスハーネス(mantis-meta-agent)は、すべてのパスで再固定することでこれを満たします(ブロック D のステップ 0 が active_snapshot.pass != N を検出 → 再固定 → ステージ実行前に active_snapshot.pass を更新)。そのため、ここではサブケース (b) は発生しません。Stage 15 のパス番号増加をまたいで active_snapshot を保持しながら再固定しないカスタムハーネスは、(a) すべてのパスで再固定する(リファレンスの動作)か、(b) ステージを呼び出す前に active_snapshot.pass を更新する、または active_snapshot を完全にクリアする、同等の事前ステージゲートを挿入する必要があります。ステージはブロック B でこの古さを自力で検出できません(ブロック B は snapshot_id のみを対象とし、pass は考慮しません)。同じ古い SNAPSHOT_ID が付与された引き継ぎ済みの検出結果と新しい検出結果は、スナップショットが古くてもブロック B で一致します。active_snapshot.pass フィールドは、まさにこのチェックのために schema.json の #/$defs/state/active_snapshot/pass で定義されています。ハーネスのブロック D のステップ 0 にある再利用チェックは代替にはなりません。このチェックが実行されるのは、同じパスでの再入場時のみです。(active_snapshot を読み取るステージは、防御策としてさらに自分でチェックしてもかまいません。各ステージのステップ 0 のセンチネルチェックを参照してください。ただし、保証を担うのはハーネスです。)
3. ピン留めの失敗(スナップショットのコピーに失敗 — ディスク容量不足、権限不足、ツリーが大きすぎるなど)— Block D のステップ 2(空き容量の事前チェック):ライブツリーの du -s の結果と、state_root における df の空き容量を比較します。収まらない場合は → コピーをスキップ → ステップ 5b。Block D のステップ 4(失敗を許容する検証):コピーの終了ステータスと妥当性チェック(ファイル数/サイズが約 90%以内)を確認します。失敗した場合は → ステップ 5b(ピン留めなし/HALT)。ステップ 5b:SNAPSHOT_ROOT=<live root>、snapshot_pinned=false、SNAPSHOT_ID="live:"+ISO8601。ハーネスは引き続き active_snapshot を書き込み、ステージに --snapshot_root/--snapshot_id を渡して HALT シグナルを認識させます。その後、各ステージは保守的に動作します。権威ある判定(VERIFIED_SECURE、failed_to_reproduce、DUPLICATE、FALSE_POSITIVE、NON_VIABLE)は禁止されます。Block B は常に NOT_MATCHED を返し、再現処理は not_attempted を記録します。パッチ処理で達成できる最善の結果は VERIFICATION_INCOMPLETE です。
4. パッチ適用済みシャドウ(--target_root が変更済みツリーを指す場合。Block A のセンチネル対象外パス 1a)— mantis-patch は再攻撃検証のため、--target_root=<PATCHED_SHADOW_ROOT> と --snapshot_pinned=false を再現処理のサブエージェントに渡します。Block A のステップ 1a:CODE_ROOT = --target_root(権威ある上書き。--snapshot_root と state のフォールバックを上書きします)。Block A のステップ 2:センチネルチェックをスキップします(--target_root のツリーは意図的に変更されており、センチネルの対象外です)。--snapshot_pinned=false 引数はセンチネル対象外を示すものであり、HALT シグナルではありません。この呼び出しで渡された引数からではなく、STATE を読み取って HALT を検出してください(active_snapshot.snapshot_id が live: で始まる場合。STATE 内の active_snapshot.snapshot_pinned が false の場合と同じです)。検出結果の discovery_commit は影響を受けません。発見時のパスレベルの SNAPSHOT_ID を保持します。--snapshot_pinned=false 引数が適用されるのは、再攻撃の呼び出しに限られます。
5. 異なるスナップショットの重複候補(discovery_commit が異なるパス間の重複排除。Block B のペアワイズ NOT_MATCHED パス)— 両方のパスで正しくピン留めされています。検出結果が異なるスナップショットに由来するだけです。mantis-dedupe の Block B におけるペアワイズチェックでは、現在の検出結果の discovery_commit を、アーカイブ済みの検出結果の discovery_commit と比較します(グローバルな SNAPSHOT_ID とは比較しません)。異なる場合は → NOT_MATCHED。NOT_MATCHED の場合、現在の検出結果を ACTIVE のままにし、possible_duplicate_of を設定します(これはソフトな非終端のヒントです。検出結果はフィルタリングも破棄もされません)。アーカイブ済みの検出結果が RESOLVED(patch_status が {VERIFIED_SECURE、MITIGATION_PROPOSED} のいずれか、または status==FALSE_POSITIVE、または production_viability==NON_VIABLE)であり、かつペアの判定が NOT_MATCHED の場合は、POSSIBLE REGRESSION とします。ACTIVE のままにし、履歴メモを追加し、決してフィルタリングしません(新しいコード上で元に戻された修正が再発見された場合、決して破棄してはいけません)。
6. シンクの証拠がない場合(Block F — PoC はコンパイルされるが、到達したシンクの証拠がない場合。not_attempted と failed_to_reproduce の区別)— mantis-reproduce Block
F:EVIDENCE が ABSENT の場合(コンパイラー/ビルドの終了コードが 0 以外、終了コード 127 のコマンド未検出、終了コード 2 の「No such file」、またはシンクに到達していない場合)は、repro_status = not_attempted(再試行可能)として、停止します。failed_to_reproduce にしてはいけません。
--reattack モードでは、履歴メモに「setup_failed」と記録し、reattack_status は UNSET のままにします。failed_to_bypass にしてはいけません。failed_to_reproduce は、ハーネスが脆弱なエントリーポイントに到達したことを確実に証明できる場合、つまりセットアップの証拠ではなく、到達したシンクの証拠がある場合に限り使用します。ただし、バグが発生しなかった場合に限ります。到達したシンクの証拠は、呼び出されたパス内部、またはターゲットが生成したトレース/バックトレースから得られる必要があります。(a)PoC スクリプト/ソースハーネスが、シンク呼び出しの直前に、その実行フロー内でサイドカーファイルへ MANTIS_REACHED_ENTRYPOINT を書き込む(マーカーの書き込みは呼び出されたパスの一部であり、起動前の手順ではありません)、または(b)バイナリ/ファームウェア/raw ペイロードを対象とする場合、取得されたクラッシュバックトレースまたはサニタイザートレース(ASan/UBSan/MSan/TSan)がターゲットのシンク関数を明示的に示す(ターゲットが生成したトレース)。ターゲットを呼び出す前に外部ラッパーが書き込むマーカーは、セットアップの証拠にすぎず(「起動を試みた」ことは証明しますが、「シンクに到達した」ことは証明しません)、それだけでは failed_to_reproduce の根拠になりません。判定ゲートでは、EVIDENCE ABSENT として扱います。
証拠は repro_hints に記録します。HALT モードでは、HALT の上限によってさらに not_attempted が強制されます(failed_to_reproduce にはしません)。これは、ピン留めされていないツリーでの否定的な結果は、信頼できる確定的な証拠として扱えないためです。
6. 大規模コードベースのセマンティック検索(RAG)
小規模なリポジトリでは、プランナーが workspace/kb/index.md を手動でスキャンし、リサーチャーが呼び出し箇所を grep できます。大規模な環境(数千のファイル、深いディレクトリツリー、複数回のパスを重ねるキャンペーン)では、これらの方法では関連するコンテキストを見落とし、無関係なファイルを読むためにトークンを浪費します。セマンティック検索レイヤーにより、すべてを読み込まずに、関連する KB エントリーやコードの場所をプランナーとリサーチャーが検索できます。
同じデータ契約を共有する、次の 2 つの実装をサポートしています。
- オプション A(デフォルト — スキルベース):
chunks.jsonlに対して BM25/TF-IDF ヘルパースクリプトを実行する専用スキルです。外部依存関係は不要で、エアギャップ環境でも動作し、ベクトル埋め込みやベクトルストアも必要ありません。利用可能な場合は、オプションでベクトル埋め込みをサポートします。 - オプション B(最大規模 — MCP ベース): ハーネスがベクトル埋め込みを使用する永続的なベクトルインデックスを所有し、永続的な
semantic_search_kb/semantic_search_codeMCP ツールを提供します。呼び出しごとの BM25 では遅すぎる、非常に大規模なコードベースに適しています。
どちらも オプトイン です。既存のスキルは変更せず、プランナーとリサーチャーには、利用可能な検索メカニズムを使用するよう実行時の指示を提供します。どちらも存在しない場合は、現在の手動での動作にフォールバックします。検索結果は カバレッジのヒントにすぎません。順序付けと優先順位付けには使用しますが、監査対象セットの構成は決定しません。検索で見つからなかったことを理由に、ファイル、呼び出し箇所、調査を省略または除外してはいけません。
A. 共有データ契約:chunks.jsonl
ステージ 2(/mantis-architecture)の完了後、チャンクは
workspace/kb/chunks.jsonl に抽出されます(1 行につき JSON オブジェクト 1 つ)。ハーネスは
workspace/kb/*.md を読み取って後から生成することも、アーキテクチャスキルに
合成中にテキストのみの副作用として書き出すよう指示することもできます。生成されるチャンクは
次の 2 種類です。
-
既存の
workspace/kb/*.mdファイルから生成される KB チャンク:{"id": "auth_module:0", "source_file": "workspace/kb/entities/auth_module.md", "entity_type": "entity", "chunk_text": "The auth module handles..."} -
CODE_ROOT(固定されたスナップショット)から生成される コードチャンク。各チャンクには ファイルパスと行範囲が含まれるため、リサーチャーはスナップショットから特定のファイルを 要求できます。{"id": "src/parser.c:0", "source_file": "src/parser.c", "start_line": 1, "end_line": 80, "chunk_text": "int parse_input(..."}
chunks.jsonl の 1 行目は、チャンクの生成元となった SNAPSHOT_ID を記録する
来歴ヘッダーです。
{"_provenance": true, "snapshot_id": "abc123", "kb_snapshot_id": "abc123"}
クエリを提供する前に、来歴ヘッダーの snapshot_id と現在の
SNAPSHOT_ID を照合し、異なる場合は再構築してください。MODE-OFF(
active_snapshot なし)では、kb_snapshot_id はスタンプされません。インデックス全体を
スキップし、スキルが手動スキャンにフォールバックするようにしてください。ライブツリーからコードチャンクを
生成しないでください。スキルが読み取る固定コピーを反映している必要があります。
B. オプション A:スキルベースの検索(デフォルト — インフラ不要)
専用スキルが chunks.jsonl を読み取り、BM25/TF-IDF 類似検索を実行するヘルパースクリプト(例:
workspace/helpers/search_chunks.py)を書き出して実行します。このスクリプトは実行時にエージェントが生成します。スキルに
コードは同梱されません(mantis-dedupe の merge_findings.py と同じパターンです)。これには
外部依存関係が一切不要です。埋め込みモデル、ベクトルストア、MCP サーバーも必要ありません。
エアギャップ環境や VPC-SC 環境でも動作します。
このスキルの完全なリファレンスブループリントは、
references/mantis-kb-query.md で確認できます。ビルダーは
環境に合わせて調整できます。ブループリントには、ブロック A(ロケーター解決)、
チャンクの来歴チェック、バージョン管理されたヘルパースクリプト契約
(MANTIS_HELPER_VERSION = 1)、および JSON 出力スキーマが含まれています。
- 呼び出し: プランナーまたはリサーチャーが、クエリ文字列を指定してスキルをサブエージェントとして起動します。スキルはヘルパーがまだ存在しない場合は作成し、実行して、上位 K 件の一致するチャンクを JSON として返します。
- オプションの埋め込み: ベクトル埋め込みが利用可能な場合、BM25 の代わりにコサイン類似度を使うようエージェントに指示できます。これは実行時の設定切り替えであり、別のスキルではありません。
- スナップショットの安全性: スキルはブロック A を介して状態から
active_snapshotを読み取り(他のすべてのスキルと同様)、提供前にチャンクの来歴をチェックします。
C. オプション B:MCP ベースの検索(最大規模向け)
呼び出しごとの BM25 が遅すぎる非常に大規模なコードベースでは、ハーネスがベクトル埋め込みを使う永続ベクトルインデックスを管理し、ガイドライン 2 の VM/ハードウェア向けカスタム MCP と同じパターンで、次の 2 つの MCP ツールを提供できます。
-
semantic_search_kb(query: string) → [{id, source_file, entity_type, chunk_text, score}]— KB チャンクを検索します。関連するエンティティ/脆弱性の Markdown コンテキストを返します。 -
semantic_search_code(query: string) → [{file, start_line, end_line, snippet, score}]— 固定されたスナップショットのコードチャンクを検索します。関連するコードの位置を返します。
ハーネスはベクトルインデックスのライフサイクルを管理します。chunks.jsonl(または
CODE_ROOT から直接)を使って構築し、SNAPSHOT_ID が変わったら再構築し、鮮度チェックも処理します。HALT モードでは、STALE フラグを付けて提供するか、提供を拒否します。MODE-OFF では、処理をすべてスキップします。
D. スキルごとの拡張ガイダンス
検索メカニズム(スキルまたは MCP)が利用可能な場合、以下のスキルに対してそれを使用するよう指示します。これらはスキルを呼び出す際にハーネスまたはメタエージェントから渡される実行時の指示であり、スキルファイル自体は変更されません:
-
mantis-architecture: 変更は不要です。ハーネスは、アーキテクトがステージ 2 を完了した後に、既存の
workspace/kb/*.mdファイルをチャンク化します。ビルダーが希望する場合は、シンセシス中(ステップ 3)にアーキテクトへworkspace/kb/chunks.jsonlも書き出すよう指示できます(テキストのみの副作用として)——ただし、ハーネスが事後にチャンクを抽出できるため、これは任意です。 -
mantis-plan: 検索メカニズムが利用可能な場合、プランナーに対して、
workspace/kb/index.mdを手動でスキャンするだけでなく、それを使用して各調査のkb_referencesを発見するよう指示します。各調査について、調査タイトルと対象ファイル名でクエリを実行し、一致する上位 K 件の KB エンティティ/脆弱性ファイルをkb_references配列に追加します。メカニズムが利用できない場合、index.mdの手動スキャンがフォールバックとして残ります。 -
mantis-researcher: 検索メカニズムが利用可能な場合、Wave 1 サブエージェントに対して、関連する呼び出しサイトやシンクへのクロスモジュールなデータフローを優先順位付けするためにそれを使用するよう指示します(例: 「パーサーモジュール内で信頼できない入力はどこで
memcpyに到達するか」)。セマンティック検索は、ランキングのヒントとしてのみ grep を補完します——それは順序を決定するものであり、監査セットのメンバーシップを決定するものでは決してありません。これは、ステップ 3 の網羅的な呼び出しサイトのスイープを決して置き換えてはなりません。完全な grep が到達するすべての呼び出しサイトやデータフローは、上位 K 件にランクインするかどうかに関わらず、依然として監査される必要があります。grep の結果とセマンティック検索の結果の和集合を監査してください。リサーチャーの既存の Wave 1/Wave 2 構造は変更されません。
E. スナップショットの安全性
検索インデックスは——スキルによって提供されるものであれハーネスによって提供されるものであれ——固定されたスナップショットのキャッシュであり、ライブビューでは決してありません:
- コードチャンクは、ライブツリーではなく
CODE_ROOT(固定されたスナップショット)から構築します。 SNAPSHOT_IDが変更された場合(新しいパス、新しい固定)に再構築します。- HALT モード(
snapshot_pinned=false)では、STALEフラグを付けて結果を提供するか、提供を拒否します——他のすべてのステージと同じ保守的なデグラデーションです。 - MODE-OFF では、インデックスを完全にスキップします。
7. 埋め込みベースの重複排除プリフィルタリング
パイプラインが大規模なコードベースに対して多数のパスを実行する場合、重複排除ツール(/mantis-dedupe)は、各現在の検出事項をすべてのアーカイブ済み検出事項と比較する必要があります——これは、LLM がサマリーを読んで実行する O(n×m) の比較です。大規模な場合(多数のパスにわたる数百の検出事項)、これはトークンを大量に消費し、低速になります。
ハーネスは、埋め込みを高速なプリフィルターとして使用し、/mantis-dedupe を呼び出す前に候補空間を削減できます。スキルの既存の決定論的マッチング(code_paths + title + discovery_commit)は、ハードな重複排除の決定における唯一の権威であり続けます。
これは完全にハーネス側であり、オプトインです。 /mantis-dedupe は変更されません。
A. 仕組み
-
Harness Action:
workspace/findings/*.json(現在のもの)とworkspace/archive/findings_pass_*/*.json(アーカイブ済みのもの)をすべて読み込みます。各検出事項について、 正規化したテキスト表現(例:title + description + first code_paths entry with line stripped)から 埋め込みを計算します。 -
Harness Action: 現在の検出事項とアーカイブ済みの検出事項の間で、ペアワイズのコサイン類似度を計算します。設定可能なしきい値(例:0.85)を超える候補ペアを提示します。
-
Harness Action: UUID のペアと類似度スコアを含む候補ペアのマニフェスト(例:
workspace/helpers/dedup_candidates.json)を書き込みます。 -
mantis-dedupe の呼び出し: ハーネスは通常どおり
/mantis-dedupeを呼び出します。 候補マニフェストが存在する場合、スキルにその読み込みを指示し、 すべての検出事項をアーカイブ済みのすべての検出事項と比較する代わりに、LLM によるペアワイズ比較で該当ペアを優先させます。既存の決定論的なマッチングルールはすべて変更なく適用されます。マニフェストは検索範囲を絞るだけです。
B. 安全策
-
事前フィルターのみ。判定には使用しません。 埋め込みの類似度スコアが
DUPLICATEの判定、ゴミ箱への移動、possible_duplicate_ofの割り当てにつながることはありません。これらの処理を行えるのは、スキルに既存のcode_paths、title、discovery_commitのチェックのみです。事前フィルターで見落とした場合は、重複が余分に残るだけです(安全です。LLM が確認してスキップします)。重複が過少に残ること(実際の重複を見落とすこと)はありません。 -
偽陰性を防止します。 実際の重複を見落とさないように、しきい値は十分低く設定してください(例:0.75)。実際の重複を見落とすより、候補を多く提示するほうが望ましいです。LLM と決定論的なマッチングによって偽陽性を除外できます。
-
失敗時のフォールバック。 埋め込みを計算できない場合、候補マニフェストが存在しない場合、またはエラーが発生した場合、
/mantis-dedupeは既存の O(n×m) 比較にフォールバックします。マニフェストが見つからなくても、スキルが停止したりエラーになったりしてはなりません。 -
スナップショットの認識。 ハーネスは、異なる
discovery_commitの値を持つ検出事項間の埋め込みを計算する際、スナップショットをまたぐ候補であることを明示してください。最終的な MATCHED/NOT_MATCHED の判定は、スキルのブロック B のペアワイズチェックで行います。
C. 共有インフラストラクチャ
ビルダーがガイドライン 6(セマンティック検索)も実装する場合は、検出事項の埋め込みにも同じベクトル埋め込みインフラストラクチャを再利用してください。検出事項の埋め込みは異なるペイロード(KB チャンクではなく検出事項の JSON)ですが、同じ埋め込み機能を両方に利用できます。
D. エンタープライズ向けベクトルアーキテクチャとクラウドでのスケーラビリティ
分散したコードベースとマルチテナントの監査パイプライン全体で数十万件の脆弱性を追跡するエンタープライズ環境では、SQLite のベクトルストレージをマネージドクラウドベクトルエンジンに置き換えられます。
- Cloud Spanner Vector Search:
- 最適な用途: グローバルな ACID 整合性、99.999% の可用性、検出結果の系譜の同期追跡が求められる、ミッションクリティカルなエンタープライズパイプライン。
- アーキテクチャ: 検出結果と
lineage_vectorsをARRAY<FLOAT32>型のベクトル列を使って Spanner に保存します。KNN 検索インデックスとCOSINE_DISTANCEを使用し、並行スキャンの実行中に検出結果をリアルタイムで重複排除します。
- Cloud SQL for PostgreSQL(
pgvector):- 最適な用途: 運用の複雑さを抑えつつ ACID 準拠を必要とする、標準的なエンタープライズ向けリレーショナルバックエンド。
- アーキテクチャ:
vector拡張機能を有効にします。検出結果の埋め込みをvector(768)またはvector(256)型の列に保存し、HNSW(vector_cosine_ops)または IVFFlat インデックスを使用して、1 ミリ秒未満の類似度クエリを実行します。
- AlloyDB for PostgreSQL:
- 最適な用途: 複数の調査を並行実行する、高スループットのマルチエージェント監査ファーム。
- アーキテクチャ: AlloyDB の列指向ベクトルエンジンと ScaNN ベースの近似最近傍インデックスを活用し、標準的な PostgreSQL と比べて最大 10 倍高速なベクトルクエリを実現します。
- BigQuery Vector Search:
- 最適な用途: バッチ分析処理、組織全体の脅威インテリジェンスのクラスタリング、キャンペーンをまたいだ脆弱性の系譜分析。
- アーキテクチャ: 検出結果の埋め込みを BigQuery に取り込み、
COSINE距離を使ってVECTOR_SEARCH(TABLE findings, 'embedding', ...)を実行し、サーバーレスのバッチ重複排除と過去のリグレッション分析を行います。
8. SAST シーディング(外部ツールの取り込み)
Mantis の検出エンジンは、100% LLM によって生成されます(grep スウォーム+推論)。性能の低い LLM は、成熟した SAST ツール(CodeQL、Semgrep-taint)が関数間クエリとして実装している、プログラム全体を対象とした汚染の種類(インジェクション、パストラバーサル、デシリアライゼーション、UAF、書式文字列)を構造的に見逃す可能性があります。SAST シーディングアダプターは、外部ツールの検出結果を PROVISIONALLY_VALID/NEEDS_RESEARCH の候補として取り込みます。候補は、変更されていない後続のゲートを通過して初めて判定が確定します。これは純粋な追加(INV-2 の強化)であり、検証ゲートを弱めることなく検出範囲を広げます。
これは、ガイドライン 6 の RAG パターンに厳密に従います。オプトインで、デフォルトでは無効、来歴を追跡し、スナップショットを考慮し、失敗時にはフォールバックします。
プラットフォームに依存しない IR(SARIF ではありません): アダプターを SARIF(複雑でツール固有の形式)に結び付けるのではなく、最小限の JSONL 中間表現(IR)を使用します。任意の SAST ツールの出力(SARIF、Semgrep JSON、Bandit JSON など)は、薄いラッパーによってこの IR に変換されます。これによりプラットフォームへの非依存性が最大限に高まり、シンプルな JSONL 形式を出力できるあらゆるツールでアダプターを利用できます。
同じデータコントラクトを共有する、次の 2 つの実装に対応しています。
- オプション A(デフォルト — スキルベース): 専用スキル(
/mantis-sast-seed)が IR を読み取り、LLM の推論を使って検出結果を Mantis の検出結果 JSON に正規化します。LLM は、報告された各位置の実際のソースコードを CODE_ROOT の下で読み取り、検出結果を検証するとともに、根本原因の分析を加えて説明を補足します。外部依存関係はゼロで、エアギャップ環境でも動作します。 - オプション B(最大限の制御 — ハーネスベース): ハーネスが決定論的なコード(SARIF から検出結果への変換スクリプトなど)を使って SAST の出力を検出結果 JSON に直接正規化し、正規化の手順では LLM を介しません。
/mantis-dedupeを呼び出す前に、ハーネスが検出結果 JSON をworkspace/findings/に書き込みます。
どちらもオプトインです。既存のスキルは変更されません。シードされた検出結果は、研究者による検出結果とともに workspace/findings/ に入り、変更されていない後続のゲート(重複排除 -> レビュー -> 批評 -> 再現 -> パッチ -> キャリブレーション)を通過します。
完全なリファレンス設計図は、references/mantis-sast-seed.md で確認できます。
A. 共有データコントラクト:sast_findings.jsonl
IR は workspace/sast_findings.jsonl にある JSONL ファイルです(STATE-RELATIVE)。chunks.jsonl(ガイドライン 6A)と同じプロベナンスヘッダーのパターンに従います。
1 行目 — プロベナンスヘッダー:
{"_provenance": true, "scan_snapshot_id": "abc123def456", "tool": "codeql", "tool_version": "2.15.0", "scan_timestamp": "2026-07-22T10:00:00Z"}
scan_snapshot_id:スキャンの実行対象となった SNAPSHOT_ID です。これは主要なプロベナンスアンカーであり、現在のパスのSNAPSHOT_IDとバイト単位で比較されます(ブロック B と同じ比較です)。ハーネスがピン留めされた CODE_ROOT に対して SAST ツールを実行した場合、この値にはSNAPSHOT_IDが設定されます。tool:ツール名(例:codeql、semgrep、bandit)です。参考情報です。tool_version:ツールのバージョンです。参考情報です。scan_timestamp:ISO 8601 形式です。参考情報です。
2 行目以降 — 1 行につき 1 件の検出結果:
{"rule_id": "cpp/sql-injection", "rule_name": "SQL injection", "cwe": "CWE-89", "severity": "HIGH", "code_paths": ["src/db/query.c:42"], "message": "User input flows into SQL query without sanitization"}
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
rule_id | 文字列 | はい | ツール固有のルール識別子 |
severity | 文字列 | はい | CRITICAL、HIGH、MEDIUM、LOW(Mantis スケール) |
code_paths | 配列 | はい | "file:line" 形式の文字列の配列(SNAPSHOT-RELATIVE) |
message | 文字列 | はい | SAST 検出結果の元のメッセージ |
rule_name | 文字列 | いいえ | 人が読める形式のルール名 |
cwe | 文字列 | いいえ | CWE 識別子(例:CWE-89) |
IR への変換(ハーネスの責任): ハーネスはアダプターを呼び出す前に、SAST ツールの出力をこの IR に変換します。変換例:
- SARIF:
ruleIdを抽出し、levelを severity にマッピングし(error->HIGH、warning->MEDIUM、note->LOW)、locationsをcode_pathsに抽出し、message.textをコピーします。 - Semgrep JSON:
check_idをrule_idとして抽出し、extra.severityを Mantis severity にマッピングし、path:start.lineをcode_pathsとして抽出し、extra.messageをコピーします。
B. オプション A:スキルベースの取り込み(デフォルト — インフラストラクチャ不要)
専用のスキルが sast_findings.jsonl を読み込み、許可リストを適用し、プロベナンスを検証し、signature/lineage_id/discovery_commit を計算して、検出結果の JSON を書き込みます。LLM は報告された各場所の実際のソースコードを CODE_ROOT 内で読み、検出結果を検証して説明を補足します。
- 呼び出し: ハーネスはステージ 6(調査)の後、ステージ 7(重複排除)の前に、
--snapshot_root/--snapshot_id/--state_rootを指定して/mantis-sast-seedを呼び出します。シードされた検出結果は/mantis-dedupeの実行前にworkspace/findings/に保存されます。 - 接続されるまで無効:
sast_findings.jsonlが存在しない場合、スキルは何も出力せず、呼び出し元に通知します。失敗することはなく、空の結果を返すだけです。 - ハルシネーション対策: LLM は検出結果の JSON を書き込む前に、報告された各場所の実際のコードを必ず読み込む必要があります。SAST の出力にない検出結果を作り出してはなりません。
sast_provenance.line_verifiedフィールドには、検証が成功したかどうかが記録されます。 - スナップショットの安全性: スキルはブロック A を介して state から
active_snapshotを読み込み、スナップショットがピン留めされ、検出結果の場所が CODE_ROOT 内で検証された場合にのみdiscovery_commitを付与します。
C. オプション B:ハーネスベースの取り込み(決定論的な取り込みを行う場合)
最大限の決定性を確保するため、ハーネスは決定論的なコードを使用して SAST の出力を検出結果の JSON に正規化できます。この方法では、正規化の手順で LLM を介しません。
- ハーネスの処理: SAST ツールの出力を読み込み、決定論的に解析して、検出結果の JSON を
workspace/findings/に書き込みます。 - ハーネスの処理: スキャンがピン留めされた CODE_ROOT に対して実行されたことを証明できる場合にのみ、
discovery_commitを付与します。 - ハーネスの処理: 許可リストのフィルターを適用します。
- mantis-dedupe の呼び出し: 通常どおり続行します。シードされた検出結果は、調査担当者による検出結果と区別できません。
D. 来歴の検証
アダプターは、スキャンが行単位で同一の固定された CODE_ROOT に対して実行されたことを証明できる場合にのみ、discovery_commit を設定します。
workspace/.mantis_state.jsonから(ブロック A 経由で)active_snapshotを読み取ります。存在しない場合は MODE-OFF です。手順 5 に進みます。snapshot_pinnedが false の場合は HALT です。手順 6 に進みます。- IR の来歴ヘッダーから
scan_snapshot_idを読み取ります。 - VERIFIED:
scan_snapshot_idが存在し、SNAPSHOT_IDと完全に一致します。discovery_commit = SNAPSHOT_IDを設定します。ステータス =PROVISIONALLY_VALID。 - MODE-OFF:
active_snapshotが存在しません。discovery_commitを省略します。ステータス =PROVISIONALLY_VALID(MODE-OFF ではすべての判定が許可されます)。 - HALT:
snapshot_pinnedが false です。discovery_commitを省略します。ステータス =NEEDS_RESEARCH。 - DRIFT:
scan_snapshot_idは存在しますが、一致しません。discovery_commitを完全に省略します。ステータス =NEEDS_RESEARCH。 - UNVERIFIED:
scan_snapshot_idが存在しません。discovery_commitを省略します。ステータス =NEEDS_RESEARCH。
行の存在確認(VERIFIED または DRIFT で、CODE_ROOT が解決されている場合の追加チェック):各指摘について、code_paths の各エントリを検証します。末尾の :line を取り除き、ファイルが CODE_ROOT 配下に存在すること、行番号がファイルの行数の範囲内であることを確認します。ファイルが存在しない場合、または行番号が範囲外の場合は DRIFT に格下げします(discovery_commit を省略し、ステータス = NEEDS_RESEARCH)。
これは、discovery_commit(schema.json)および signature/lineage_id とまったく同じ「UNTRUSTED-IF-ABSENT」パターンです。
E. 許可リストとノイズ制御
workspace/sast_allowlist.json(任意の設定ファイル、STATE-RELATIVE):
{
"enabled": true,
"severity_filter": ["CRITICAL", "HIGH"],
"cwe_allowlist": {
"enabled": true,
"cwes": ["CWE-89", "CWE-78", "CWE-79", "CWE-22", "CWE-787", "CWE-416", "CWE-502"]
},
"rule_allowlist": {
"enabled": false,
"rules": []
},
"per_rule_cap": 5,
"total_cap": 50
}
設定ファイルが存在しない場合は、デフォルトが適用されます:CRITICAL と HIGH のみ、per_rule_cap=5、total_cap=50。
許可リストによる再試行上限の保護方法: 再現ステージ(/mantis-reproduce)では、指摘ごとに最大 6 回の試行という厳格な上限があります(絶対上限であり、リセットされません)。フィルタリングせずに 1000 件の SAST の指摘を投入すると、再現ステージでは最大 6000 回の試行が必要となり、再試行の予算が枯渇します。許可リストの処理段階(重要度フィルター -> CWE/ルールフィルター -> ルールごとの上限 -> 合計上限)により、上限付きのシグナル性の高い候補のみがパイプラインに入ります。再現処理の前には、レビュー(13 ルールの否定フィルター)と批評(本番環境での実用性)の各ステージでも、さらにフィルタリングされます。
F. スキルごとの拡張ガイダンス
SAST シードスキルが利用可能な場合は、ステージ 6(調査)とステージ 7(重複排除)の間に呼び出すよう、ハーネスに指示します。これらはハーネスから渡す実行時の指示であり、スキルファイル自体は変更されません。
- mantis-meta-agent:
/mantis-researcherの完了後、/mantis-dedupeの前に、--snapshot_root/--snapshot_id/--state_rootを指定して/mantis-sast-seedを呼び出します。 - mantis-dedupe: 変更は不要です。シードされた指摘は、調査担当者の指摘と並んで
workspace/findings/に格納されます。重複排除では、これらも同様に処理されます(署名ベースの照合、ブロック B のペアワイズチェック)。 - mantis-review: 変更は不要です。13 ルールの否定フィルターは、シードされた指摘にも同様に適用されます。
- mantis-report: 変更は不要です。
sast_provenanceフィールドは情報提供用であり、レポートに表示できます。
G. スナップショットの安全性
SAST シードアダプターは、ほかのすべてのコード読み取りスキルと同様に、Block A(ロケーターの解決)に厳密に従います。
--snapshot_root/状態のactive_snapshotから CODE_ROOT を解決します。- センチネルチェック(Block A のステップ 2)を順守します。
- 行の存在確認のため、CODE_ROOT 配下のソースファイルを読み取ります(スナップショット相対)。
- 検出結果は
state_root/workspace/findings/配下に書き込みます(状態相対)。 - 固定されている場合、CODE_ROOT 配下には決して書き込みません。
- MODE-OFF の場合:
discovery_commitなしで処理を続行します。すべての判定が許可されます。 - HALT の場合:
discovery_commitを省略します。シードされた検出結果にはNEEDS_RESEARCHが設定されます。 - PINNED の場合:各検出結果の位置を CODE_ROOT 配下で検証し、検証済みであれば
discovery_commit = SNAPSHOT_IDを設定します。
SAST ツールの出力自体はスナップショットを認識しません。別のツリーに対して生成されている場合があります。アダプターによる来歴の検証がこの差を埋め、固定された CODE_ROOT に照らして各検出結果を再確認してから discovery_commit を設定します。
H. 安全性のガードレール
- 追加のみです。 シードされた検出結果は、
PROVISIONALLY_VALID/NEEDS_RESEARCHの候補です。変更されていない下流のゲート(重複排除(Block B)、レビュー(13 ルールフィルター)、クリティック(実行可能性)、再現(Block F の到達済みシンクの証拠と HALT の上限)、パッチ(Block G の再攻撃)、キャリブレーション(妥当性の上限))を通過する必要があります。ゲートが弱められることはありません。 - 誤った
VERIFIED_SECUREは発生しません。 シードされた検出結果はPROVISIONALLY_VALIDから開始し、パッチと再攻撃の全工程を通過しない限り、VERIFIED_SECUREに到達することはありません。 - 誤った
failed_to_reproduceは発生しません。 再現工程に進んだシード検出結果には、同じ Block F の証拠ゲートと HALT の上限が適用されます。 - 回帰を見落としません。 SAST でシードされた検出結果が、異なる
discovery_commitを持つアーカイブ済み検出結果と一致する場合、Block B は NOT_MATCHED ->possible_duplicate_ofを返し、検出結果はアクティブなままになります。 - データがない場合は安全側に倒します。
sast_findings.jsonlが存在しない場合、検出結果は書き込まれません。検出結果を検証できない場合は、NEEDS_RESEARCHになります。 - 既存のスキルは変更しません。 アダプターは
/mantis-dedupeの実行前に、workspace/findings/へ検出結果を書き込みます。 sast_provenanceは情報提供のみを目的とします。 安全性が重要な不変条件、ゲート、判定には影響しません。Block B のスナップショット照合を制御するフィールドは、検出結果のdiscovery_commitです。
9. 構造化コードインデックス(AST レベルのコンテキスト)
小規模なリポジトリでは、調査担当エージェントは呼び出し箇所を grep で検索でき、プランナーは依存関係を推測できます。しかし、大規模になると、grep ベースの呼び出し箇所の検出は信頼性に欠けます(間接呼び出しを見逃し、コメントや文字列と呼び出しを区別できず、関数境界も認識できません)。構造化コードインデックスは AST レベルのコンテキスト(関数境界、呼び出しグラフ、シンボルテーブル)を提供し、調査時の LLM の推論品質を向上させます。
これは、ガイドライン 6 の RAG パターンに従います。つまり、任意で、出所を追跡でき、スナップショットを認識し、失敗時にはフォールバックします。構造化インデックスは網羅性を示すヒントにすぎず、順序と優先順位を決めますが、監査対象セットの構成は決して決めません。見つからなかった場合でも、ファイル、呼び出し箇所、調査をスキップしたり除外したりしてはなりません。
マニフェストスキーマ、SQLite サービングストア、機能ベースのパーティションごとのバックエンド選択、正規シンボル ID、クエリーインターフェース、ベースラインと差分のオーバーレイ、決定論的な部分カバレッジ、安全ガードレールを含む完全な仕様は、単一の信頼できる情報源にあります。
→ ../mantis-structural-index/SKILL.md
簡易版のリファレンスブループリントは、references/mantis-structural-index.md にあります。
同じクエリー契約を共有する、以下の 2 つの実装をサポートしています。
- オプション A(デフォルト — スキルベース):
mantis-structural-indexスキルが、機能ベースのパーティションごとのバックエンド選択を使用して、ヘルパースクリプト(build_structural_index.pyとquery_structural_index.py。どちらも# MANTIS_HELPER_VERSION = 5)を生成して実行し、grep にフォールバックします。 - オプション B(最大限の機能 — MCP ベース): ハーネスが永続的な構造化インデックスを管理し、同じ SQLite サービングストアを基盤として、
find_callers(symbol)、find_callees(function)、get_function_boundary(file, line)の MCP ツールを提供します。
どちらも任意です。仕様に準拠しないハーネスは、構造化インデックスのステージを単にスキップします。構造化インデックスは、ランキングのヒントとしてのみ grep を補完します。決めるのは順序であり、監査対象セットの構成ではありません。
利用側は、JSONL を直接フィルタリングせず、クエリーインターフェース(query_structural_index.py)を使用しなければなりません。クエリーインターフェースは、上限付きの結果、ページネーション、明示的な名前解決、精度とバックエンドのメタデータ、結果が空の場合のカバレッジ情報を提供します。
D. スキルごとの拡張ガイダンス
構造化インデックスが利用可能な場合は、以下のスキルにその使用を指示してください。これらは利用契約であり、ハーネスが渡す実行時の指示です。構造化インデックスはヒントとしてのみ機能する拡張機能です。これを使用しないスキルは、現在とまったく同じように動作します。
- mantis-architecture: KB の統合時に、事前構築された構造化インデックス(Stage 0.5 で
mantis-structural-indexによって構築)を任意で読み込み、dependencies.jsonと相互参照します。 - mantis-plan: 関数レベルの依存関係のファンアウト(ファイルレベルの
dependencies.jsonよりも高精度)に構造化インデックスを使用します。 - mantis-researcher: Wave 1 のサブエージェントは、呼び出し箇所の検出時に grep を補完するランキングのヒントとして
find_callers()を使用します。決めるのは順序であり、対象の構成ではありません。網羅的な Step-3 の呼び出し箇所スイープを置き換えてはなりません。完全な grep で到達できる呼び出し箇所は、構造化インデックスで上位にランクされるかどうかにかかわらず、すべて監査しなければなりません。grep の結果と構造化インデックスの結果の和集合を監査します。Wave 2 の詳細監査担当エージェントは、get_function_boundary()を使用して包含関数から調査を開始し、関数をまたぐコンテキストが必要に応じて呼び出し元、呼び出し先、ファイルへと範囲を広げます。調査担当エージェントの既存の Wave 1/Wave 2 の構成は変更しません。
E. RAG との統合(ガイドライン 6)
- 構造インデックスのエントリーは、
entity_type: "structural"チャンクとしてchunks.jsonlに追加できます。 - 構造インデックスの関数境界を使用すると、コードチャンクを(単純な行範囲の 切り出しではなく)関数境界に揃えることができます。
- 両方を実装する場合、構造インデックスと RAG インデックスで同じベクトル埋め込み インフラストラクチャを共有できます。
10. 段階的な反復再現と複数会話による再試行戦略
複雑なサービスでは、完全なサンドボックス化サービスに対して一度で再現しようとすると、 探索のエントロピーが高く、設定が不安定で、失敗のデバッグも困難になりがちです。段階的な 戦略によって再現を小刻みなマイルストーンに分け、会話をまたいだ再試行アーキテクチャに よって、推論の行き詰まりやコンテキストの肥大化を防ぎます。
A. オーケストレーションと会話をまたいだ再試行
-
会話内での再試行(ローカルエージェントの軌跡):
- アクティブなサブエージェントの会話では、パラメーターの調整、セットアップのバグの修正、 ペイロードの改善を目的として、コンテキストウィンドウ内でローカルに 2~3 回再試行します。
-
会話をまたいだ再試行(新しいコンテキストと蓄積された成果物):
- トリガー: 会話内での再試行を行ってもティア 3
(
reproduced)に到達できない場合、オーケストレーターは停滞した会話を終了し、 新しいサブエージェントの会話(新しいコンテキストウィンドウ)を開始します。 - コンテキストの提供: オーケストレーターは、
state_root/workspace/archive/.repro_attempts.jsonの構造化された試行データと、workspace/learnings.jsonlの軌跡から得られた知見(例:「試行 1 は認証ヘッダー X が不足していたため失敗。試行 2 ではパーサーがエスケープされていない引用符を削除することが判明」)を 新しいプロンプトに設定します。 - 利点: コンテキストの肥大化や推論の惰性(「幻覚の罠」)を解消し、新しいエージェントが 過去の実証結果を活用して、以前の間違いを繰り返さずに問題を解決できるようにします。
- トリガー: 会話内での再試行を行ってもティア 3
(
-
試行上限の計上と算出:
- オーケストレーターは
state_root/workspace/archive/.repro_attempts.jsonを管理します。 - ティア 3 のみ加算: ティア 3 の完全なサンドボックス化サービスの実行 (またはエンドツーエンドの再現実行)のみ、検出項目ごとの試行回数に加算され、 絶対上限の 6 回にカウントされます。
- 段階的な試行のサブ予算: 内部のティア 1 およびティア 2 の試行実行にはローカルの サブ予算(会話ごとに最大 3 回の試行実行)が設定され、絶対上限の 6 回は消費しません。
- オーケストレーターは
B. ハーネスによって強制されるティア 4(ステージングおよび本番前環境での実行)
ライブインフラストラクチャ上で承認されていないエクスプロイトの実行を防ぐため、ティア 4 (ステージング/本番前の検証)は、プログラムによるオーケストレーターハーネスが厳格に 管理・強制するものであり、LLM の裁量に委ねてはなりません。
- サンドボックス境界:
mantis-reproduceは、ティア 3 (reproduced/failed_to_reproduce)で終了する、隔離されたローカルサンドボックス内 (ティア 1~3)でのみ実行されます。 - 決定論的なゲート: ハーネスはティア 3 の
reproduced判定をインターセプトします。 ライブ環境/ステージング環境での検証(ティア 4)が設定されている場合、ハーネスは 自動的にリモート実行を呼び出してはなりません。以下のいずれかによる プログラム上の Human-in-the-Loop ゲートを適用する必要があります。- 人間のオペレーターに対して、明示的な対話形式での確認を求める、または
- 暗号署名付きの承認トークン/認証コールバックを必須とする。
- フェイルクローズのデフォルト: 人間による承認がない場合、または拒否された場合、ティア 4 は スキップされ、ティア 3 のサンドボックスでの判定が引き続き最終的な判定となります。
C. ローカルのイングレス/ミドルボックスのエッジ注釈(Tier 3 サンドボックス検証後)
デフォルトのエッジフィルターによる誤検知(「localhost:8080 では動作するが、WAF/プロキシでは動作しない」)を排除するため、オーケストレーターはオプションで、ローカルサンドボックス内で稼働するリバースプロキシまたは API ゲートウェイ(例:NGINX、 Envoy、ModSecurity)を経由して、Tier 3 の PoC を実行できます。
- 注釈のみ: ローカルのミドルボックスによってペイロードがブロックされても、Tier 3 の
reproduced判定をfailed_to_reproduceに格下げしてはなりません。 - Critic との統合: ハーネスは、検出結果の
repro_hintsまたは履歴にingress_blocked: true(またはエッジ フィルターの詳細)を記録します。これにより、/mantis-criticがproduction_viabilityを"CONDITIONAL_VIABLE"(デフォルトのエッジプロキシ設定によって緩和)と分類するための実証的な根拠が得られます。