mantis-plan

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Strategist (/mantis-plan)

策略生成器(/mantis-plan)

System Goal

系统目标

Security Architect. Analyzes code structure, directory metadata, and historical records to map the external boundary and formulate an adaptive review roadmap.
安全架构师。分析代码结构、目录元数据和历史记录,以映射外部边界并制定自适应评审路线图。

Command Definition

命令定义

  • Command:
    /mantis-plan
  • Description: Formulates a targeted defensive security reviewing plan based on the active threat model and historical learnings.
  • Arguments (optional; supplied by the orchestrator, consumed by Block A):
    • --snapshot_root
      /
      SNAPSHOT_ROOT
      : absolute path to the pinned read-only code snapshot (CODE_ROOT for all snapshot-relative paths).
    • --snapshot_id
      /
      SNAPSHOT_ID
      : the pass snapshot identifier (sentinel + Block B comparisons).
    • --state_root
      : absolute path to the
      workspace/
      state dir (plan.json, .mantis_state.json, findings/, kb/, archive/). STATE-RELATIVE — never prefixed with CODE_ROOT.
    • All flags absent -> MODE-OFF/legacy mode (Block A step 1d): behaves exactly as today.
  • 命令:
    /mantis-plan
  • 描述: 基于当前威胁模型和历史经验制定针对性的防御安全评审计划。
  • 参数(可选;由编排器提供,供Block A使用):
    • --snapshot_root
      /
      SNAPSHOT_ROOT
      :固定只读代码快照的绝对路径(所有快照相对路径的CODE_ROOT)。
    • --snapshot_id
      /
      SNAPSHOT_ID
      :本次快照的标识符(用于Block B比较的标记)。
    • --state_root
      workspace/
      状态目录的绝对路径(包含plan.json、.mantis_state.json、findings/、kb/、archive/)。为状态相对路径——切勿以CODE_ROOT作为前缀。
    • 所有标志缺失 -> MODE-OFF/传统模式(Block A步骤1d):与当前行为完全一致。

Input/Output Contract

输入/输出约定

  • Reads:
    • workspace/.mantis_state.json
      (to track current loop pass).
    • workspace/kb/THREAT_MODEL.md
      (if exists).
    • workspace/kb/index.md
      (checks existence to determine Mode A vs B).
    • Mode A: traverses production directories and source files, reads
      mantis-summary.md
      (if available).
    • Mode B: reads
      workspace/kb/index.md
      ,
      workspace/kb/THREAT_MODEL.md
      ,
      workspace/archive/.repro_attempts.json
      (if exists), VCS diffs or file timestamps/hashes.
    • workspace/kb/structural_index/manifest.json
      (to check structural index availability/status).
    • workspace/helpers/query_structural_index.py
      (to invoke bounded structural-index queries).
    • workspace/.mantis_state.json
      NEW fields:
      active_snapshot.{snapshot_id, snapshot_pinned, vcs_type}
      ,
      snapshot_history
      (read, written by the meta-agent).
      vcs_type
      is read because Block E branches on it. Plan runs Block E in the LIVE repo root to compute
      changed_files
      /
      changed_files_status
      (COMPUTED or UNKNOWN) and writes them back to state.
  • Writes:
    • workspace/plan.json
      .
    • Copies retry-eligible finding JSON files from
      workspace/archive/findings_pass_K/
      or
      workspace/archive/loopK_findings/
      (where K is the pass it was archived in) to
      workspace/findings/
      (preserving their original UUID filenames).
  • Preconditions:
    • Codebase must be accessible.
  • Idempotency Guarantee:
    • Overwrites
      workspace/plan.json
      directly. In Mode B, copies a finding back verbatim only when Block B is MATCHED and its file is unchanged and present; otherwise it schedules a fresh re-discovery investigation. Consults
      .repro_attempts.json
      under the cache read rule.
  • 读取内容:
    • workspace/.mantis_state.json
      (用于跟踪当前循环轮次)。
    • workspace/kb/THREAT_MODEL.md
      (如果存在)。
    • workspace/kb/index.md
      (检查是否存在以确定Mode A或Mode B)。
    • Mode A:遍历生产目录和源文件,读取
      mantis-summary.md
      (如果可用)。
    • Mode B:读取
      workspace/kb/index.md
      workspace/kb/THREAT_MODEL.md
      workspace/archive/.repro_attempts.json
      (如果存在)、版本控制系统(VCS)差异或文件时间戳/哈希值。
    • workspace/kb/structural_index/manifest.json
      (用于检查结构索引的可用性/状态)。
    • workspace/helpers/query_structural_index.py
      (用于调用受限的结构索引查询)。
    • workspace/.mantis_state.json
      新增字段:
      active_snapshot.{snapshot_id, snapshot_pinned, vcs_type}
      snapshot_history
      (由元代理读取和写入)。读取
      vcs_type
      是因为Block E会根据它分支执行。计划在LIVE仓库根目录运行Block E,计算
      changed_files
      /
      changed_files_status
      (COMPUTED或UNKNOWN)并将其写回状态。
  • 写入内容:
    • workspace/plan.json
    • 将符合重试条件的发现JSON文件从
      workspace/archive/findings_pass_K/
      workspace/archive/loopK_findings/
      (K为归档时的轮次)复制到
      workspace/findings/
      (保留其原始UUID文件名)。
  • 前置条件:
    • 代码库必须可访问。
  • 幂等性保证:
    • 直接覆盖
      workspace/plan.json
      。在Mode B中,仅当Block B匹配且文件未更改并存在时,才将发现原样复制回来;否则安排新的重新发现调查。根据缓存读取规则查阅
      .repro_attempts.json

Instructions

操作说明

Step 0: Locator Resolution (run before everything else)

步骤0:定位器解析(在所有操作之前运行)

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.
[!NOTE] CURRENT-PASS CHECK (defensive; the binding guarantee is on the harness per
mantis-pipeline-adapter
Scenario 2):
if
active_snapshot
is present AND
active_snapshot.pass != state.pass_number
, treat the snapshot as STALE for this pass — STOP "stale active_snapshot: pass mismatch" or degrade as HALT (
snapshot_pinned
effectively false: no authoritative verdicts, Block B NOT_MATCHED, reproduce
not_attempted
). This catches a custom harness that preserved
active_snapshot
across the Stage 15 pass increment without re-pinning. The reference meta-agent re-pins every pass, so this check never fires there. Block B itself cannot detect this (it is
snapshot_id
-only, not
pass
-aware).
Skill-specific notes for the strategist:
  • Plan is a CODE-READING stage in Mode A (it crawls production directories); the findings-only skip does NOT apply.
  • Mode A crawling and every
    target_files
    path are SNAPSHOT-RELATIVE: crawl and resolve them under CODE_ROOT.
  • workspace/kb/
    ,
    workspace/plan.json
    ,
    workspace/.mantis_state.json
    ,
    workspace/archive/
    , and
    workspace/findings/
    are STATE-RELATIVE: read/write them under --state_root, NEVER under CODE_ROOT.
  • Never write, compile, or generate under CODE_ROOT (Block A step 4). The plan script writes ONLY workspace/plan.json (state-relative). The VCS diff in Block E runs in the LIVE repo root per Block A step 5, NOT CODE_ROOT.
Analyze the repository structure and create a detailed defensive security review plan that avoids duplication of prior efforts while digging deep into complex inter-procedural paths and un-scanned code boundaries.
Target Agnosticism Directive: The target you are evaluating may be raw source code, a compiled binary, a firmware blob, or a live staging/dev endpoint. Ground your planning in whatever format the target is currently in. You are authorized and encouraged to use whatever suitable tools are at your disposal (e.g., standard Unix tools,
unblob
,
radare2
,
angr
,
objdump
,
Ghidra
,
qemu
,
unicorn
) to explore the artifact structure. If source code is not available, do not attempt to force a source-code workflow (e.g. searching for
.c
or
.py
files); adapt and 'do what works' for the artifact at hand.
Execute the planning stage as follows:
  1. Check for Threat Model Context: Check the knowledge base directory for a
    workspace/kb/THREAT_MODEL.md
    file. If it exists, read the file it completely to understand the program's official security boundaries, threat actors, assets, high-risk interfaces, and trusted inputs.
  2. Determine Mode & Retrieve Learnings: Check if the knowledge base index
    workspace/kb/index.md
    exists.
    • MODE A: First-Pass Exhaustive Mode (No
      workspace/kb/index.md
      found):
      If this is the first run, guarantee complete coverage of the codebase. To avoid hitting output token limits on large repositories, do not generate the
      workspace/plan.json
      manually in your text response. Instead, execute a shell command to run a short script in your preferred language that:
      1. Uses
        find
        or
        os.walk
        to crawl all production directories. If a
        mantis-summary.md
        file exists in a directory, use its contents to understand the directory structure instead of reading every individual source file. Otherwise, crawl all production source code files (e.g.,
        .c
        ,
        .cpp
        ,
        .py
        ,
        .js
        ,
        .go
        ,
        .rs
        ,
        .java
        ).
      2. Ignores test folders, build artifacts, and vendor dependencies (e.g.,
        node_modules
        ,
        .git
        ,
        tests/
        ).
      3. Programmatically formats the list into the
        workspace/plan.json
        schema and writes it directly to disk. Because this is an automated script, instruct it to use a generic, overarching baseline question for the
        "question"
        field (e.g., "Conduct a baseline audit for memory safety and logic flaws"), reserving highly contextual custom questions for Mode B.
    • MODE B: Strategic Learning Mode (
      workspace/kb/index.md
      exists):
      Read
      workspace/kb/index.md
      and
      workspace/kb/THREAT_MODEL.md
      to review the compounded historical knowledge of the codebase, including trust boundaries, vulnerability classes, and architectural components. Adapt your focus to design new, targeted deep dives and regression reviews for components and files that have histories of vulnerabilities. You may generate the
      workspace/plan.json
      manually using your file-writing tools for this mode, as the scope will be much narrower.
      • Targeted Re-Evaluation & Retries: Review the KB index, entity files, and the reproduction attempt cache file (
        workspace/archive/.repro_attempts.json
        if it exists). You must identify findings that need re-evaluation or retries:
        Also read the snapshot context from
        workspace/.mantis_state.json
        :
        active_snapshot.{snapshot_id, snapshot_pinned}
        and
        snapshot_history
        (both written by the meta-agent). Then COMPUTE
        changed_files
        /
        changed_files_status
        for THIS pass by running Block E below in the LIVE repository root (per Block A step 5 — VCS-metadata carve-out; the pinned --snapshot_root strips .git/.hg/.repo, so the diff MUST run against the live tree). Write the computed
        changed_files
        (array of repo-relative paths) and
        changed_files_status
        (
        COMPUTED
        or
        UNKNOWN
        ) back to
        workspace/.mantis_state.json
        , then use them for the rest of the stage. Also write
        changed_files_pass
        = the current
        pass_number
        from state, so consumers can detect a stale (prior-pass) diff. Use the following to know which files changed since the previous pass:
        CHANGED-SINCE-PREVIOUS: run in the LIVE repository root (NOT SNAPSHOT_ROOT). CUR = current commit/revision; PREV = snapshot_history entry BEFORE this pass. If PREV missing OR vcs_type in {none,unknown} OR the SNAPSHOT_ID for prev or cur is a content:/live:/+content_hash fallback OR the diff command errors -> changed_files_status = UNKNOWN. Treat EVERY file as CHANGED. NEVER treat as unchanged. NEVER drop. (Note:
        snapshot_pinned false
        alone is NOT a trigger for UNKNOWN — in HALT mode,
        active_snapshot
        is present and
        snapshot_history
        has a PREV entry, so the diff can still run. In MODE-OFF — no
        active_snapshot
        — there is no PREV entry, so PREV is missing and the diff degrades to UNKNOWN, but this does NOT force a full Mode-A crawl; see the Mode-A trigger below.) Else: git :
        git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR
        (the
        -M
        flag detects renames;
        -C
        detects copies;
        --name-status
        outputs
        R<score>\told_path\tnew_path
        for renames so both old and new paths are visible;
        --diff-filter=RAMDCT
        includes Renamed, Added, Modified, Deleted, Copied, and Type-changed files) hg :
        hg status -C --rev PREV:CUR
        (
        -C
        /
        --copies
        shows the source path on a following line for renames/copies; hg codes: A=added, R=removed, M=modified) multi-vcs :
        repo forall -c 'git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR'
        (any error -> UNKNOWN) A finding's file is CHANGED if any of its
        code_paths
        (path part) is in the set, OR if its path was renamed-to or renamed-from (parse
        R<score>\told\tnew
        lines: both old and new paths are in the changed set). If a finding's primary file appears as a rename source (old path), treat the NEW path as changed too — the bug likely moved with the file.
        Also apply this cache read rule wherever you inspect
        workspace/archive/.repro_attempts.json
        . FIRST pick the cache KEY exactly the way
        mantis-reproduce
        writes it: if the finding has a
        signature
        field, the key is that
        signature
        ; otherwise the key is
        stable_key = normalized_title + "@" + primary_file_path
        (title lowercased with all non-alphanumerics removed;
        primary_file_path
        = first
        code_paths
        entry with any trailing
        :line
        stripped). THEN read the value V under that key: if V is an integer then count=V and last_snapshot=UNKNOWN; if V is an object then count=V.count and last_snapshot=V.last_snapshot (default UNKNOWN). If no entry is found under the chosen key, also try the OTHER key form before concluding count=0, so a signature-keyed writer and a stable_key reader never miss each other and wrongly reset the attempt budget. (The cache mixes both value forms AND both key styles during migration.)
        1. Schedule for Research: For findings in the archive marked
          "NEEDS_RESEARCH"
          , schedule a targeted investigation in
          workspace/plan.json
          (to gather missing context and resolve them to
          "VALID"
          or
          "FALSE_POSITIVE"
          ).
        2. Copy for Retry (snapshot-gated) or Re-discover: For each archived finding that would otherwise be retry-eligible (repro not attempted, or
          failed_to_reproduce
          with fewer than 2 attempts per the cache read rule above, or
          patch_status
          in {
          VERIFICATION_FAILED
          ,
          ERROR
          ,
          VERIFICATION_INCOMPLETE
          }), run:
          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.)
          Then decide mechanically:
          • COPY VERBATIM (fast retry) ONLY if ALL hold: Block B is MATCHED for the finding, AND its primary file (first
            code_paths
            , line stripped) is NOT in
            changed_files
            , AND that file EXISTS under CODE_ROOT. Copy the archived
            <uuid>.json
            back to
            workspace/findings/<uuid>.json
            preserving the UUID and its ORIGINAL
            discovery_commit
            (do not re-stamp it — drift must stay detectable).
          • MODE-OFF bypass (3-state rule): if
            active_snapshot
            is ABSENT in state (MODE-OFF — no
            --sync
            was requested), Block B always returns NOT_MATCHED (
            snapshot_pinned is false -> NOT_MATCHED
            ), so the COPY-VERBATIM gate above never fires and every retry- eligible finding is RE-DISCOVERed — a regression from today's behavior (today, pass ≥2 carries forward unchanged findings when the file still exists). In MODE-OFF, COPY-VERBATIM when the finding's primary file (first
            code_paths
            , line stripped) EXISTS under CODE_ROOT (drop the
            Block B MATCHED
            and
            file NOT in changed_files
            conjuncts — there is no
            changed_files
            diff in MODE-OFF anyway). This mirrors
            mantis-patch
            's LEGACY-mode carve- out (
            patch:133-138
            ,
            patch:172-174
            ). Do NOT gate the bypass on
            snapshot_pinned==false
            — that would also catch HALT mode, where the STALE banner legitimately marks the finding as needing re-verification. Gate ONLY on
            active_snapshot
            absent. (Do NOT change Block B itself — it is character-identical across skills per
            README_AGENTS.md:711-718
            block-fidelity warning; the fix goes in plan's CONSUMERS of Block B, not Block B.)
          • RE-DISCOVER in every other case (Block B NOT_MATCHED, or file in
            changed_files
            , or file missing, or
            changed_files_status
            ==UNKNOWN): do NOT copy back. Instead append a fresh investigation to
            workspace/plan.json
            that embeds the finding's
            title
            ,
            description
            , and
            repro_hints
            , sets
            target_files
            to the old code_paths' directory subtree(s) PLUS a repository-wide symbol/keyword search for the finding's function/struct/title terms (so a moved/renamed bug is re-found), and asks the researcher to re-derive the exact lines on the CURRENT snapshot. Additionally, record a history note
            unconfirmed-regression-pending
            on the archived finding so it is never silently dropped until a pass re-discovers it or a human dismisses it.
          • Line/AST Re-anchoring (Phase 2 incremental efficiency): Before falling back to full RE-DISCOVER, attempt to re-anchor the finding's line numbers to the CURRENT snapshot using forward line-tracking (reverse blame or diff-hunk offset). This is an optimization: if the finding's primary function/symbol still exists nearby, re-anchoring produces a line-number HINT that focuses the RE-DISCOVER investigation — it does NOT replace re-verification (the snapshot changed, so the finding is still re-researched downstream).
            • How: Translate the finding's old line FORWARD from PREV to CUR (do NOT blame PREV in isolation — that returns the line as of PREV and does not map it forward). Run in the LIVE repo root (Block A step 5 carve-out): git :
              git blame --reverse <PREV>..<CUR> -L <old_line>,<old_line> -- <file>
              (reverse blame follows the line forward to CUR), or add the hunk offset from
              git diff <PREV> <CUR> -- <file>
              to
              <old_line>
              . Then read the mapped line in CODE_ROOT (the current pinned snapshot) and confirm the finding's primary function/symbol is present within ±50 lines. This yields a CANDIDATE new line number only — a search hint for RE-DISCOVER, never a trusted re-validation.
            • When re-anchoring SUCCEEDS (symbol found at the mapped line): use the new line number to FOCUS this finding's RE-DISCOVER investigation (point the researcher at the mapped
              code_paths
              location first). Do NOT convert the finding to COPY-VERBATIM and do NOT skip re-verification: Block B is NOT_MATCHED, so the finding is still re-researched/re-reproduced downstream (a symbol can exist at the mapped line yet already be FIXED). Keep
              discovery_commit
              ,
              signature
              , and
              lineage_id
              unchanged; add a history note
              re-anchored: <old_line> -> <new_line> (search hint)
              .
            • When re-anchoring FAILS (function deleted, symbol not found, diff too large, blame errors, or the code at the old line is completely different): fall back to full RE-DISCOVER as above. This is the conservative guardrail: on ANY uncertainty, re-discover.
            • Never use re-anchoring to suppress or drop a finding. It is purely a fast-path for line-number updates; if it fails, the finding is still re-discovered via the normal path.
            • VCS-agnostic: For hg, diff
              PREV:CUR
              (
              hg diff --rev PREV:CUR -- <file>
              ) and apply the hunk offset to
              <old_line>
              to get the forward-mapped line. For no-VCS/binary targets, re-anchoring is not applicable; always fall back to RE-DISCOVER.
          • NEVER copy back a finding whose
            "status"
            is
            "FALSE_POSITIVE"
            , or
            "patch_status"
            is
            "VERIFIED_SECURE"
            , or
            "repro_status"
            is
            "reproduced"
            (unless patch failed as above), or that has reached the 2-attempt cap for the CURRENT snapshot. But if such a finding's file IS in
            changed_files
            or Block B is NOT_MATCHED, treat it as a possible regression: RE-DISCOVER it (do not trust the old terminal verdict against changed code). MODE-OFF carve-out: if
            active_snapshot
            is ABSENT (MODE-OFF), drop the
            or Block B is NOT_MATCHED
            disjunct above — in MODE-OFF, Block B is NOT_MATCHED for every finding (artifact of no snapshot, not a signal of drift), so leaving the disjunct in would re-open every terminal verdict (FALSE_POSITIVE/VERIFIED_SECURE/reproduced) every pass. In MODE-OFF, rely ONLY on
            file IS in changed_files
            (which is vacuously false in MODE-OFF — there is no
            changed_files
            diff), so terminal findings are carried forward unchanged. This is today's behavior.
      • Changed / new attack-surface coverage (MANDATORY): Add an investigation titled
        Exhaustive Review: <path>
        for EVERY path in
        changed_files
        (whether or not it maps to an archived finding). If
        changed_files_status
        ==UNKNOWN AND
        active_snapshot
        is present (HALT or PINNED mode — a sync was requested this pass), OR a sync occurred this pass (
        snapshot_id
        != the previous
        snapshot_history
        entry's id), you CANNOT trust a narrow set: fall back to a full Mode A exhaustive crawl for this pass EVEN IF
        kb/index.md
        exists (this is the only way to catch newly added files). However, in MODE-OFF (no
        active_snapshot
        — no
        --sync
        ), do NOT force a full Mode-A crawl in pass ≥2 even if
        changed_files_status
        ==UNKNOWN: this is today's default behavior, and forcing Mode-A on every MODE-OFF pass ≥2 would be a regression. In MODE-OFF, rely on the existing
        kb/index.md
        (Mode B) for narrowing, as today.
      • Dependency-aware fan-out (Phase 2 incremental efficiency): When
        changed_files_status
        is known (not UNKNOWN) and a dependency graph is available, EXPAND the investigation scope beyond just the changed files themselves. The goal: identify files that IMPORT or DEPEND ON the changed files, so the planner can schedule targeted investigations for consumers of the changed code (not just the changed code itself).
        • How: Start with the file-level dependency graph (
          workspace/kb/dependencies.json
          or entity-relationship markdown) as the mandatory floor: for each changed file F, find all files that import F (directly or transitively up to 2 hops). Add these dependent files to the investigation scope as
          Exhaustive Review: <dependent_file>
          entries. Then ADD structural index callers on top: use the query helper (
          workspace/helpers/query_structural_index.py
          ) for function-level precision when available — call
          resolve_symbol()
          for a changed file's exported functions, then
          find_callers()
          to enumerate dependents at the symbol level. Schedule investigations for the UNION of dependency-graph-found dependents and structural-index-found callers — they are complementary, not alternatives. If the structural index is absent (no
          manifest.json
          ), empty, or the query helper is missing, the dependency graph alone remains the floor.
        • When to use: ONLY when
          changed_files_status
          is known AND the KB contains dependency information. If the KB lacks an import/build graph, or the KB is stale (check
          kb_snapshot_id
          in
          workspace/.mantis_state.json
          against
          SNAPSHOT_ID
          — if they differ, the KB was built against a different snapshot and may be stale), fall back to the Phase-1 behavior (full Mode-A crawl or Mode-B narrowing).
        • Guardrail: If the dependency graph is incomplete, stale, or any uncertainty arises, fall back to Phase-1 re-discovery (treat ALL files as potentially affected). Never use dependency narrowing to DROP an investigation — it can only ADD targeted investigations for dependent files. The changed files themselves are ALWAYS investigated regardless.
        • VCS-agnostic: The dependency graph is derived from the KB's architecture analysis, not from VCS metadata. It works for any language with import/include/use statements that the KB has indexed.
      • Structural Index Queries (HINT-only enhancement): When a structural index is available (
        workspace/kb/structural_index/manifest.json
        exists), use it to SUPPLEMENT the dependency-aware fan-out above with precise, symbol-level caller discovery. The structural index decides ORDER of investigation priority, NEVER MEMBERSHIP of the audit set.
        • Resolution-first protocol (MANDATORY): Before querying callers, resolve the symbol:
          python3 workspace/helpers/query_structural_index.py resolve_symbol --name "<function_name>" [--language "<lang>"] [--file "<path>"] --state_root <state_root>
          If the response has
          ambiguous: true
          , do NOT silently pick one match. Narrow with
          --file
          /
          --language
          , or schedule investigations for ALL matched symbols.
        • Bounded caller queries: Once resolved, query callers with explicit bounds:
          python3 workspace/helpers/query_structural_index.py find_callers --symbol_id "<resolved_id>" --limit 100 --offset 0 --state_root <state_root>
          Paginate with
          --offset
          if
          has_more
          is true.
        • Coverage-aware interpretation: Check
          coverage.partition_status
          in every structural index response:
          • complete
            +
            precision == semantic
            + no callers = "no indexed callers" — the partition is fully indexed with a semantic backend, so the empty result is authoritative for indexed code. Still run grep per the HINT-only rule (grep catches macro-based calls, function pointers, and dynamic dispatch).
          • complete
            +
            precision != semantic
            + no callers = "no indexed callers" — the partition is complete but precision is below semantic, so the empty result is NOT authoritative. MUST run exhaustive grep fallback.
          • partial
            /
            empty
            /
            failed
            + no callers = "not fully indexed" — the partition is not complete, so expand the investigation scope and MUST run exhaustive grep fallback.
        • Guardrails:
          • HINT-only: structural index results decide ORDER, never MEMBERSHIP. They prioritize which dependent files to investigate first; they MUST NEVER cause a file to be dropped from the audit scope.
          • Every result carries
            precision
            and
            backend
            fields — use
            precision
            (
            semantic
            >
            typecheck
            >
            ast
            >
            symbol-only
            >
            heuristic
            >
            deferred
            >
            coverage-only
            ) to weight trust in the result.
          • If the structural index is absent (no
            manifest.json
            ), empty, or the query helper is missing: fall back to grep-based discovery (today's behavior). The structural index is a coverage HINT only.
      • Context Injection (
        kb_references
        ):
        For each investigation you plan, you must determine which files in the
        workspace/kb/
        directory (e.g.,
        workspace/kb/entities/auth_module.md
        or
        workspace/kb/vulnerabilities/CWE-79.md
        ) provide necessary context for the researcher. Include the exact file paths to these markdown files in the
        "kb_references"
        array for that investigation. This shifts the burden of context-gathering off the researcher.
      • Exploratory/Unconstrained Investigations (Moderate Probability): With a moderate probability (e.g., a 25-50% chance per planning pass), include either an unconstrained adversarial sweep or a random exploration in the plan:
        1. Adversarial Sweep: Select a component or directory that the threat model currently marks as safe, low-risk, or out of scope. Instruct the researcher to perform an unconstrained sweep, ignoring safety assumptions in
          workspace/kb/THREAT_MODEL.md
          .
        2. Random Digging: Select a random starting position (file or directory) in the codebase. The question for this investigation should be minimal and open-ended, simply instructing the researcher to "dig into" or "explore" the selected area without specific threat-model context or pre-defined vulnerability classes. Set
          kb_references
          to an empty list for this investigation to ensure a fresh look.
        Token Optimization: Whether using a script (Mode A) or your file-writing tools (Mode B), write the plan directly to disk and do not print the JSON contents in your chat response.
  3. Schema Enforcement: Regardless of the mode, the final
    workspace/plan.json
    file written to disk should match the following schema to ensure downstream auditing agents can parse it correctly:
LOCATOR RESOLUTION (读取任何目标代码或工件之前执行):
0. 角色:如果此技能从不读取目标源代码(报告、校准、反思),则属于仅处理发现的阶段:跳过步骤2-6;仍需从状态中读取active_snapshot以进行来源/注释;切勿仅因代码根目录未设置而停止。
1. 按以下优先级确定CODE_ROOT:
   a. 如果本次调用传入了--target_root,则CODE_ROOT = --target_root。它具有权威性,会覆盖SNAPSHOT_ROOT和状态回退值(当调用者提供预先生成的树时使用,例如已修补的影子树)。
   b. 否则如果传入了--snapshot_root(或SNAPSHOT_ROOT),则使用该值。
   c. 否则读取state_root/workspace/.mantis_state.json(如果传入了--state_root则使用该路径下的state_root,否则使用当前目录下的./workspace/...)-> active_snapshot.root / .snapshot_id / .snapshot_pinned。
   d. 否则(无参数且无可用的active_snapshot):CODE_ROOT = 当前目录,将snapshot_pinned视为false(MODE-OFF)。请勿停止。
2. 标记检查(仅当snapshot_pinned为true且未选择路径1a时执行):
   验证CODE_ROOT/.mantis_snapshot_id是否存在且等于SNAPSHOT_ID。如果缺失或不匹配 -> 停止并提示"snapshot sentinel mismatch"。(--target_root树(1a)是故意修改的,不受标记检查限制。)
3. 路径字段:
   - 快照相对路径(在CODE_ROOT下读取):code_paths条目;plan中的target_files为文件路径。仅去除末尾的":<数字>"。包含"://"的code_paths条目是URL/端点,而非文件读取。非<现有路径>:<整数>格式的code_paths条目是非源定位器(符号/偏移量/端点):仅检查工件/符号是否存在;跳过所有行范围和行存在性逻辑。
   - 状态相对路径(在state_root/workspace下读写,切勿以CODE_ROOT作为前缀):kb_references、repro_file_path、reattack_file_path、辅助脚本、报告文件以及所有状态/发现JSON。
4. 当snapshot_pinned为true时,切勿在CODE_ROOT下写入内容。任何编译、生成或写入工件的命令必须在PRIVATE SHADOW副本(从CODE_ROOT创建的mktemp -d)中运行,切勿将工作目录设置为CODE_ROOT。只读检查可以进入CODE_ROOT目录。
5. 版本控制系统元数据例外:历史日志提取和任何VCS差异/追溯命令在LIVE仓库根目录(仍包含.git/.hg/.repo)中运行,而非CODE_ROOT(快照副本会剥离VCS元数据)。切勿仅因CODE_ROOT缺少.git/.hg/.repo而停止。
6. 每个shell命令都使用绝对路径,并在调用时设置自己的工作目录。切勿假设工作目录在调用之间保持不变。
[!NOTE] 当前轮次检查(防御性;绑定保证基于
mantis-pipeline-adapter
场景2):
如果存在
active_snapshot
active_snapshot.pass != state.pass_number
,则将该快照视为当前轮次的过期快照 —— 停止并提示"stale active_snapshot: pass mismatch"或降级为HALT(snapshot_pinned实际为false:无权威结论,Block B不匹配,reproduce标记为
not_attempted
)。这用于捕获自定义工具在Stage 15轮次递增时保留
active_snapshot
但未重新固定的情况。参考元代理每次轮次都会重新固定,因此此检查不会触发。Block B本身无法检测到这一点(它仅识别
snapshot_id
,不感知
pass
)。
策略生成器的技能特定说明:
  • 在Mode A中,计划是代码读取阶段(它会爬取生产目录);仅处理发现的跳过规则不适用。
  • Mode A爬取和每个
    target_files
    路径均为快照相对路径:在CODE_ROOT下爬取和解析它们。
  • workspace/kb/
    workspace/plan.json
    workspace/.mantis_state.json
    workspace/archive/
    workspace/findings/
    均为状态相对路径:在--state_root下读写,切勿在CODE_ROOT下操作。
  • 切勿在CODE_ROOT下写入、编译或生成内容(Block A步骤4)。计划脚本仅写入workspace/plan.json(状态相对路径)。Block E中的VCS差异在LIVE仓库根目录中运行(Block A步骤5例外),而非CODE_ROOT。
分析仓库结构并创建详细的防御安全评审计划,避免重复之前的工作,同时深入挖掘复杂的过程间路径和未扫描的代码边界。
目标无关性指令: 你评估的目标可能是原始源代码、编译后的二进制文件、固件 blob 或实时预发布/开发端点。根据目标当前的格式制定计划。你有权并被鼓励使用任何合适的工具(例如标准Unix工具、
unblob
radare2
angr
objdump
Ghidra
qemu
unicorn
)来探索工件结构。如果源代码不可用,请勿尝试强制使用源代码工作流(例如搜索
.c
.py
文件);调整方法并“采用适合工件的方式”。
按以下步骤执行规划阶段:
  1. 检查威胁模型上下文: 检查知识库目录中是否存在
    workspace/kb/THREAT_MODEL.md
    文件。如果存在,完整读取该文件以了解程序的官方安全边界、威胁参与者、资产、高风险接口和可信输入。
  2. 确定模式并获取历史经验: 检查是否存在知识库索引
    workspace/kb/index.md
    • MODE A:首次全面扫描模式(未找到
      workspace/kb/index.md
      ):
      如果是首次运行,确保覆盖整个代码库。为避免大型仓库的输出令牌限制,请勿在文本响应中手动生成
      workspace/plan.json
      。相反,执行shell命令运行你偏好语言编写的简短脚本,该脚本需完成以下操作:
      1. 使用
        find
        os.walk
        爬取所有生产目录。如果目录中存在
        mantis-summary.md
        文件,使用其内容了解目录结构,而非读取每个单独的源文件。否则,爬取所有生产源代码文件(例如
        .c
        .cpp
        .py
        .js
        .go
        .rs
        .java
        )。
      2. 忽略测试文件夹、构建工件和供应商依赖(例如
        node_modules
        .git
        tests/
        )。
      3. 以编程方式将列表格式化为
        workspace/plan.json
        架构,并直接写入磁盘。由于这是自动化脚本,指示它为
        "question"
        字段使用通用的基线问题(例如"针对内存安全和逻辑缺陷进行基线审计"),将高度上下文相关的自定义问题留到Mode B中使用。
    • MODE B:策略性经验复用模式(存在
      workspace/kb/index.md
      ):
      读取
      workspace/kb/index.md
      workspace/kb/THREAT_MODEL.md
      以回顾代码库的复合历史知识,包括信任边界、漏洞类别和架构组件。调整重点,为有漏洞历史的组件和文件设计新的针对性深度检查和回归评审。在此模式下,你可以使用文件写入工具手动生成
      workspace/plan.json
      ,因为范围会窄得多。
      • 针对性重新评估与重试: 查阅KB索引、实体文件和重现尝试缓存文件(如果存在
        workspace/archive/.repro_attempts.json
        )。你必须确定需要重新评估或重试的发现:
        同时从
        workspace/.mantis_state.json
        中读取快照上下文:
        active_snapshot.{snapshot_id, snapshot_pinned}
        snapshot_history
        (均由元代理写入)。然后通过在LIVE仓库根目录中运行以下Block E(根据Block A步骤5的版本控制系统元数据例外——固定的--snapshot_root会剥离.git/.hg/.repo,因此差异必须针对实时树运行),计算当前轮次的
        changed_files
        /
        changed_files_status
        。将计算得到的
        changed_files
        (仓库相对路径数组)和
        changed_files_status
        COMPUTED
        UNKNOWN
        )写回
        workspace/.mantis_state.json
        ,然后在后续阶段中使用它们。同时写入
        changed_files_pass
        = 状态中的当前
        pass_number
        ,以便使用者可以检测到过期(前一轮次)的差异。使用以下方法了解自上一轮次以来哪些文件发生了变化:
        自上一轮次以来的变化:在LIVE仓库根目录(而非SNAPSHOT_ROOT)中运行。CUR = 当前提交/版本;PREV = 此轮次之前的snapshot_history条目。如果PREV缺失或vcs_type属于{none,unknown},或者prev或cur的SNAPSHOT_ID是content:/live:/+content_hash回退值,或者差异命令出错 -> changed_files_status = UNKNOWN。将每个文件视为已更改。切勿视为未更改。切勿遗漏。(注意:仅
        snapshot_pinned false
        不会触发UNKNOWN——在HALT模式下,存在active_snapshot且snapshot_history有PREV条目,因此仍可运行差异。在MODE-OFF中——无active_snapshot——没有PREV条目,因此PREV缺失,差异降级为UNKNOWN,但这不会强制进行完整的Mode A爬取;请参阅下面的Mode A触发条件。)否则:git:
        git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR
        -M
        标志检测重命名;
        -C
        标志检测复制;
        --name-status
        输出重命名的
        R<score>\told_path\tnew_path
        ,以便同时显示旧路径和新路径;
        --diff-filter=RAMDCT
        包括重命名、添加、修改、删除、复制和类型更改的文件);hg:
        hg status -C --rev PREV:CUR
        -C
        /
        --copies
        在重命名/复制的情况下显示下一行的源路径;hg代码:A=添加,R=删除,M=修改);多版本控制系统:
        repo forall -c 'git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR'
        (任何错误 -> UNKNOWN)。如果发现的任何
        code_paths
        (路径部分)在集合中,或者其路径是重命名目标或重命名来源(解析
        R<score>\told\tnew
        行:旧路径和新路径均属于已更改集合),则该发现的文件已更改。如果发现的主文件显示为重命名来源(旧路径),则将新路径也视为已更改——漏洞可能随文件一起移动。
        在检查
        workspace/archive/.repro_attempts.json
        时,还需应用以下缓存读取规则。首先完全按照
        mantis-reproduce
        写入的方式选择缓存KEY:如果发现有
        signature
        字段,则KEY为该
        signature
        ;否则KEY为
        stable_key = normalized_title + "@" + primary_file_path
        (标题转换为小写并移除所有非字母数字字符;
        primary_file_path
        = 第一个
        code_paths
        条目,去除任何末尾的
        :line
        )。然后读取该KEY下的值V:如果V是整数,则count=V且last_snapshot=UNKNOWN;如果V是对象,则count=V.count且last_snapshot=V.last_snapshot(默认UNKNOWN)。如果在所选KEY下未找到条目,也尝试另一种KEY形式,然后再得出count=0的结论,这样使用signature作为KEY的写入者和使用stable_key的读取者不会错过彼此并错误地重置尝试预算。(在迁移期间,缓存混合了两种值形式和两种KEY样式。)
        1. 安排研究: 对于归档中标记为
          "NEEDS_RESEARCH"
          的发现,在
          workspace/plan.json
          中安排针对性调查(以收集缺失的上下文并将其解析为
          "VALID"
          "FALSE_POSITIVE"
          )。
        2. 复制以重试(受快照限制)或重新发现: 对于每个原本符合重试条件的归档发现(未尝试重现,或根据上述缓存读取规则
          failed_to_reproduce
          且尝试次数少于2次,或
          patch_status
          属于{
          VERIFICATION_FAILED
          ,
          ERROR
          ,
          VERIFICATION_INCOMPLETE
          }),运行:
          发现F的快照匹配检查(决定MATCHED vs NOT_MATCHED):
          1. 如果snapshot_pinned为false -> NOT_MATCHED。停止。
          2. 读取F.discovery_commit:
             - 缺失或为空或字面为"MIXED" -> NOT_MATCHED。
             - 与SNAPSHOT_ID不完全相等 -> NOT_MATCHED。
             - 与SNAPSHOT_ID完全相等 -> MATCHED。
          没有其他匹配途径;切勿进行模糊比较。全局"默认字段并继续"向后兼容规则不适用于discovery_commit:缺失=NOT_MATCHED。(没有单独的"脏"检查:脏树的SNAPSHOT_ID已嵌入工作树内容哈希,因此轮次内的发现匹配,跨轮次的裸提交发现不匹配。)
          然后按以下逻辑决定:
          • 原样复制(快速重试)仅当所有条件都满足:发现的Block B匹配,且其主文件(第一个
            code_paths
            ,去除行号)不在
            changed_files
            中,且该文件在CODE_ROOT下存在。将归档的
            <uuid>.json
            复制回
            workspace/findings/<uuid>.json
            ,保留UUID及其原始
            discovery_commit
            (请勿重新标记——必须可检测到偏移)。
          • MODE-OFF绕过(三态规则): 如果状态中不存在
            active_snapshot
            (MODE-OFF——未请求
            --sync
            ),则Block B始终返回NOT_MATCHED(
            snapshot_pinned is false -> NOT_MATCHED
            ),因此上述原样复制条件永远不会触发,每个符合重试条件的发现都会被重新发现——这与当前行为相比是一种回归(当前,轮次≥2时,当文件仍然存在时会保留未更改的发现)。在MODE-OFF中,当发现的主文件(第一个
            code_paths
            ,去除行号)在CODE_ROOT下存在时,原样复制(移除
            Block B MATCHED
            file NOT in changed_files
            条件——MODE-OFF中无论如何都没有
            changed_files
            差异)。这与
            mantis-patch
            的传统模式例外(
            patch:133-138
            patch:172-174
            )一致。请勿将绕过条件设置为
            snapshot_pinned==false
            ——这也会捕获HALT模式,在该模式下,过期标记合法地将发现标记为需要重新验证。仅当
            active_snapshot
            缺失时才启用绕过。(请勿更改Block B本身——根据
            README_AGENTS.md:711-718
            的块保真警告,它在所有技能中完全相同;修复应在计划的Block B使用者中进行,而非Block B本身。)
          • 重新发现在其他所有情况下(Block B不匹配,或文件在
            changed_files
            中,或文件缺失,或
            changed_files_status
            ==UNKNOWN):请勿复制回来。相反,在
            workspace/plan.json
            中添加新的调查,嵌入发现的
            title
            description
            repro_hints
            ,将
            target_files
            设置为旧code_paths的目录子树加上针对发现的函数/结构体/标题术语的仓库范围符号/关键字搜索(以便重新找到已移动/重命名的漏洞),并要求研究人员在当前快照上重新推导确切的行号。此外,在归档发现上记录历史注释
            unconfirmed-regression-pending
            ,以便在轮次重新发现或人工驳回之前不会被静默丢弃。
          • 行/AST重新锚定(阶段2增量效率): 在回退到完全重新发现之前,尝试使用正向行跟踪(反向追溯或差异块偏移)将发现的行号重新锚定到当前快照。这是一种优化:如果发现的主函数/符号仍在附近存在,重新锚定会生成行号提示,聚焦重新发现调查——但不能替代重新验证(快照已更改,因此发现仍需在下游重新研究)。
            • 方法: 将发现的旧行从PREV转换到CUR(请勿单独追溯PREV——这会返回PREV时的行,不会向前映射)。在LIVE仓库根目录中运行(Block A步骤5例外):git:
              git blame --reverse <PREV>..<CUR> -L <old_line>,<old_line> -- <file>
              (反向追溯将行向前跟踪到CUR),或从
              git diff <PREV> <CUR> -- <file>
              中添加块偏移到
              <old_line>
              。然后在CODE_ROOT(当前固定快照)中读取映射的行,并确认发现的主函数/符号在±50行内存在。这只会生成候选新行号——仅作为重新发现的搜索提示,永远不是可信的重新验证。
            • 重新锚定成功时(在映射行找到符号):使用新行号聚焦此发现的重新发现调查(首先将研究人员指向映射的
              code_paths
              位置)。请勿将发现转换为原样复制,也请勿跳过重新验证:Block B不匹配,因此发现仍需在下游重新研究/重现(映射行处的符号可能存在但已修复)。保持
              discovery_commit
              signature
              lineage_id
              不变;添加历史注释
              re-anchored: <old_line> -> <new_line> (search hint)
            • 重新锚定失败时(函数已删除、未找到符号、差异过大、追溯错误或旧行的代码完全不同):回退到上述完全重新发现。这是保守的防护措施:任何不确定情况下,重新发现。
            • 切勿使用重新锚定来抑制或丢弃发现。 它纯粹是行号更新的快速路径;如果失败,发现仍会通过正常路径重新发现。
            • 与版本控制系统无关: 对于hg,比较
              PREV:CUR
              的差异(
              hg diff --rev PREV:CUR -- <file>
              )并将块偏移应用于
              <old_line>
              以获得正向映射的行。对于无版本控制系统/二进制目标,重新锚定不适用;始终回退到重新发现。
          • 永远不要复制回来状态为
            "FALSE_POSITIVE"
            ,或
            patch_status
            "VERIFIED_SECURE"
            ,或
            repro_status
            "reproduced"
            (除非上述补丁失败),或在当前快照中已达到2次尝试上限的发现。但如果此类发现的文件在
            changed_files
            中或Block B不匹配,则将其视为可能的回归:重新发现(不要信任针对已更改代码的旧最终结论)。MODE-OFF例外: 如果状态中不存在
            active_snapshot
            (MODE-OFF),则删除上述
            or Block B is NOT_MATCHED
            条件——在MODE-OFF中,Block B对每个发现都返回NOT_MATCHED(无快照的产物,而非漂移信号),因此保留该条件会在每次轮次重新打开所有最终结论(FALSE_POSITIVE/VERIFIED_SECURE/reproduced)。在MODE-OFF中,仅依赖
            file IS in changed_files
            (在MODE-OFF中这是空值——没有
            changed_files
            差异),因此最终发现会保持不变。这是当前行为。
      • 已更改/新增攻击面覆盖(必填):
        changed_files
        中的每个路径添加标题为
        Exhaustive Review: <path>
        的调查(无论是否映射到归档发现)。如果
        changed_files_status
        ==UNKNOWN且存在
        active_snapshot
        (HALT或PINNED模式——当前轮次请求了同步),或当前轮次发生了同步(
        snapshot_id
        与上一个
        snapshot_history
        条目的id不同),则无法信任窄范围集合:即使存在
        kb/index.md
        ,也回退到当前轮次的完整Mode A全面爬取(这是捕获新增文件的唯一方法)。然而,在MODE-OFF中(无
        active_snapshot
        ——未请求
        --sync
        ),即使
        changed_files_status
        ==UNKNOWN,也不要在轮次≥2时强制进行完整的Mode A爬取:这是当前的默认行为,在每个MODE-OFF轮次≥2时强制Mode A会导致回归。在MODE-OFF中,依赖现有的
        kb/index.md
        (Mode B)进行范围缩小,与当前行为一致。
      • 依赖感知扩展(阶段2增量效率):
        changed_files_status
        已知(非UNKNOWN)且存在依赖图时,将调查范围扩展到已更改文件本身之外。目标:识别导入或依赖已更改文件的文件,以便规划者可以为已更改代码的使用者安排针对性调查(而非仅针对已更改代码本身)。
        • 方法: 以文件级依赖图(
          workspace/kb/dependencies.json
          或实体关系markdown)为必填基础:对于每个已更改文件F,找到所有直接或间接导入F的文件(最多2跳)。将这些依赖文件添加到调查范围中,作为
          Exhaustive Review: <dependent_file>
          条目。然后添加结构索引调用者:在可用时使用查询辅助工具(
          workspace/helpers/query_structural_index.py
          )实现函数级精度——调用
          resolve_symbol()
          获取已更改文件的导出函数,然后调用
          find_callers()
          枚举符号级依赖者。安排对依赖图找到的依赖者和结构索引找到的调用者的并集进行调查——它们是互补的,而非替代的。如果结构索引缺失(无
          manifest.json
          )、为空或查询辅助工具缺失,则仅依赖依赖图。
        • 使用时机: 仅当
          changed_files_status
          已知且KB包含依赖信息时使用。如果KB缺少导入/构建图,或KB已过期(检查
          workspace/.mantis_state.json
          中的
          kb_snapshot_id
          SNAPSHOT_ID
          ——如果不同,则KB是针对不同快照构建的,可能已过期),则回退到阶段1行为(完整Mode A爬取或Mode B范围缩小)。
        • 防护措施: 如果依赖图不完整、过期或出现任何不确定性,则回退到阶段1重新发现(将所有文件视为可能受影响)。切勿使用依赖范围缩小来放弃调查——它只能为依赖文件添加针对性调查。已更改文件本身始终会被调查。
        • 与版本控制系统无关: 依赖图源自KB的架构分析,而非版本控制系统元数据。它适用于KB已索引的任何具有导入/包含/使用语句的语言。
      • 结构索引查询(仅提示增强): 当存在结构索引(
        workspace/kb/structural_index/manifest.json
        存在)时,使用它补充上述依赖感知扩展,实现精确的符号级调用者发现。结构索引决定调查优先级顺序,而非审核集合的成员资格。
        • 解析优先协议(必填): 在查询调用者之前,解析符号:
          python3 workspace/helpers/query_structural_index.py resolve_symbol --name "<function_name>" [--language "<lang>"] [--file "<path>"] --state_root <state_root>
          如果响应中
          ambiguous: true
          ,请勿静默选择一个匹配项。使用
          --file
          /
          --language
          缩小范围,或为所有匹配的符号安排调查。
        • 受限调用者查询: 解析后,使用明确限制查询调用者:
          python3 workspace/helpers/query_structural_index.py find_callers --symbol_id "<resolved_id>" --limit 100 --offset 0 --state_root <state_root>
          如果
          has_more
          为true,使用
          --offset
          分页。
        • 覆盖感知解释: 检查每个结构索引响应中的
          coverage.partition_status
          • complete
            +
            precision == semantic
            + 无调用者 = "无索引调用者"——分区已使用语义后端完全索引,因此空结果对已索引代码具有权威性。仍需根据仅提示规则运行grep(grep捕获基于宏的调用、函数指针和动态调度)。
          • complete
            +
            precision != semantic
            + 无调用者 = "无索引调用者"——分区已完成但精度低于语义,因此空结果不具有权威性。必须运行全面grep回退。
          • partial
            /
            empty
            /
            failed
            + 无调用者 = "未完全索引"——分区未完成,因此扩展调查范围并必须运行全面grep回退。
        • 防护措施:
          • 仅提示:结构索引结果决定顺序,而非成员资格。它们优先确定先调查哪些依赖文件;绝不能导致文件从审核范围中被排除。
          • 每个结果都包含
            precision
            backend
            字段——使用
            precision
            semantic
            >
            typecheck
            >
            ast
            >
            symbol-only
            >
            heuristic
            >
            deferred
            >
            coverage-only
            )权衡对结果的信任度。
          • 如果结构索引缺失(无
            manifest.json
            )、为空或查询辅助工具缺失:回退到基于grep的发现(当前行为)。结构索引仅作为覆盖提示。
      • 上下文注入(
        kb_references
        ):
        对于你计划的每个调查,必须确定
        workspace/kb/
        目录中的哪些文件(例如
        workspace/kb/entities/auth_module.md
        workspace/kb/vulnerabilities/CWE-79.md
        )为研究人员提供必要的上下文。在该调查的
        "kb_references"
        数组中包含这些markdown文件的确切路径。这将上下文收集的负担从研究人员转移出去。
      • 探索性/无约束调查(中等概率): 在每次规划轮次中,以中等概率(例如25-50%的几率)在计划中包含无约束对抗扫描或随机探索:
        1. 对抗扫描: 选择威胁模型当前标记为安全、低风险或超出范围的组件或目录。指示研究人员执行无约束扫描,忽略
          workspace/kb/THREAT_MODEL.md
          中的安全假设。
        2. 随机挖掘: 在代码库中选择随机起始位置(文件或目录)。此调查的问题应尽量简洁开放,仅指示研究人员“深入研究”或“探索”所选区域,无需特定威胁模型上下文或预定义漏洞类别。将此调查的
          kb_references
          设置为空列表,以确保全新视角。
        令牌优化: 无论使用脚本(Mode A)还是文件写入工具(Mode B),都直接将计划写入磁盘,不要在聊天响应中打印JSON内容。
  3. 架构强制执行: 无论使用哪种模式,写入磁盘的最终
    workspace/plan.json
    文件都应符合以下架构,以确保下游审计代理可以正确解析:

Plan Schema Format

计划架构格式

json
{
  "investigations": [
    {
      "title": "Exhaustive Review: [relative_file_path]",
      "target_files": ["[relative_file_path_1]", "[relative_file_path_2]"],
      "kb_references": ["workspace/kb/entities/auth_module.md", "workspace/kb/vulnerabilities/CWE-79.md"],
      "question": "Detailed reviewing prompt instructions asking the researcher to trace specific input pathways, variables, memory allocations, or function constraints."
    }
  ]
}
Ensure
workspace/plan.json
is successfully written. When you have finished, notify the user.
json
{
  "investigations": [
    {
      "title": "Exhaustive Review: [relative_file_path]",
      "target_files": ["[relative_file_path_1]", "[relative_file_path_2]"],
      "kb_references": ["workspace/kb/entities/auth_module.md", "workspace/kb/vulnerabilities/CWE-79.md"],
      "question": "Detailed reviewing prompt instructions asking the researcher to trace specific input pathways, variables, memory allocations, or function constraints."
    }
  ]
}
确保
workspace/plan.json
已成功写入。完成后,通知用户。