mantis-critic について
mantis-critic は、報告済みの問題が最適化された本番ビルドでも成立するかを独立して検証するセキュリティレビュー用スキルです。スナップショットとソースコードを確認し、コードの差分や欠落だけを根拠に問題を非該当と判定しない仕組みです。
主な機能
- 01本番ビルドでの成立性確認
- 02ソースコード経路の独立検証
- 03スナップショット差分と行範囲の確認
- 04脅威モデルのデプロイ意図の確認
- 05問題と学習記録の冪等更新
活用シーン
- 01デバッグ用またはテスト用経路だけの問題の除外
- 02固定スナップショットに基づく問題の再評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-criticインストール後、Claude Code で/mantis-criticを入力して読み込まれたか確認します。
詳細
Critic (/mantis-critic)
システム目標
本番環境での実行可能性を評価するエキスパートです。検証済みのセキュリティ上の指摘を精査し、標準的なリリース構成および本番構成でも引き続きトリガー可能かを確認します。
コマンド定義
- コマンド:
/mantis-critic [--target_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<id>] [--state_root=<path>] - 説明: 指摘が本番環境で実行可能かを評価し、デバッグ専用機能やアサーションによるトラップを除外します。
- パラメーター:
--target_root:対象コードベースのルートへの権威あるパスです。他のすべてのパス特定元より優先され、センチネルチェックの対象外です(Block A path 1a)。デフォルトでは未設定です。--snapshot_root:このパスで使用する、固定された不変のスナップショットコピーへのパスです(別名SNAPSHOT_ROOT)。--target_rootが未設定の場合、CODE_ROOT として使用されます(Block A path 1b)。--snapshot_id:このパスについてオーケストレーターが計算したSNAPSHOT_IDです。Block A のセンチネルチェックと、Step 3 の指摘ごとの Block B ドリフト比較に使用されます。省略した場合は、state のactive_snapshot.snapshot_idを使用します。--state_root:workspace/を含む Mantis state ディレクトリのルートへのパスです(デフォルトは.)。このファイル内のworkspace/...というパスはすべて--state_rootを基準に解決されます。デフォルトの.では、現在のworkspace/と同じ場所になります。
入出力の契約
- 読み込み対象:
workspace/findings/(ステータスにかかわらずすべての指摘を読み込みます。また、指摘ごとのスナップショット一致チェックのため、各指摘に任意で設定されたdiscovery_commitも読み込みます)。workspace/kb/THREAT_MODEL.md(存在する場合は、デプロイの意図と KB に記録されたkb_snapshot_idを確認するために読み込みます)。workspace/.mantis_state.json(現在のループパスを追跡し、パス解決と来歴確認のためにactive_snapshot.{root,snapshot_id,snapshot_pinned}を読み込みます)。- 解決済みの CODE_ROOT 配下にある対象ソースコードファイル(
snapshot_pinnedの場合は固定されたスナップショットルート)。code_paths内のパス/行と、前後のコンテキストを読み込みます。
- 書き込み対象:
- 指摘をその場で更新します(
"production_viability"と"critic_reasoning"を設定し、履歴を追加します)。 workspace/learnings.jsonlに追記します。
- 指摘をその場で更新します(
- 前提条件:
workspace/findings/に指摘が存在する必要があります。
- 冪等性の保証:
- 実行可能性フィールドをその場で上書きします。現在のパスに対する Critic のエントリーが履歴配列にすでに記録されているかを確認し、同じ入力で再実行した際に重複レコードを書き込まないよう、
workspace/learnings.jsonlも確認する必要があります。
- 実行可能性フィールドをその場で上書きします。現在のパスに対する Critic のエントリーが履歴配列にすでに記録されているかを確認し、同じ入力で再実行した際に重複レコードを書き込まないよう、
指示
検証済みの指摘を評価し、コンパイル済みの最適化リリースビルドにおいて、対処可能なセキュリティ上の欠陥に該当するかどうかを判断してください。極めて懐疑的かつ敵対的な姿勢を取ってください。前段階の推論を信頼してはいけません。本番環境での実行可能性を決定的に証明または否定するため、コードパスを独自に再検証してください。
パスの解決(最初に実行)
Critic は対象ソースを調査するコード読解ステージであるため、指摘のみを扱うステージではありません。Block A をすべて実行してください。指摘を読み込む前に、Block A に従って 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.
メモ
現在のパスの確認(防御的措置。拘束力のある保証は、
mantis-pipeline-adapterScenario 2 に基づきハーネスが担います):active_snapshotが存在し、かつactive_snapshot.pass != state.pass_numberの場合、そのスナップショットはこのパスに対して古いものとして扱います。"stale active_snapshot: pass mismatch"で停止するか、HALT として処理を縮退させてください(snapshot_pinnedは実質的に false:権威ある判定はなし、Block B は NOT_MATCHED、再現はnot_attempted)。これにより、Stage 15 のパス番号のインクリメント後に再固定せず、カスタムハーネスがactive_snapshotを保持した場合を検出できます。参照メタエージェントは各パスで再固定するため、このチェックがそこで発動することはありません。Block B 自体ではこの状況を検出できません(passを考慮せず、snapshot_idのみを確認するためです)。 このステージの SNAPSHOT_ID:--snapshot_idが指定されている場合はその値を、指定されていない場合はworkspace/.mantis_state.jsonのactive_snapshot.snapshot_idをSNAPSHOT_IDとします。どちらも存在しない場合(--snapshot_idがなく、状態にactive_snapshotもない場合)、または Block A がパス 1d(引数なし、カレントディレクトリ)経由で CODE_ROOT を解決した場合、SNAPSHOT_ID は UNAVAILABLE です(MODE-OFF = 本日のデフォルト):Step 3 の Block B の各チェックを NOT_MATCHED とし、Step 2 の KB 鮮度ゲートを FAILED として扱います。停止せず、以下の説明に従って縮退動作してください。active_snapshotが存在するもののsnapshot_pinnedが false(HALT モード)の場合、SNAPSHOT_ID は記録されたlive:ID であり、利用可能です。Block B は引き続き NOT_MATCHED を返します(snapshot_pinnedが false のため)が、以下の Step-3c「MODE-OFF 例外」は適用されません。NOT_MATCHED の結果はドリフトとして扱われ、CONDITIONAL_VIABLE になります。calibrate が除外する NON_VIABLE にはなりません。
次の手順で批評評価を実行してください。
-
Finding の読み込み:
workspace/findings/ディレクトリ内の JSON ファイルを読み込みます。処理または長期メモリへの記録ができるよう、ステータス("VALID"、"FALSE_POSITIVE"、"PROVISIONALLY_VALID"、"NEEDS_RESEARCH"を含む)にかかわらず、すべての finding を読み込む必要があります。存在しない場合はユーザーに通知してください。 -
リポジトリ全体の意図の評価(KB 鮮度による制御あり):
workspace/kb/THREAT_MODEL.mdが存在する場合は読み込みます。Deployment Intent セクションを確認してください。KB 鮮度ゲート — 一括マークを行う前に必須(3 状態ルール): KB の構築対象となったスナップショットを特定します。次のいずれかのソースから読み取り、上から順に確認して最初に見つかったものを使用します。
workspace/kb/THREAT_MODEL.mdの1 行目にあるリテラルのKB_SNAPSHOT:トークン(threat-model はこれをヘッダーのみで書き込みます。architecture は KB ファイルごとにコメントで囲んで `` として書き込みます)。architecture ファイルの場合は、コメント内のKB_SNAPSHOT:部分文字列を検索します。kb_snapshot_id:やSnapshot:は検索しないでください。これらのトークンは書き込まれず、ゲートが一致しないためです。- それ以外の場合は、
workspace/.mantis_state.jsonのkb_snapshot_idの値(architecture が状態スタンプのステップで書き込みます)。 - それ以外の場合は
""(KB の出所情報なし)。以下の一括マークは、次の条件に従います。
- MODE-OFF(状態に
active_snapshotがない場合 —--syncなし):鮮度ゲートを完全にスキップします。SAMPLE_OR_TESTの一括マークは、現行どおり許可されます(本日の動作とバイト単位で同一)。KB はライブツリーを対象に構築されており、比較対象となるスナップショットがありません。 - HALT または PINNED(状態に
active_snapshotが存在する場合):記録されたKB_SNAPSHOT:(またはkb_snapshot_id)が存在し、上記の Locator Resolution で解決した現在のSNAPSHOT_IDとバイト単位で完全に一致する場合に限り、一括マークが許可されます(あいまいな比較は禁止)。値がない、空、またはSNAPSHOT_IDと一致しない場合は、一括マークしてはいけません。この一括処理全体をスキップし、Step 3〜5 で各 finding を個別に評価してください。
鮮度ゲートを通過した場合(または MODE-OFF でスキップされた場合)に限り、threat model にリポジトリ全体がチュートリアル、サンプルプロジェクト、またはテストスイートのみであると明記されている場合(例:
Intent: SAMPLE_OR_TEST_ONLY)、ファイル構造上の場所にかかわらず、すべての finding をSAMPLE_OR_TESTとしてマークする必要があります。そのうえで、以降の finding ごとの生存可能性チェックをスキップしてください。 -
対象コードスニペットの取得(スナップショット一致):
statusが"VALID"または"PROVISIONALLY_VALID"の各 finding について、以下を実行します("FALSE_POSITIVE"または"NEEDS_RESEARCH"の finding では、この手順および以降の評価手順をスキップします)。 a. Block Aのステップ3に従って、指摘のcode_pathsから対象ファイルを特定します。code_pathsはスナップショット相対パスなので、CODE_ROOT配下で読み込みます。末尾の:<digits>を取り除いて行番号を取得します。://はURLを意味し、ファイルではありません。<path>:<int>形式ではないエントリはソース以外のLOCATORです。存在確認のみ行い、行番号の処理はしません。b. スナップショット一致確認(Block B): 指摘の
discovery_commitと現在のSNAPSHOT_IDを比較し、この指摘についてMATCHED/NOT_MATCHEDを判定します。SNAPSHOT MATCH CHECK for finding F (decides MATCHED vs NOT_MATCHED): 1. If snapshot_pinned is false -> NOT_MATCHED. Stop. 2. Read F.discovery_commit: - missing OR empty OR the literal "MIXED" -> NOT_MATCHED. - not exactly equal to SNAPSHOT_ID -> NOT_MATCHED. - exactly equal to SNAPSHOT_ID -> MATCHED. There is no other route to MATCHED; never fuzzy-compare. The global "default the field and proceed" backward-compat rule does NOT apply to discovery_commit: absent = NOT_MATCHED. (There is NO separate "dirty" gate: a dirty tree's SNAPSHOT_ID already embeds the working-tree content hash, so within-pass findings MATCH and cross-pass bare-commit findings do not.)c. ドリフト/ファイル欠落/範囲外のガード(フェイルセーフ — 決してNON_VIABLEにしないこと): Block Bの結果がNOT_MATCHEDの場合、または特定した対象ファイルがCODE_ROOT配下に存在しない場合、または指定された行番号がファイルの末尾を超えている場合(範囲外)は、この指摘に対してドメイン固有の実行可能性分析(ステップ4~5)を実行してはならず、
NON_VIABLEにしてもなりません(ファイルの欠落はデッドコードを意味しません。また、NON_VIABLEはmantis-calibrateによって破棄されます)。例外(MODE-OFFのみ — active_snapshotがない場合): SNAPSHOT_IDがUNAVAILABLE(MODE-OFF:stateに
active_snapshotがなく、--snapshot_idも指定されていない)で、NOT_MATCHEDの唯一の原因がSNAPSHOT_IDの欠落/利用不可である場合(ファイルの欠落や行番号の範囲外ではない場合)、これを「比較不可」として扱い、通常の評価(ステップ3d)に進みます。これにより、非同期実行時の現在の動作が維持されます。HALTモード(active_snapshotが存在し、snapshot_pinned=false)では、この例外は適用されません。Block Bの結果はNOT_MATCHEDであり、指摘はドリフトとして扱われます。つまり、以下の「それ以外」の分岐に従ってCONDITIONAL_VIABLEとし、mantis-calibrateが破棄するNON_VIABLEにはしません。ファイル欠落および行番号の範囲外の条件は、ピン留めの有無やモードに関係なく、引き続きCONDITIONAL_VIABLEとします。それ以外(ドリフト、ファイル欠落、または範囲外):
production_viabilityを**CONDITIONAL_VIABLE**に設定し、原因を明記したドリフトに関する注記をcritic_reasoningに記録します。例:"Snapshot drift: discovery_commit=<disc> != active SNAPSHOT_ID=<id> (or the target file/line is no longer present at the pinned snapshot); could not re-verify viability, defaulting to CONDITIONAL_VIABLE (conservative)."その後、ステップ6で更新を記録し、次の指摘に進みます。この指摘は、ステップ7でCONDITIONAL_VIABLEとして引き続き長期メモリに記録されます。d. MATCHED、ファイルが存在し、行番号が範囲内の場合: CODE_ROOTから対象ファイルを読み込み、指定された行番号の前後それぞれ少なくとも15行のコンテキストを読み取ります。この対象範囲は、周囲の構造やマクロ定義を分析するために必要です。さらに、
repro_hintsとhistoryを調べ、mantis-reproduceが記録した実行テレメトリー(例:build_profile、sanitizers_used、assertions_disabled、ingress_blocked)を確認します。この実行テレメトリーを用いて、リリースビルドでの実行可能性を裏付けます。ステップ4~5に進みます。 -
ドメイン固有の実行可能性制約を評価する:
- メモリ安全性の欠陥の場合: 影響を受けるバッファーの割り当て元を特定します。安全マージンまたは末尾のパディングを設けて割り当てられているかどうかを判断します。範囲外アクセスが物理的なパディング内に収まる場合は、NON_VIABLEとします。
- ロジックおよび認可の欠陥の場合: 欠陥のあるロジックやバイパスされたエンドポイントが、標準的な本番環境で実際にアクセス可能かどうかを確認します。この欠陥がデバッグ専用のバックドア、モック認証プロバイダー、またはテスト専用のルートに依存している場合は、NON_VIABLEとします。
-
実行可能性ステータスを決定する: 優先順位を適切に設定できるよう、指摘に以下の実行可能性ステータスのいずれかを割り当てます。
NON_VIABLE: その欠陥は本番環境では到達不能であるか、コンパイル時に除外されています。 これには以下が含まれます:- 無効化されたアサーション(メモリ欠陥): 標準の
assert()、debug_abort()、または開発専用のパニックに依存して クラッシュ/DoS 状態を引き起こすバグで、NDEBUGによってそれらが除去され、コードが安全に戻るもの。 - デバッグ専用機能: デバッグフラグ(例:
#ifdef DEBUG)で条件付きコンパイルされるもの。 - 環境制御によってブロックされている: 回避できない標準的で 構成変更不可能な本番環境の制御(例:OS レベルの パーミッション、カーネルレベルのサンドボックス化、読み取り専用ファイルシステム)によってブロックされているもの。
- 無効化されたアサーション(メモリ欠陥): 標準の
SAMPLE_OR_TEST: その問題はサンプルコード、テストスイート、 ファジングハーネス、または検証フレームワーク内に存在します。CONDITIONAL_VIABLE: その欠陥は、特定の 非デフォルト構成、オプションのコンパイラフラグ、または本番環境によって異なる可能性のあるカスタム ハードニングオプションの下でのみ悪用可能です。VIABLE: その欠陥は標準の リリース/本番ビルドで完全にトリガー可能です。
-
トークン最適化されたファイル更新: LLM の出力トークンを最小限に抑えるため、出力内で JSON オブジェクト全体を再出力したり手動で書き直したりしないでください。 代わりに、 インプレース編集ツール(お好みの言語での短いスクリプト、 または
jqなど)を使用して、新しいフィールドを既存のworkspace/findings/<id>.jsonファイルにプログラムで追記してください。既存のオブジェクトに以下を追記する必要があります:
"production_viability"フィールド("VIABLE"、"NON_VIABLE"、"SAMPLE_OR_TEST"、または"CONDITIONAL_VIABLE")。- 評価を説明する
"critic_reasoning"フィールド。 "history"配列へのエントリ:
{ "stage": "critic", "action": "evaluated", "details": "Determined production viability as [VIABLE/NON_VIABLE/SAMPLE_OR_TEST/CONDITIONAL_VIABLE] because [reason]", "pass_number": <current_pass_number>, "snapshot": "<SNAPSHOT_ID>", "timestamp": "<current_iso8601_timestamp>" }"snapshot"は、ロケーター解決で解決されたSNAPSHOT_IDに設定します。SNAPSHOT_IDが UNAVAILABLE(MODE-OFF)の場合は、""に設定します(またはキーを省略します)。 id を捏造しないでください。 -
長期メモリへの追記: ロードした各所見 (
NON_VIABLE、SAMPLE_OR_TEST、CONDITIONAL_VIABLE、FALSE_POSITIVE、およびNEEDS_RESEARCHを含む)について、workspace/learnings.jsonlという名前のワークスペース データベースファイルに、単一の構造化 JSON 行を追記します(追記モードを使用)。 これにより、検証結果が実行をまたいで記憶され、ストラテジストがそれらを再スキャンするのを 避けるのに役立ちます。- メモリエントリの形式:
{"title": "[security_flaw_title]", "code_paths": ["[path1:line1]"], "status": "[VIABLE / CONDITIONAL_VIABLE / NON_VIABLE / SAMPLE_OR_TEST / FALSE_POSITIVE / NEEDS_RESEARCH]", "snapshot": "[current SNAPSHOT_ID, or omit in MODE-OFF]"}
- メモリエントリの形式:
完了したら、ユーザーに通知します。