mantis-researcher について
mantis-researcher は、計画に沿ってソースコードのメモリ安全性、ロジック、堅牢性を調べるセキュリティ監査スキルです。環境が対応していれば、サブエージェントによる並列の一次選別と詳細監査を行い、構造インデックスは網羅的な検索の補助として使います。
主な機能
- 01計画に沿ったソースコード監査
- 02メモリ安全性とロジックの確認
- 03一次選別と詳細監査の並列実行
- 04検索ヒントとしての構造インデックス照会
- 05個別の JSON 問題ファイル出力
活用シーン
- 01対象ファイルの境界リスクやチェック漏れの調査
- 02API 呼び出し箇所を追跡してサイズ要件を確認
- 03一次選別後に優先度の高いコード箇所を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-researcherインストール後、Claude Code で/mantis-researcherを入力して読み込まれたか確認します。
詳細
Mantis Researcher (/mantis-researcher)
システムの目標
レジリエンスコード監査ツールです。ソースファイルを迅速にトリアージし、詳細にレビューして、境界チェック、事前条件、サニタイズ漏れ、インターフェース違反を特定します。
コマンド定義
- コマンド:
/mantis-researcher - 説明:
workspace/plan.jsonの戦略に基づいて、本番環境のソースコードファイルを監査します。 - 引数(省略可。オーケストレーターから渡され、Block A で使用):
--snapshot_root/SNAPSHOT_ROOT:このパスで使用する、ピン留めされた読み取り専用コードスナップショットの絶対パスです。すべてのスナップショット相対パスフィールドが解決される CODE_ROOT です(Block A step 1b)。--snapshot_id/SNAPSHOT_ID:パスのスナップショット識別子です。センチネルチェック(Block A step 2)に使用され、各検出事項のdiscovery_commitにそのまま記録されます。--state_root:workspace/状態ディレクトリ(plan.json、.mantis_state.json、findings/、kb/)の絶対パスです。状態パスは STATE-RELATIVE であり、CODE_ROOT は決して付加されません(Block A step 3)。--target_root(権威あるオーバーライド、Block A step 1a)も指定されていれば使用されます。- すべてのフラグが指定されていない場合 -> DEGRADED/レガシーモード: CODE_ROOT は現在のディレクトリにフォールバックし、
snapshot_pinnedは false として扱われ、動作は現在とまったく同じになります(discovery_commitは書き込まれません)。
入出力契約
- 読み取り対象:
workspace/plan.json(存在しない、または空の場合はコードベース全体をスイープします)。workspace/.mantis_state.json(現在のループパスを追跡するため)。"kb_references"で参照されている Markdown ファイル(例:workspace/kb/entities/*.md)。- 対象のソースコードファイル。
workspace/kb/structural_index/manifest.json(構造インデックスの可用性/状態を確認するため)。workspace/helpers/query_structural_index.py(範囲を限定した構造インデックスクエリを実行するため)。
- 書き込み対象:
- 生の検出事項ファイルを
workspace/findings/<uuid>.jsonに書き込みます(存在しない場合はworkspace/findings/を作成します)。
- 生の検出事項ファイルを
- 前提条件:
- 対象ファイルにアクセスできる必要があります。
- 冪等性の保証:
- 一意の UUID を使用して、新しい検出事項を別々のファイルとして書き込みます。後続のステップで重複する検出事項をグループ化して統合するため、
mantis-dedupeを利用してください。
- 一意の UUID を使用して、新しい検出事項を別々のファイルとして書き込みます。後続のステップで重複する検出事項をグループ化して統合するため、
手順
Step 0:ロケーターの解決(スナップショット対応のパス処理)
以下の番号付き調査ステップより先に、これを実行してください。この段階におけるすべての target_files/code_paths 参照が解決される単一の CODE_ROOT を確定し、すべてのサブエージェントが同じピン留めされたスナップショットを監査できるようにします。
LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
(used when a caller hands you a prepared tree, e.g. a patched shadow).
b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
c. Else read state_root/workspace/.mantis_state.json (state_root from
--state_root if passed, else ./workspace/... relative to the current dir)
-> active_snapshot.root / .snapshot_id / .snapshot_pinned.
d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
- SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
NOT of the form <existing-path>:<integer> is a non-source LOCATOR
(symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
line-range and line-existence logic.
- STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
kb_references, repro_file_path, reattack_file_path, helper scripts, report
files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
(mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
(the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
that call. Do NOT assume the working directory persists between calls.
調査担当者向けのスキル固有の注意事項:
- 調査担当者はコードを読み取る段階なので、Block A step 0 の「検出事項のみ」のスキップは適用されません。CODE_ROOT を必ず解決し、センチネルを尊重してください。
workspace/plan.jsonのtarget_filesと検出事項のcode_pathsは SNAPSHOT-RELATIVE です。CODE_ROOT 配下で解決してください(Block A step 3)。kb_references、workspace/plan.json、workspace/.mantis_state.json、およびworkspace/findings/配下のすべての項目は STATE-RELATIVE です。--state_root 配下で読み書きし、CODE_ROOT 配下では決して読み書きしないでください。- ピン留めされている場合は、CODE_ROOT 配下で書き込み、コンパイル、生成を決して行わないでください(Block A step 4)。
対象のコードベースについて、メモリ安全性、論理的正確性、堅牢性を徹底的にレビューしてください。
次のように調査段階を実行してください:
-
レビュー計画とコンテキストの読み込み:
workspace/.mantis_state.jsonから現在のパス番号を読み取り、現在の ISO 8601 タイムスタンプを解決します。workspace/plan.jsonファイルを読み取り、対象となる調査を取得します。workspace/plan.jsonが存在しないか空の場合は、 ディレクトリを全般的に一覧表示し、主要なソースファイルを確認します。調査に"kb_references"配列が含まれる場合は、 監査を開始する前に、これらの Markdown ファイル(例:workspace/kb/entities/auth.md)を明示的に読み込み、 蓄積された過去のコンテキストを把握します。また、workspace/.mantis_state.jsonからactive_snapshot(root、snapshot_id、snapshot_pinned)も読み取ります。active_snapshot.snapshot_idをメモリに保持してください。 これは、各指摘のdiscovery_commitに記録する値です(Findings Schema Format を参照)。active_snapshotが存在しない場合、 またはsnapshot_pinnedが false の場合は、DEGRADED/レガシーモードです。停止してはいけません(Block A の手順 1d)。discovery_commitを省略してください。 -
サブエージェントへの委任(ウェーブ方式の群並列化): CLI またはエージェントプラットフォームがサブエージェントの起動に対応している場合 (専用のサブエージェントツールやマルチエージェントオーケストレーターのディレクティブを使用する場合など):
-
サブエージェントに対応している場合、調査を逐次実行してはいけません。
workspace/plan.jsonの調査を並列ウェーブに分割し、スループットとコンテキスト効率を最大化します。 -
ウェーブ 1:軽量な迅速トリアージ(最大並列実行): 軽量なサブエージェントを同時に起動し (例:最大 10~20 個)、
workspace/plan.jsonに記載されたすべてのファイルを確認します。各サブエージェントは、 迅速な分類のみを出力します:{"potentially_flawed": true/false, "reason": "..."}。 -
ウェーブ 2:セキュリティ上の欠陥が疑われる箇所の詳細監査と並列攻撃経路探索: ウェーブ 1 でフラグが付いたファイルをすべて収集します。これらの特定された箇所だけに集中する、 詳細監査用のサブエージェントを同時に起動します(例:最大 4~8 個)。特に複雑なファイルについては、 異なるプロンプト制約を指定するか、比較的低コストな多様な LLM を使い、同じファイルを対象とする複数のサブエージェントを 起動して、並行して攻撃経路を調査します。後続の重複排除段階で、重複する指摘を統合します。
-
トークンの最適化(分散書き込み): ウェーブ 2 のサブエージェントに一意の UUID を生成させ、 指摘を
workspace/findings/<id>.jsonという個別のファイルに直接書き込ませます。コンテキストウィンドウを 圧迫するため、JSON ペイロード全体をメッセージで返すよう求めてはいけません。作成した UUID の一覧だけを返すよう求めます。 -
スナップショットの分離(ウェーブの固定)— 必須: すべてのウェーブ 1 およびウェーブ 2 のサブエージェントに、 同じ
--snapshot_root(ステップ 0 で解決した CODE_ROOT)と同じ--snapshot_idの値を渡し、 Block A に従うよう指示します(その CODE_ROOT 配下でtarget_files/code_pathsを解決し、センチネルを尊重する)。 指摘を書き込むウェーブ 2 のサブエージェントは、Findings Schema Format の指定どおり、discovery_commitにそのsnapshot_idを必ず記録しなければなりません。サブエージェントはgit pull/fetch/checkout/reset、hg pull/update、repo sync、その他作業ツリーを変更したり リビジョンを切り替えたりするコマンドを実行してはいけません。パス全体を通してスナップショットは不変です。 スナップショットを確認できないサブエージェントは、再同期せず、その旨を報告しなければなりません。 -
現在の環境がサブエージェントまたは並列実行に対応していない場合は、確認と詳細調査を逐次実行します。
-
構造インデックス(HINT のみの拡張): 構造インデックスが利用可能な場合(
workspace/kb/structural_index/manifest.jsonが存在する場合)は、上記のウェーブベースのスウォームを補完するために使用してください。構造インデックスが決めるのは順序であり、対象の網羅性ではありません。Step-3 のコールサイト網羅調査に取って代わることは絶対にできません。-
解決優先プロトコル(構造インデックスへのクエリの前に必ず実施):
- まずシンボルを解決します。
python3 workspace/helpers/query_structural_index.py resolve_symbol --name "<function_name>" [--language "<lang>"] [--file "<path>"] --state_root <state_root> - 応答に
ambiguous: trueが含まれている場合は、一致したシンボルをすべて調査します。暗黙のうちに 1 つを選んではいけません。可能であれば--file/--languageで絞り込むか、一致したシンボルごとに調査を予定してください。 - 解決された
symbol_idを使って、範囲を限定したクエリを実行します。python3 workspace/helpers/query_structural_index.py find_callers --symbol_id "<id>" --limit 100 --offset 0 --state_root <state_root>
- まずシンボルを解決します。
-
カバレッジを踏まえた解釈: 構造インデックスの応答ごとに
coverage.partition_statusを確認します。complete+precision == semantic+ 結果が空の場合は、「インデックス上の呼び出し元なし」です(インデックス対象コードについては信頼できますが、HINT のみのルールに従って grep も実行してください)。complete+precision != semantic+ 結果が空の場合は、「インデックス上の呼び出し元なし」ですが、信頼できる結果ではありません。網羅的な grep を必ず実行してください。partial/empty/failed+ 結果が空の場合は、「インデックスが不完全」です。網羅的な grep を必ず実行してください。- 各結果の
precisionフィールドとbackendフィールドを使って信頼度を判断してください(semantic>typecheck>ast>symbol-only>heuristic>deferred>coverage-only)。
-
ウェーブ 1(迅速なトリアージ):
find_callers()を使って grep を補完し、優先順位付けの HINT として使用してください。順序付けにのみ使い、対象の網羅性には使いません。構造インデックスの結果を使って、potentially_flawedとしてフラグを立てるファイルの優先順位を決めます。これによって Step-3 のコールサイト網羅調査に取って代わることは絶対にできません。grep の結果と構造インデックスの結果の和集合を監査してください。 -
ウェーブ 2(詳細監査):
get_function_boundary(file, line)を使って、まず対象を含む関数から調査を開始し、必要に応じて呼び出し元/呼び出し先/ファイルへと範囲を広げ、詳細な調査に必要なコンテキストを得てください。 -
適切なフォールバック: 構造インデックスが存在しない場合(
manifest.jsonがない場合)、空の場合、またはクエリヘルパーがない場合は、grep ベースの検出にフォールバックしてください(現行の動作)。構造インデックスはカバレッジに関する HINT にすぎません。
-
-
-
インターフェースとコールサイトの網羅的なレビュー: 対象のソースファイルで、サイズ制約や安全要件(例:呼び出し元が特定のサイズのバッファーを確保することを求める要件)が明示された公開関数または API 関数(数値パーサー、デコーダー、エンコーダー、コンバーターなど)を定義している場合:
- 関数名でリポジトリ全体を grep し、候補となるコールサイトを網羅的に洗い出してください。これが必須の最低限です。その後、構造インデックスのクエリヘルパー(
resolve_symbolの後にfind_callers)を使って、監査するコールサイトの優先順位を付けてください(インデックスは実際の呼び出しと、コメント/文字列/変数名とを区別します)。両方の結果セットの和集合を監査してください。構造インデックスはマクロベースの呼び出し、関数ポインター、動的ディスパッチを見落とす可能性があるため、grep が最低限の要件となります。 - コードベース全体を検索して、リポジトリ全体にわたるこれらの関数のコールサイトをすべて見つけてレビューし、安全性に関する契約がグローバルに遵守されていることを確認してください。
- 呼び出し元のファイルを読み、すべてのコールサイトが入力制約を厳密に遵守し、境界を適切に管理し、サイズを確認しているか検証してください。
- 不整合があれば、契約の整合性に関するバグまたはチェックの欠落としてフラグを立ててください。
- 関数名でリポジトリ全体を grep し、候補となるコールサイトを網羅的に洗い出してください。これが必須の最低限です。その後、構造インデックスのクエリヘルパー(
-
制約のない調査/探索的な調査: 調査計画
workspace/plan.jsonに、制約のない網羅的な調査、敵対的監査、またはランダムな探索を明示的に求める指示や質問が含まれている場合:workspace/kb/THREAT_MODEL.mdに記載されている既存の安全性に関する前提や信頼境界を無視してください。- すべての入力と境界を、信頼できず、不正な形式である可能性があるものとして扱ってください。
- 実装をゼロから分析し、完全な自由と自律性をもって調査してください。
- 指示が最小限のランダムな探索/掘り下げタスクの場合は、特定の脅威モデルに制約されず、対象ファイルの動作を把握し、主要なエントリーポイントを特定し、予期しない副作用や境界ケースを探すことに注力してください。
-
調査結果をまとめて書き出す: 単一の巨大なファイルではなく、存在しない場合は
workspace/findings/ディレクトリを作成してください。潜在的な調査結果ごとに一意の UUID を生成し、個別のファイルworkspace/findings/<id>.jsonに有効な JSON オブジェクトを書き込んでください。こうすることで調査結果を分離し、後続の分析でトークン制限に達するのを防げます。ファイル内には、JSON の前後にテキストを含めないでください。シグネチャと系譜の計算(ステップ 5a):
各調査結果について、JSON ファイルを書き込む前に
signature、lineage_id、および任意でcweを計算してください。-
cwe(任意): 脆弱性が既知の CWE に該当する場合は、cweフィールドに識別子(例:"CWE-787"、"CWE-416")を設定してください。該当する CWE がない場合は、このフィールドを省略してください。これはシグネチャの入力値です。 -
signatureの計算(決定論的なコンテンツ識別ハッシュ):normalized_title= 調査結果のtitleを小文字に変換し、英数字以外の文字をすべて削除したもの(ASCII[a-zA-Z0-9]のみ。Unicode 文字、句読点、空白など、それ以外の文字はすべて削除)。削除後のnormalized_titleが空になる場合(例:ASCII 以外/Unicode 文字のみで構成されるタイトル)、異なる非 ASCII タイトルが空文字列で衝突しないように、normalized_titleにsha256(<original raw title as UTF-8 bytes>)の先頭 16 桁の 16 進数を設定してください。cwe_part= 調査結果のcweフィールドが存在し、かつ null でない場合はその値、それ以外の場合は空文字列。primary_target=code_pathsの最初のエントリーから末尾の:lineを取り除いたもの(例:src/auth.c:145→src/auth.c)。code_pathsが空の場合、または最初のエントリーがソース以外の LOCATOR(://を含む URL、またはブロック A のステップ 3 で定義されるファイル以外のシンボル/オフセット)の場合は、空文字列を使用してください。primary_target、ひいてはsignatureがパス間で変動しないように、code_pathsの順序を決定論的にしてください(主要なシンクを先頭にし、パス間で安定させてください)。順序が不安定な場合の唯一の代償は、系譜の継承が見逃されることです。その場合、調査結果は新規として過剰に報告され、隠されることはありません。ただし、安定した順序により、パス間の統合を維持できます。primary_targetが空でない場合:signature=sha256(normalized_title + "|" + cwe_part + "|" + primary_target)の先頭 16 桁の 16 進数。primary_targetが空の場合:signature=sha256(normalized_title + "|" + cwe_part + "|" + sorted(code_paths).join(","))の先頭 16 桁の 16 進数。- 調査結果の作成時にシグネチャを一度だけ計算し、再計算、編集、または捏造は決してしないでください(
discovery_commitと同じルールです)。
-
lineage_idの計算(パス間の系譜チェーン):workspace/archive/findings_pass_*/とworkspace/archive/loop*_findings/をスキャンし、signatureフィールドが この検出結果の計算済みsignatureと等しいアーカイブ済み検出結果 JSON を 探します。- 一致が見つかった場合:
lineage_id= アーカイブ済みの祖先のlineage_id(系列チェーンを継承し、コンシューマーがパスをまたいで折りたたむことが できるようにします)。MULTIPLE のアーカイブ済み検出結果が同じ signature を 共有している場合は、MOST RECENT(最も高いパス番号)の祖先から継承します。 同じ signature を持つすべての祖先は同じ lineage_id を共有 SHOULD します。 もし共有していない場合は、最も新しいものから継承し、警告をログに記録します。 - 完全一致する signature で一致しない場合: TRUE なリネーム ONLY に対して
ベースネームリネームフォールバックを試みます。signature を再計算しない
でください(これは作成時に ONCE 計算され、決して再計算されません — 不変条件 #4)。
代わりに:
- CURRENT な検出結果のベースネームを計算します:
primary_target(末尾の:lineを除去した最初のcode_pathsエントリで、ステップ 2 で signature 用にすでに計算済み)を取得し、そのベースネームを取得します (例:src/auth.c→auth.c)。primary_targetが空の場合(非ソースの LOCATOR または空の code_paths)、このフォールバックを SKIP します — 以下の 新しい UUIDv4 に進みます。 - ステップ 3 のアーカイブスキャンで見つかった各アーカイブ済み検出結果に
ついて: ARCHIVED な検出結果のベースネームを、格納されている
code_paths[0]から再構築します(末尾の:lineを除去し、ベースネームを 取得します — 例:lib/old_auth.c:88→old_auth.c)。アーカイブ済み 検出結果の signature を再計算しないでください。また signature を比較しない でください。2 つのベースネームを STRINGS として比較します。 - このフォールバックを介して祖先の
lineage_idを継承するのは、ONLY IF (i) ベースネームが一致し AND (ii) 祖先の完全なprimary_target(:lineを除去したそのcode_paths[0])が現在のスナップショット上に NO LONGER EXISTS である場合のみです(古い完全パスが CODE_ROOT 配下に 存在しないことを確認します — これは本当のリネームと、単にベースネームを 共有するだけの 2 番目の独立したファイルとを区別します)。(i) と (ii) を 満たす MULTIPLE のアーカイブ済み祖先が存在する場合は、MOST RECENT (最も高いパス番号)から継承します。ベースネームを介して継承する場合は、 検出結果の履歴ノートlineage-via-basename-renameも ALSO 追加し、 ダウンストリームのコンシューマーがそのリンクをベースネーム由来として 扱うようにします(レポートは、SAME-BUG 述語に従って完全なsignatureも ALSO 一致する場合にのみ 2 つの検出結果を折りたたむため、 ベースネーム由来の系列リンクが別個のバグを統合することは決してありません)。 - 古い完全パスが現在のスナップショット上にまだ存在する場合は、継承しないで ください — 一致なしとして扱います(以下の新しい UUIDv4)。
- CURRENT な検出結果のベースネームを計算します:
- 完全一致する signature またはベースネームリネームのいずれでも一致しない場合:
lineage_id= 新しい UUIDv4。 - これらは STATE-RELATIVE なパス(ブロック A ステップ 3)です —
--state_root/workspace/archive/配下で読み取り、CODE_ROOT 配下では NEVER 読み取らないでください。
-
3 つのフィールドすべて(
cwe、signature、lineage_id)をdiscovery_commitと並べて検出結果 JSON に書き込みます。 モード非依存性:discovery_commit(DEGRADED/レガシーモードでは省略される)とは異なり、signatureとlineage_idは常に計算されます。これらはコンテンツ同一性フィールドであり、スナップショット同一性フィールドではありません。スナップショットが固定されているか、固定されていないか、あるいは存在しないか(MODE-OFF)に関係なく機能します。これは意図的な Phase-3 の改善です。MODE-OFF では、検出結果の JSON に Phase 1 には存在しなかった 2~3 個の追加のオプションキー(cwe、signature、lineage_id)が含まれるようになりました。これはスナップショットモデルを変更するものではありません(active_snapshotなし、同期なし、固定なし — 3 状態ルールは影響を受けません)。重複排除の MODE-OFF フォールバックは、signatureが存在する場合にstable_keyよりもsignatureを優先するようになりました。これは厳密に、より識別力が高い(signature は title+path の組み合わせにcweを追加する)ため、stable_keyならマージしていたであろうエントリを分割することしかできず(新しいバジェット、より保守的 = 安全)、偽のマージを生成したり、正当な検出結果を抑制したりすることは決してありません。signatureが存在しない場合 → 現在のstable_keyの動作とまったく同じです。
対象ファイルが見つからない、または読み取れない場合:
target_files内のパスが存在しない、または CODE_ROOT 配下で読み取れない場合(例えば、計画が作成されてから削除または名前変更された場合)、検出結果、行番号、またはファイル内容を捏造しないでください。その対象をスキップし、関連する検出結果のdescriptionにスキップを明確に記録してください(または完全に省略してください)。読んでいないコードを決してでっち上げないでください。非ソース対象: 非ソースの LOCATOR(バイナリ、ファームウェア、または URL エンドポイント — ブロック A のステップ 3 を参照)の場合、
code_pathsエントリは:lineサフィックスなしの STABLE LOCATOR(シンボル名、オフセット、またはベアパス)でなければなりません。テキストとして開けない対象に捏造した行番号を付与しないでください。 -
検出結果スキーマ形式(ファイルごと)
{
"id": "A unique identifier generated for this finding (e.g., a UUID or random hash). This must be included and match the filename.",
"title": "Authorization bypass or Memory bounds violation in [function_name]",
"description": "Thorough root cause analysis detailing why the function is flawed under untrusted input.",
"impact": "Exploit outcome (e.g., Privilege escalation, Memory corruption, Data exfiltration).",
"severity": "CRITICAL / HIGH / MEDIUM / LOW",
"privileges_required": "NONE / LOW / HIGH",
"attacker_position": "EXTERNAL / INTERNAL_NETWORK / IN_CLUSTER / LOCAL / HOST_SYSTEM / SUPPLY_CHAIN / PHYSICAL_TEMPORARY / PHYSICAL_LONG_TERM",
"user_interaction": "NONE / REQUIRED",
"status": "PROVISIONALLY_VALID",
"code_paths": ["SNAPSHOT-RELATIVE path under CODE_ROOT, e.g. 'relative/file/path.c:145'. For a NON-SOURCE target (binary/firmware/URL, per Block A step 3) use a STABLE LOCATOR (symbol name, offset, or bare path) WITHOUT a fabricated ':line'. Never invent a line number."],
"discovery_commit": "The active_snapshot.snapshot_id read from workspace/.mantis_state.json at the start of this pass (Step 1). REQUIRED and NON-EMPTY whenever the snapshot is pinned: copy it VERBATIM, set it exactly ONCE at finding creation, and never recompute, edit, or invent it. OMIT this key entirely (do not write \"\" or null) if active_snapshot is absent or snapshot_pinned is false (DEGRADED/legacy mode).",
"cwe": "CWE-787 (optional; omit if no CWE applies)",
"signature": "First 16 hex chars of sha256(normalized_title + '|' + cwe_part + '|' + primary_target). Computed once at creation, never recomputed.",
"lineage_id": "UUIDv4, or inherited from an archived finding with the same signature. Computed once at creation.",
"mitigation": "Recommended corrective modification.",
"history": [
{
"stage": "researcher",
"action": "created",
"details": "Initial audit finding recorded.",
"pass_number": <current_pass_number>,
"timestamp": "<current_iso8601_timestamp>"
}
]
}
discovery_commit ルール(作成時に一度だけ設定): このステージは discovery_commit の作成サイトです。スナップショットが固定されている場合、あなた(またはあなたの Wave-2 サブエージェント)が書き込むすべての検出結果は、active_snapshot.snapshot_id と等しい空でない discovery_commit を持たなければなりません。下流のステージは、discovery_commit が存在しない場合を NOT_MATCHED(保守的な分岐)として扱うため、空文字列や誤った値を書き込むと、マッチングがサイレントに破損します。決して行わないでください。DEGRADED/レガシーモード(active_snapshot がない、または snapshot_pinned が false)では、現在のパイプラインと同じ動作になるようにキーを省略してください。
signature/lineage_id ルール(作成時に一度だけ設定): これらのフィールドは常に計算されます(degraded モードで省略される discovery_commit とは異なります)。signature は検出結果のコンテンツ同一性の決定論的ハッシュであり、lineage_id は検出結果をそのアーカイブされた祖先に連鎖させます。下流のコンシューマー(dedupe、chain、report、reproduce)は、UUID フォールバック付きで signature/lineage をキーとします。signature が存在しない場合 → 現在の UUID の動作とまったく同じです(サイレントな誤った結果はありません)。
すべての個別の検出結果ファイルが workspace/findings/ ディレクトリに書き込まれるようにしてください。完了したら、ユーザーに通知してください。