mcpField
M
mantis-chain

mantis-chain

github.com/googleセキュリティ2.7k1.5k 回インストール3 日前に更新
リポジトリ

mantis-chain について

検証済みの脆弱性情報とナレッジベースの項目を分析し、複数段階のエクスプロイトチェーンを探すMantisのセキュリティスキルです。スナップショット固定時は、現在のコードスナップショットに一致する情報だけを使います。

主な機能

  1. 01検証済み脆弱性情報の分析
  2. 02前提条件と効果による情報の連結
  3. 03ナレッジベースの要素を連鎖に利用
  4. 04スナップショット一致による構成要素の選別
  5. 05実行間のチェーン重複を回避

活用シーン

  1. 01複数の脆弱性を組み合わせた影響の評価
  2. 02アーキテクチャ要素を使った攻撃経路の発見
  3. 03固定スナップショットのチェーンから古い情報を排除

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/google/mantis --skill mantis-chain

インストール後、Claude Code で/mantis-chainを入力して読み込まれたか確認します。

詳細

脆弱性チェイナー(/mantis-chain)

システムの目的

エクスプロイトチェーンの設計者です。個別に検証された分離状態のセキュリティ検出結果と、過去のナレッジベースのプリミティブを分析し、複雑な複数ステップのエクスプロイトチェーンを特定して構築します。

コマンドの定義

  • コマンド: /mantis-chain
  • 説明: 個々のセキュリティ検出結果を分析し、複雑なエクスプロイトチェーンを特定して構築します。
  • 引数(すべて省略可能。ハーネスのライフサイクル契約に従ってオーケストレーターが指定します。schema.json の「Non-JSON Contracts」を参照):
    • --snapshot_root / SNAPSHOT_ROOT — このパスで固定された不変のコードスナップショットのルートです。ブロック A で使用されます。
    • --snapshot_id / SNAPSHOT_ID — このパスのスナップショット識別文字列です。ブロック A(センチネル)とブロック B(一致確認)で使用されます。
    • --state_root — workspace/ の親ディレクトリです。指定されない場合は、現在のディレクトリがデフォルトになります(ブロック A のステップ 1c/1d)。
    • --target_root — スナップショットのルートを上書きする、事前に準備されたツリーです(この段階で使用されることはまれですが、ブロック A のステップ 1a で考慮されます)。これらの引数がいずれも渡されない場合、ブロック A は workspace/.mantis_state.json 内の active_snapshot にフォールバックします。それも存在しない場合、ステージは MODE-OFF(snapshot_pinned = false)で実行され、従来どおりの動作になります(後方互換性を参照)。

入出力の契約

  • 読み込み対象:
    • workspace/findings/(ステータスが "VALID"で、実行可能性が"VIABLE"、"CONDITIONAL_VIABLE"、または "SAMPLE_OR_TEST"である、検証済みの検出結果 JSON ファイル)。
    • workspace/kb/entities/*.mdおよびworkspace/kb/vulnerabilities/*.md (ナレッジベースの基本要素)。
    • workspace/.mantis_state.json(現在のループパスを追跡するため)。
  • 書き込み先:
    • 新規のエクスプロイトチェーン検出結果 JSON ファイルを workspace/findings/<new_uuid>.jsonに書き込みます。元の検出結果は変更しません。
  • 前提条件:
    • 検証済み、または実行可能な検出結果がworkspace/findings/に存在する必要があります。
  • 冪等性の保証:
    • 新しいエクスプロイトチェーン検出結果を書き込む前に、構成要素となる検出結果の順序を比較して、既存のエクスプロイトチェーン検出結果を確認する必要があります。現在のworkspace/findings/ディレクトリと、すべてのアーカイブ済みパスworkspace/archive/findings_pass_*/および旧形式のworkspace/archive/loop*_findings/の両方をスキャンしてください(すべてSTATE-RELATIVEです。CODE_ROOTを決して先頭に付けないでください)。constituent_findings配列が存在し、空でない検出結果は、すべてチェーン JSON とみなします。いずれかの場所に、構成要素の順序付きシーケンスが完全に同一のチェーン JSON がすでに存在する場合は、重複の作成をスキップします。
    • **シグネチャをキーとする冪等性(優先)— code_pathsによる同順位判定:**すべての構成要素の検出結果にsignatureフィールドがある場合、UUID ではなく、構成要素の順序付きsignatureシーケンスを比較します。対応する構成要素の各ペアについて、少なくとも1つのcode_pathsエントリ(行番号を含む。つまり、末尾の:lineも含めて比較)が一致する場合に限り、2つのチェーンを同一とみなして(新しいチェーンの作成をスキップして)ください。シグネチャシーケンスが一致しても、対応する構成要素のcode_pathsが1つでも異なる場合、チェーンは別個のものです。新しいチェーンを作成してください。(報告の過剰は安全です。signatureは行番号を除去するため、同じファイル内の別々のバグ間で衝突することがあります。シグネチャの衝突によって、本当に新しいエクスプロイトチェーンが決して抑止されないようにしてください。)
    • **UUID フォールバック(現在の動作):**構成要素の検出結果にsignatureフィールドがないものが1つでもある場合、従来どおり、構成要素の順序付き UUID シーケンスを厳密に比較します。これにより、従来の形式の検出結果や未アップグレードの検出結果に対する、現在の動作が維持されます。
    • 安定した検出結果のシグネチャにより、アーカイブのスキャンが完全に有効になりました。構成要素のシグネチャが一致する2つのチェーンは、パスをまたいで正しく重複排除されます。シグネチャがない場合(従来形式の検出結果)も、スキャンは無害です。正当な新しいチェーンを誤って抑止すること(結果が黙って破棄されること)はなく、再開または再実行されたパス内で UUID が完全に一致する重複のみを防ぎます。workspace/archive/ディレクトリが存在しない場合、アーカイブ済みの検出結果は空として扱い、そのまま続行してください。

手順

ロケーター解決(最初に実行 — 全ステージ)
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-adapter Scenario 2 のハーネス側にあります): active_snapshot が 存在し、かつ active_snapshot.pass != state.pass_number の場合、このパスではスナップショットを 古いものとして扱います — 「stale active_snapshot: pass mismatch」で停止するか、 HALT に退化させます(snapshot_pinned は実質的に false:権威ある判定なし、 Block B は NOT_MATCHED、再現は not_attempted)。これは、パス 15 のインクリメント後も 再ピン留めせずに active_snapshot を保持したカスタムハーネスを検出します。 リファレンスのメタエージェントは毎パス再ピン留めするため、この確認がそこで 発動することはありません。Block B 自体ではこれを検出できません(snapshot_id のみを 対象とし、pass は認識しません)。

Block A に関するステージ固有の注意事項:

  • mantis-chain は検出結果のみを扱うステージではありません(report/calibrate/reflect

ではありません)。そのため、Block A はステップ 1〜6 を実行し、 --snapshot_root / --snapshot_id / state active_snapshot から CODE_ROOT、 SNAPSHOT_ID、snapshot_pinned を解決します。

  • このステージでは、新しい検出結果 JSON のみを workspace/findings/ (状態相対パス、Block A ステップ 3)に書き込みます。CODE_ROOT 配下には書き込まないため、Block

A のステップ 4 は自動的に満たされます。チェーンの妥当性確認のために、構成要素の code_paths を任意で再調査する場合は、CODE_ROOT 配下のスナップショット相対パス (Block A ステップ 3)から読み取り、そこへ移動して書き込むことは決してしないでください。

  • チェーンの検出結果の code_paths は、構成要素からそのままコピーされます(すでに スナップショット相対パスです)。前置詞の追加、再解決、番号の振り直しは 行わないでください。
スナップショット一致確認(構成要素の選択に使用)
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.)

以下のステップ 1 では、候補となる構成要素の検出結果ごとに Block B を 1 回実行し、 その検出結果の discovery_commit を F.discovery_commit として使用します。

現在の検証済み検出結果の一括データを読み込み、深刻度が低いと思われる、または互いに関連性がない複数の脆弱性を順番に組み合わせることで、より大きな影響を伴う侵害が可能になるかを調査します。

次の手順でチェーン化ステージを実行します:

  1. プリミティブと検証済み検出結果を読み込む:

    • workspace/findings/ ディレクトリ内の JSON ファイルを読み取ります。検証に合格した 所見(例: status が "VALID" で、viability が "VIABLE"、"CONDITIONAL_VIABLE"、 または "SAMPLE_OR_TEST")をフィルタリングします。
    • スナップショット適格性ゲート(NEW — active_snapshot の有無で分岐する 3 状態モデル):
      • MODE-OFF(state に active_snapshot がない — --sync が要求されておらず、 これが今日のデフォルト): このゲートを完全にスキップします。上記の 検証/viability フィルターを通過したすべての所見が、今日とまったく同じように 適格な構成要素となります。チェーンは通常どおり構築します。
      • HALT(active_snapshot は存在するが snapshot_pinned == false): このパスではチェーンを一切構築しないでください。HALT では、所見のロケーターや 事前/事後条件が古くなっている可能性があり(ツリーが競合した、またはピン留め できなかった)、権威あるチェーンの判定を生成できません。ログに「no chain: HALT mode (active_snapshot present, snapshot_pinned=false)」を記録し、チェーン構築 ステージをクリーンに停止します(チェーンファイルを生成しません)。これは 以下の最小適格性ガードと同じ考え方です — チェーンにはスナップショットに対して 証明された構成要素が必要であり、HALT ではそれを提供できません。
      • PINNED(active_snapshot が存在し、かつ snapshot_pinned == true): そのような各所見に対して、その discovery_commit を用いて スナップショット一致チェック(ブロック B) を実行します。MATCHED を 返した所見のみを適格な構成要素として保持します。NOT_MATCHED を返した所見 — つまり discovery_commit が存在しない/空である所見、リテラルの "MIXED" である所見、または現在の SNAPSHOT_ID と異なる所見を含む — は、別のコード スナップショットに対して発見されたものであり、その file:line ロケーターや 事前/事後条件がもはや成立しない可能性があるため、このパスではチェーンの リンクとして使用してはいけません。
    • 最小適格性ガード(NEW): 適格な構成要素が 2 つ未満しか残らない場合、 このパスではチェーンを構築しないでください — チェーンには同じスナップショットに 対して証明された少なくとも 2 つのリンクが必要です。ログに「no chain: fewer than 2 snapshot-matched constituents」を記録し、チェーン構築ステージをクリーンに 停止します(これはエラーではありません。単にチェーンファイルを生成しないだけ です)。これは、チェーン可能な所見が 2 つ未満の場合の今日の動作と同じです。
    • Markdown ナレッジベース(workspace/kb/entities/ および workspace/kb/vulnerabilities/)を読み取り、それ自体ではバグではないものの、 足がかりとなり得るアーキテクチャ上のプリミティブ(例: 「ユーザーがファイル アップロードパスを制御できる」、「サービスが root として実行される」)を 特定します。
  2. 所見横断分析(チェーン構築マトリクス):

    • 検証済みの各所見の事前条件と事後条件を分析します。
    • 問いかけます: 所見 A の出力または副作用は、所見 B をトリガーするために必要な 厳格な事前条件を満たすことができるか?
    • 探すべきチェーンの例:
      • パストラバーサル + 緩いパーミッション = RCE: 低深刻度のパストラバーサル (所見 A)により /tmp への書き込みが可能になり、別の設定ミス(所見 B)に より cron ジョブが /tmp 内のスクリプトを実行できる。
      • XSS + CSRF = アカウント乗っ取り: 格納型 XSS(所見 A)を使用して anti-CSRF トークンを窃取し、状態を変更するアクション(所見 B)を実行できる。
      • 情報漏洩(メモリ露出)+ バッファオーバーフロー = ASLR バイパス: 情報漏洩(所見 A)によりベースポインタが明らかになり、スタックバッファ オーバーフロー(所見 B)を悪用するための事前条件が満たされる。
  3. 「スーパー所見」の構築:

    • 実行可能なエクスプロイトチェーンが見つかった場合でも、元の分離された所見を変更または削除しないでください。それらも個別にパッチを適用する必要があります。
    • 冪等性チェック(UUID の生成前に実行): 上記の冪等性保証を適用し、現在の workspace/findings/、workspace/archive/findings_pass_*/、および従来の workspace/archive/loop*_findings/ をスキャンして、構成要素の順序付きシーケンスがこのチェーンの順序付き構成要素シーケンスと一致するチェーンがないか確認します。すべての構成要素に signature がある場合は、順序付きの signature シーケンスを比較し、冪等性保証で説明されている構成要素ごとの行を含む code_paths のタイブレークも必須とします。signature シーケンスの一致だけではスキップするには不十分です。いずれかの構成要素に signature がない場合は、順序付きの構成要素 UUID シーケンスにフォールバックします(現行の動作)。タイブレーク条件を満たす一致がある場合に限り、このチェーンをスキップし(ファイルを作成せず)、次の候補に進みます。
    • 代わりに、新しい UUID を生成し、workspace/findings/<new_uuid>.json に新しい所見 JSON ファイルを作成します。
    • 構成要素の所見: 構造化された "constituent_findings" プロパティに、構成要素となる所見の UUID の配列を必ず記録します(例:["UUID_A", "UUID_B"])。これにより、エクスプロイトチェーンの関連性を明確に記録できます。
    • 検出スナップショット(discovery_commit)を決定する: チェーン所見の discovery_commit は、対象として残した構成要素(ステップ 1 で残したもの)から設定します。
      • MODE-OFF の早期終了(3 状態ルール): 状態内に active_snapshot が存在しない場合(MODE-OFF、つまり --sync が要求されていない場合)、チェーン所見には discovery_commit を含めません。MODE-OFF では、調査者はすべての構成要素で discovery_commit を省略します(researcher:317,340-341:「active_snapshot が存在しないか、snapshot_pinned が false の場合は、このキー自体を省略する」)。したがって、すべての構成要素で discovery_commit は欠落または空になります。そのため、以下の SAME/MIXED ロジックでは、すべてのチェーンに文字列 "MIXED" が書き込まれてしまいます。これは Phase 1 には存在せず、MODE-OFF の「現在の動作とバイト単位で同一」という保証(schema.json:4)に反します。チェーン独自のスキーマコメント(chain:307)にも「レガシーまたは固定されていない実行では存在しない」とあり、MODE-OFF で意図されているのは "MIXED" ではなく省略であることが確認できます(機能上の影響は小さく、schema.json:232 では「欠落」と "MIXED" のどちらも NOT_MATCHED として扱いますが、モードの一貫性は重要です)。MODE-OFF では "MIXED" やその他の値を書き込まないでください。
      • 対象となるすべての構成要素で discovery_commit が同じ空でない値の場合、チェーンの discovery_commit にその文字列をそのまま設定します。
      • 構成要素間で discovery_commit の値が異なる場合、または対象となる構成要素のいずれかで discovery_commit が欠落もしくは空の場合(PINNED/HALT モードでのみ発生し、MODE-OFF では上記の早期終了によりこのフィールドがすでに省略されています)、チェーンの discovery_commit に文字列 "MIXED" を設定します。この値を独自に生成、ハッシュ化、または曖昧に正規化しないでください。文字列をそのままコピーするか、リテラルの "MIXED" を書き込みます。理由:固定モードでは、対象となるすべての構成要素が MATCHED であるため、同じ現在の SNAPSHOT_ID を共有し、チェーンもそれを引き継ぎます(その後、チェーンに対して Block B を実行すると、このパスに MATCHES します)。"MIXED" の番兵値により、単一のスナップショットに基づいてリンクを証明できないチェーンに対する安全な分岐として、Block B はそのチェーンを NOT_MATCHED として返します(Block B のステップ 2 では、リテラルの "MIXED" を NOT_MATCHED として扱います)。
    • signature の計算(チェーンの決定的なコンテンツ識別ハッシュ):
      • 対象となるすべての構成要素の所見から signature フィールドを収集します(ステップ 1 の discovery_commit で使用したものと同じ集合です)。
      • 対象となるすべての構成要素に空でない signature がある場合:構成要素の signature を辞書順(昇順)にソートし、signature = sha256("chain|" + "|".join(sorted_constituent_signatures)) の先頭 16 桁の 16 進文字列として計算します。"chain|" のプレフィックスにより、チェーン以外の所見の signature(タイトル+cwe+ターゲットからハッシュ化されます)との衝突を防ぎます。ソートにより、構成要素の順序を入れ替えてもチェーンの signature は変わりません。
      • 対象となる構成要素のいずれかで signature フィールドが欠落している場合(レガシー、またはアップグレードされていない所見):チェーンの signature を空文字列に設定し、JSON には含めません(下流のコンシューマーは schema.json:256 に従い UUID ベースの折りたたみ/重複排除にフォールバックします)。この安全な分岐では、誤った折りたたみが発生することはなく、報告が過剰になる可能性だけがあります。
      • チェーンの作成時に signature を一度だけ計算し、その後は再計算、編集、独自生成を決して行わないでください(discovery_commit と同じルールで、通常の所見に関する researcher:241-242 のルールと同じです)。
    • lineage_id の計算(パスをまたぐチェーンの系譜):
      • workspace/archive/findings_pass_*/ および従来の workspace/archive/loop*_findings/ をスキャンし、アーカイブされたチェーン所見 JSON(空でない constituent_findings 配列を持つ所見)のうち、signature フィールドがこのチェーンで計算した signature と完全一致するものを探します。
      • 一致が見つかった場合:lineage_id に、アーカイブされた祖先の lineage_id を設定します(レポートでパスをまたいで折りたためるように、系譜を引き継ぎます)。同じ signature を持つアーカイブ済みチェーンが複数ある場合は、最も新しい(パス番号が最も大きい)祖先から継承します。同じチェーン signature を持つすべての祖先で、同じ lineage_id を共有することが望ましいです。一致しない場合は、最も新しい祖先から継承し、警告を記録します。
      • 一致がない場合(このチェーンの signature が空文字列の場合を含む):lineage_id に新しい UUIDv4 を設定します。
      • これらは状態に依存するパスです(Block A のステップ 3)。CODE_ROOT ではなく、--state_root/workspace/archive/ の下を読み取ってください。(スキャン対象とアルゴリズムの構造は、通常の所見に関する researcher:246-272 と同じです。チェーンでは、名前の正規化に基づくリネームのフォールバックを省略します。チェーンの識別情報は単一ファイルのパスではなく、構成要素の集合であるためです。)
    • エントリーポイントの権限を決定する: チェーンの privileges_required フィールドには、チェーンの最初のステップ(エントリーポイント)を開始するのに必要な権限レベルを設定します。たとえば、未認証のエクスプロイト(NONE)で始まり、そこから管理者アクセスを獲得し、それを使って RCE を引き起こすチェーンの場合、チェーンの privileges_required は NONE に設定する必要があります。
    • 攻撃者の位置を決定する: チェーンの attacker_position フィールドには、チェーンのエントリーポイント、つまり最初の構成要素の所見から攻撃者の位置を引き継ぎます。
    • ユーザー操作の要件を決定する: エントリーポイントまたはチェーン内のいずれかのステップでユーザー操作が必要な場合、チェーンの user_interaction フィールドを REQUIRED に設定します。チェーン全体がゼロクリックの場合に限り、NONE に設定します。
    • ステータスを決定する: status を "VALID" に設定します。
    • 本番環境での実行可能性を決定する: 構成要素となる所見から引き継ぎます。いずれかの構成要素が "SAMPLE_OR_TEST" の場合は "SAMPLE_OR_TEST" に設定します。それ以外で、いずれかの構成要素が "CONDITIONAL_VIABLE" の場合は "CONDITIONAL_VIABLE" に設定します。それ以外の場合は "VIABLE" に設定します。
    • 再現ステータスを決定する: 構成要素となる所見から引き継ぎます。
      • いずれかの構成要素の repro_status が "failed_to_reproduce" または "not_attempted" の場合は、"not_attempted" に設定します。
      • それ以外で、すべての構成要素の repro_status が "reproduced" または "statically_confirmed" の場合は、"statically_confirmed" に設定します。
      • エクスプロイトチェーンが "reproduced" を引き継ぐことは決してありません(構成要素が再現できても、エンドツーエンドでチェーンが機能する証明にはならないためです)。
    Chain Findings Schema Format (Per File)
    {
      "id": "A unique identifier generated for this chain finding. Must match filename.",
      "title": "Exploit Chain: [Impact] via [Finding A] and [Finding B]",
      "description": "Step-by-step documentation of the exploit chain. Start with Step 1 (Triggering Finding A) and explain how its outcome feeds into Step N (Triggering Finding Z).",
      "impact": "The combined, escalated impact of the chain (e.g., Remote Code Execution, Full Database Exfiltration). This should be higher than the individual findings.",
      "severity": "CRITICAL / HIGH",
      "privileges_required": "NONE / LOW / HIGH",
      "user_interaction": "NONE / REQUIRED",
      "code_paths": [
        "relative/file/path_A.c:line_number",
        "relative/file/path_B.c:line_number"
      ],
      "attacker_position": "EXTERNAL / LOCAL / etc. (inherited from entry point)",
      "mitigation": "Recommended strategy to break the chain. Usually involves fixing at least one, if not all, of the underlying links.",
      "status": "VALID",
      "production_viability": "VIABLE / SAMPLE_OR_TEST / CONDITIONAL_VIABLE",
      "repro_status": "statically_confirmed / not_attempted",
      "constituent_findings": ["UUID_A", "UUID_B"],
      "signature": "First 16 hex chars of sha256(\"chain|\" + \"|\".join(sorted(constituent_signatures))) if EVERY constituent has a non-empty `signature`; else the EMPTY STRING (absent-equivalent -> downstream falls back to UUID-only behavior). Computed ONCE at chain creation and NEVER recomputed (same rule as discovery_commit). See the signature/lineage computation steps above.",
      "lineage_id": "Inherited from the most-recent archived chain finding whose `signature` equals this chain's `signature` (scan workspace/archive/findings_pass_*/ AND workspace/archive/loop*_findings/); else a fresh UUIDv4. See the signature/lineage computation steps above.",
      "discovery_commit": "The SNAPSHOT_ID shared by all constituents, or the literal \"MIXED\" if they differ / are missing (only computed in PINNED/HALT mode). OMITTED (absent) on legacy/unpinned runs (MODE-OFF) — see the MODE-OFF short-circuit in the discovery_commit computation step above.",
      "history": [
        {
          "stage": "chainer",
          "action": "created",
          "details": "Constructed by chaining findings [UUID_A] and [UUID_B].",
          "pass_number": <current_pass_number>,
          "timestamp": "<current_iso8601_timestamp>"
        }
      ]
    }
    
  4. Chain Deduplication Tagging:

    • To ensure /mantis-dedupe treats these chains differently than raw findings, ensure the word "Chain" is prominently featured in the "title" and "history" fields as shown in the schema.

新たに作成したチェーンファイルは、必ず workspace/findings/ ディレクトリに書き込んでください。完了したら、ユーザーに通知してください。

コメント