Reviewer (/mantis-review)
System Goal
Independent Validator. Reviews consolidated findings against active source code
to verify validity and filter out noise and false positives.
Command Definition
- Command:
/mantis-review
- Description: Independently reviews findings and filters out false
positives.
Input/Output Contract
- Reads:
workspace/findings/ (finding JSON files, including each finding's optional
discovery_commit provenance stamp).
workspace/.mantis_state.json (current loop pass_number; and, when
present, active_snapshot = {root, snapshot_id, snapshot_pinned} for
snapshot provenance).
- Invocation args when passed by the orchestrator:
--snapshot_root,
--snapshot_id, --state_root (and, rarely, --target_root).
- Target source code files at the
code_paths paths/lines, read under the
resolved CODE_ROOT (the pinned snapshot root — see Instructions Step 0 /
Block A), never the live tree when a snapshot is pinned.
- Writes:
- Updates findings on disk in-place (sets
"status", "reasoning",
"repro_hints", "triage_checklist", and appends history).
- Writes helper script
workspace/helpers/append_review.py.
- Preconditions:
workspace/findings/ exists with finding files.
- Target source code files exist.
- Idempotency Guarantee:
- Modifies finding files in-place using the helper script
append_review.py,
which MUST carry # MANTIS_HELPER_VERSION = 2 as its first line; regenerate
the helper if that marker is absent or a different integer (see Instructions
step 5).
- Idempotency key is (pass_number, snapshot). Before (re)writing a
finding, scan its
history array:
- SNAPSHOT MODE OFF (neither
--snapshot_id was passed NOR is
active_snapshot readable in state): SKIP the review update iff a
"stage": "reviewer" entry already exists for the current pass_number
(byte-for-byte today's behavior).
- SNAPSHOT MODE ON: SKIP the review update iff a
"stage": "reviewer"
entry exists whose pass_number equals the current pass AND whose
snapshot equals SNAPSHOT_ID. A reviewer entry that lacks snapshot
(legacy) or carries a different snapshot counts as UNKNOWN → RE-REVIEW
(do NOT skip), so a finding reviewed under the old skill is re-grounded
against the current pinned snapshot.
Instructions
Read and evaluate the deduplicated findings against the actual source code of
the repository. Assume every finding is a false positive by default. Your job
is to disprove the finding using an adversarial stance. Evaluate the claim based
ONLY on the code and the raw claim itself. Explicitly ignore the original
finder's prose reasoning and justification, as they may be hallucinated.
Execute your validation as follows:
Step 0 — Locator Resolution & Snapshot Provenance Gate (do this FIRST, before
reading any finding's code):
0a. Resolve where to read code. Block A — Locator Resolution here:
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.
The reviewer READS target source, so it is NOT a findings-only stage: run all of
Block A steps 1-6. CODE_ROOT is the pinned snapshot root you will read every
code_paths entry under. Per Block A step 3, a code_paths entry containing
:// is a URL (existence check only), and any entry not of the form
<existing-path>:<integer> is a non-source locator (check the artifact/symbol
exists; skip all line-existence logic). Never STOP merely because CODE_ROOT
lacks .git/.hg (Block A step 5).
[!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).
0b. Determine SNAPSHOT MODE (once, before touching findings): - SNAPSHOT
MODE is OFF iff --snapshot_id was NOT passed on this invocation AND
workspace/.mantis_state.json has no readable active_snapshot. This is a
legacy / non-sync run: do NOT run the Snapshot Provenance Gate below; review
EVERY finding with steps 1-5 exactly as before. - Otherwise SNAPSHOT MODE is
ON. From Block A you now hold SNAPSHOT_ID and snapshot_pinned. Apply the
Snapshot Provenance Gate (0c) to every finding.
0c. Snapshot Provenance Gate (SNAPSHOT MODE ON only). After Step 1 loads the
findings, apply the match check to EACH finding F via Block B — Snapshot Match
Check, applied to F:
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, using the idempotency rule (Input/Output Contract → Idempotency Guarantee)
to avoid double-writes:
- MATCHED → F is grounded in the current pinned snapshot. Proceed to steps
2-5 (the full 13-rule review) for F.
- NOT_MATCHED (includes:
snapshot_pinned false / HALT / live-endpoint
pass; discovery_commit missing, empty, or the literal MIXED; or
discovery_commit != SNAPSHOT_ID) → F was discovered against a different (or
absent/unpinned) snapshot; its code_paths line numbers may no longer point
at the same code. DO NOT run the 13 rules on F. DO NOT mark it
FALSE_POSITIVE. Finalize F as a drift NEEDS_RESEARCH via the helper (step
5), writing EXACTLY:
"status": "NEEDS_RESEARCH"
"reasoning":
"Snapshot drift: finding discovered against snapshot <F.discovery_commit or 'unknown'>, which does not match the current pinned snapshot <SNAPSHOT_ID>. Not re-validated this pass; routed to re-research."
- omit
"repro_hints" (and, if F carried stale repro_hints from a prior
pass, leave them — they are ignored downstream because status is not
VALID/PROVISIONALLY_VALID).
"triage_checklist": all 13 constraints set to UNKNOWN (paste the object
below verbatim). This object is REQUIRED: appending a reviewer history
entry makes triage_checklist mandatory on a non-chain finding
(schema.json lines 365-398), and for a NEEDS_RESEARCH finding every
entry MUST avoid FAIL/passes:false (schema.json lines 418-470).
Setting ensure_source_code_coherence and
verify_attacker_control_of_source to UNKNOWN (never FAIL) is the whole
point: a line/path mismatch caused by DRIFT is NOT evidence of
hallucination, so Rules 12/13 must NOT fire on it.
- append the
reviewer "history" entry (with "snapshot", per step 5 / the
history JSON below). Then STOP processing F — skip steps 2-5 for it.
Drift triage_checklist (paste verbatim; all 13 keys, all UNKNOWN):
{
"ignore_hypothetical_misuse": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"ignore_missing_hygiene": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"require_strict_reproducibility": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"avoid_pedantic_linting": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"no_security_flaw_stretching": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"evaluate_questionable_file_paths": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"ignore_resource_exhaustion_dos": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"intrinsic_security_flaws": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"verify_mitigations_pragmatically": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"refine_code_paths_strictly": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"ignore_simd_vector_padding": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
"ensure_source_code_coherence": { "outcome": "UNKNOWN", "reason": "snapshot drift: line/path mismatch may be caused by drift, not hallucination; not re-validated" },
"verify_attacker_control_of_source": { "outcome": "UNKNOWN", "reason": "snapshot drift: trust-boundary path not re-traced against the current pinned snapshot" }
}
Findings finalized as drift NEEDS_RESEARCH in Step 0c are DONE — do not
process them again in steps 2-5. Only MATCHED findings (SNAPSHOT MODE ON) or all
findings (SNAPSHOT MODE OFF) flow into steps 2-5 below.
Load Clustered Findings: Read the JSON files in the workspace/findings/
directory. If the directory is empty or missing, notify the user.
Source Code Inspection: For each finding that reached this step (in
SNAPSHOT MODE ON, only findings that were MATCHED in Step 0c; findings
finalized there as drift NEEDS_RESEARCH are already done and are skipped),
read the file under CODE_ROOT (the pinned snapshot root resolved in
Step 0 / Block A — resolve every code_paths path relative to CODE_ROOT,
never the live tree) to inspect the exact files and line numbers listed in
code_paths and confirm the finding is grounded in the actual snapshot
state. Do not make assumptions about the validity of a path without
inspecting the source code first.
Strict Validation Filtering (Apply the 13 Negative Constraints): Evaluate
each finding against these strict criteria. Mark a finding as
FALSE_POSITIVE if it violates any of the following rules:
- Ignore Hypothetical Misuse: Do not flag security flaws that rely on a
calling API hypothetically misusing a function, writing bad fallback
logic, or sending invalid parameters if the function itself behaves
safely.
- Ignore Missing Hygiene / Defense-In-Depth: Do not report missing HTTP
security headers (e.g.,
X-Content-Type-Options), missing authentication
on local-only test functions, or hardcoded mock databases as security
flaws.
- Require Strict Reproducibility: Only mark a finding as VALID if a
direct, unambiguous, and triggerable flaw exists within the boundaries of
the code logic. If the finding is extremely fragile (e.g., relies on
unstable timing that cannot be automated or brute-forced, or requires
unrealistic environmental conditions to trigger), mark it as
FALSE_POSITIVE. Note on Race Conditions: Do NOT dismiss race conditions
or timing bugs simply because they have a low success probability (e.g.,
1 in a million), provided the attack path can be automated and repeatedly
attempted by an attacker to eventually trigger the exploit.
- Avoid Pedantic Linting: If the code uses standard safe libraries
(such as
json.loads, parameterised SQL queries, or secure standard
library hashes) but lacks extreme paranoia, mark it as FALSE_POSITIVE.
- No Security Flaw Stretching on Mitigations: If you are reviewing a
mitigation or a safe variant of a function that successfully blocks the
original security flaw class, do NOT invent complex protocol-level
bypasses or adjacent security flaw classes (e.g., SSRF when reviewing
Command Injection fixes). If the primary security flaw is successfully
blocked, mark it as FALSE_POSITIVE.
- Evaluate Questionable File Paths: Do NOT instantly dismiss a finding
simply because its path contains
/test, /experimental, or /mock.
Code in these paths is sometimes compiled into production targets or
reachable via production endpoints. Do not blindly assume it is safe;
instead, take reasonable measures to trace its usage to confirm whether
it is actually exposed in production.
- Ignore Resource Exhaustion DoS: Do not flag functions for lacking
recursion limits, input size boundaries, or cycle constraints unless the
primary stated purpose of the module is to defend against DoS attacks.
- Intrinsic Security Flaws: If a function uses a fundamentally broken
algorithm (such as MD5, SHA1), hardcodes static secrets, or contains
direct injection paths in its own logic, mark it as VALID even if it is
not currently called anywhere in the codebase.
- Verify Mitigations Pragmatically: Do not hallucinate flaws in active
mitigations. If the code adds trailing validation slashes or configures
safe parsing flags, accept that the mitigation works.
- Refine
code_paths Strictly: The code_paths field should only
include the exact filename:line_number of the flawed code block. Strip
out any helper files, test harnesses, or correct caller files from
code_paths.
- Ignore SIMD/Vector Padding Violations: If a finding represents an
out-of-bounds read or write inside optimized vector routines (e.g., NEON,
SSE, AVX, VSX), verify if the library employs a global memory allocation
contract (such as trailing safety padding, like
row_bytes + 16). If the
out-of-bounds access is mathematically guaranteed to reside entirely
within this pre-allocated padding buffer under all execution paths, mark
the finding as a FALSE_POSITIVE (By Design).
- Ensure Source Code Coherence (Anti-Hallucination): Verify that every
file path listed in
code_paths exists in the repository, and that
function names, variable names, or line numbers actually exist at those
locations. If references are missing or incorrect, immediately mark the
finding as a FALSE_POSITIVE to prevent downstream agents from wasting
resources on hallucinated bugs.
- Verify Attacker Control of the Source (Trust-Boundary Tracing):
Before marking a data-flow finding VALID, identify and cite the file:line
where untrusted data enters the analyzed codebase (the "Ingress Point")
from which the specific tainted field's value flows to the sink, OR where
that field is populated by an untrusted writer.
- If you have access to the untrusted-side code (e.g. Guest/Client in a
multi-component repo), cite the writer.
- If you only have access to the trusted-side code, cite the Host/Server
ingress point on the data-flow path (e.g., reads from shared memory,
IPC handlers, HTTP request parameter retrieval).
- If the source data is proven to originate solely from trusted-side
origins (server-authored static config, host-plane internal state),
mark FALSE_POSITIVE.
- Exception: Do not apply this rule to Intrinsic Security Flaws (Rule 08)
where the vulnerability exists in library code independent of active
callers.
Status Resolution:
- Mark as FALSE_POSITIVE if it violates any of the 13 rules above.
- Mark as VALID if it passes all rules and has a clear, triggerable
flaw.
- Mark as PROVISIONALLY_VALID if it passes the rules, but you are
uncertain of its feasibility without dynamic verification (e.g. requires
complex heap grooming or precise timing).
- Mark as NEEDS_RESEARCH if the review is inconclusive due to high
complexity, unresolved external APIs, or massive call graphs — OR because
the finding was NOT_MATCHED by the Step 0c Snapshot Provenance Gate
(snapshot drift). Drift findings are finalized in Step 0c and never reach
these 13 rules; do NOT re-classify a drift finding as
FALSE_POSITIVE.
- SCHEMA-CRITICAL:
FALSE_POSITIVE is the ONLY status for which a
triage_checklist entry may be "FAIL" (or "passes": false). For any
VALID, PROVISIONALLY_VALID, or NEEDS_RESEARCH finding, EVERY
checklist entry must be PASS / NOT_APPLICABLE / UNKNOWN — never
FAIL — or schema.json (lines 418-470) will reject the finding. If a
rule looks failed but you are NOT setting status to FALSE_POSITIVE
(e.g. Rule 12/13 references look off only because of snapshot drift), use
UNKNOWN with a reason, not FAIL.
Checklist Construction:
- Construct the
triage_checklist object evaluating all 13 negative
constraints. For each rule, set outcome to:
"PASS": if the finding satisfies the constraint (does not violate the
rule, meaning the bug remains potentially valid).
"FAIL": if the finding violates the rule. Setting ANY entry to
"FAIL" REQUIRES the finding's status to be FALSE_POSITIVE
(schema.json lines 418-470 reject FAIL on VALID/
PROVISIONALLY_VALID/NEEDS_RESEARCH). A FAIL entry also REQUIRES a
reason (schema.json lines 788-797).
"UNKNOWN": if the rule applicability is unresolved/needs research
(REQUIRES a reason). Use this — not "FAIL" — whenever the finding
is not being marked FALSE_POSITIVE, including all rules on a drift
NEEDS_RESEARCH finding (Step 0c).
"NOT_APPLICABLE": if this rule is entirely irrelevant to this class
of bug (REQUIRES a reason).
- Consistency rule: if
status is VALID, every entry must be PASS or
NOT_APPLICABLE (no UNKNOWN, no FAIL) per schema.json lines
471-507.
Construct Reproduction Script Hints: For every finding marked as
VALID or PROVISIONALLY_VALID, provide high-signal "repro_hints"
explaining how a reproducer agent can trigger the bug, what inputs or payload
parameters are required, and what crash condition, sanitizer trace
(ASan/UBSan/MSan/TSan), or functional validation result (e.g., an unexpected
HTTP 200 OK) is expected to confirm the security flaw.
Token-Optimized File Updates: To minimize LLM output tokens, do not
re-emit or manually rewrite the entire JSON object in your output. Instead,
write a reusable helper script (e.g., workspace/helpers/append_review.py)
during your first finding update. For all subsequent findings, do not
regenerate the script; simply execute the existing helper script with the new
parameters to append the required fields.
Helper version guard (mechanical): the helper's FIRST line MUST be the
comment # MANTIS_HELPER_VERSION = 2. Before reusing an existing
workspace/helpers/append_review.py, check that first line (a one-line
grep): if the marker is ABSENT or a DIFFERENT integer, REGENERATE the helper
(an old persisted helper would silently omit the snapshot provenance field
and mishandle the drift path). The regenerated helper MUST:
- accept parameters for
status, reasoning, optional repro_hints,
triage_checklist (JSON), pass_number, timestamp, and snapshot
(write it under key "snapshot", never "snapshot_id");
- write the reviewer
history entry INCLUDING "snapshot" (the current
SNAPSHOT_ID; omit or write "" only in SNAPSHOT MODE OFF, where no
snapshot is in play);
- enforce the (pass_number, snapshot) idempotency check (Idempotency
Guarantee): do nothing if a matching reviewer entry already exists.
You must append the following to the existing object:
A "status" field (one of "VALID", "FALSE_POSITIVE",
"PROVISIONALLY_VALID", or "NEEDS_RESEARCH").
A "reasoning" field.
A "repro_hints" field (optional for "NEEDS_RESEARCH" or
"FALSE_POSITIVE").
A "triage_checklist" object containing evaluations for all 13 negative
constraints (each key in the object maps to the constraint of the matching
name from Section 3 above):
{
"ignore_hypothetical_misuse": { "outcome": "PASS" },
"ignore_missing_hygiene": { "outcome": "PASS" },
"require_strict_reproducibility": { "outcome": "FAIL", "reason": "Requires unstable 1-in-a-million race condition that cannot be automated." },
"avoid_pedantic_linting": { "outcome": "PASS" },
"no_security_flaw_stretching": { "outcome": "PASS" },
"evaluate_questionable_file_paths": { "outcome": "PASS" },
"ignore_resource_exhaustion_dos": { "outcome": "PASS" },
"intrinsic_security_flaws": { "outcome": "PASS" },
"verify_mitigations_pragmatically": { "outcome": "PASS" },
"refine_code_paths_strictly": { "outcome": "PASS" },
"ignore_simd_vector_padding": { "outcome": "PASS" },
"ensure_source_code_coherence": { "outcome": "PASS" },
"verify_attacker_control_of_source": { "outcome": "PASS" }
}
For backward compatibility, the schema also permits "passes": <bool> as
an alternative to "outcome", but "outcome" is preferred. The reason
must be provided if the outcome is FAIL, UNKNOWN, or NOT_APPLICABLE
(or if passes is false) to explain the evaluation; it should be omitted
for PASS / true to save tokens.
An entry to the "history" array (now carrying the snapshot the review was
performed against, for (pass_number, snapshot) idempotency):
{
"stage": "reviewer",
"action": "reviewed",
"details": "Determined status as [VALID/FALSE_POSITIVE/PROVISIONALLY_VALID/NEEDS_RESEARCH] because [reason]",
"pass_number": <current_pass_number>,
"snapshot": "<SNAPSHOT_ID>",
"timestamp": "<current_iso8601_timestamp>"
}
In SNAPSHOT MODE OFF (no snapshot in play), set "snapshot": "" (or omit the
field). schema.json's history_entry has no additionalProperties:false,
so this extra field validates unchanged.
When complete, notify the user.
1---2name: mantis-review3description: Independently reviews findings and filters out false positives. Use when consolidated findings need validation against the actual source code. Don't use for reproducing crashes or patching code.4---5
6# Reviewer (/mantis-review)
7
8## System Goal
9
10Independent Validator. Reviews consolidated findings against active source code
11to verify validity and filter out noise and false positives.
12
13## Command Definition
14
15- **Command:** `/mantis-review`
16- **Description:** Independently reviews findings and filters out false
17 positives.
18
19## Input/Output Contract
20
21- **Reads**:
22 - `workspace/findings/` (finding JSON files, including each finding's optional
23 `discovery_commit` provenance stamp).
24 - `workspace/.mantis_state.json` (current loop `pass_number`; and, when
25 present, `active_snapshot` = `{root, snapshot_id, snapshot_pinned}` for
26 snapshot provenance).
27 - Invocation args when passed by the orchestrator: `--snapshot_root`,
28 `--snapshot_id`, `--state_root` (and, rarely, `--target_root`).
29 - Target source code files at the `code_paths` paths/lines, read under the
30 resolved `CODE_ROOT` (the pinned snapshot root — see Instructions Step 0 /
31 Block A), never the live tree when a snapshot is pinned.
32- **Writes**:
33 - Updates findings on disk in-place (sets `"status"`, `"reasoning"`,
34 `"repro_hints"`, `"triage_checklist"`, and appends history).
35 - Writes helper script `workspace/helpers/append_review.py`.
36- **Preconditions**:
37 - `workspace/findings/` exists with finding files.
38 - Target source code files exist.
39- **Idempotency Guarantee**:
40 - Modifies finding files in-place using the helper script `append_review.py`,
41 which MUST carry `# MANTIS_HELPER_VERSION = 2` as its first line; regenerate
42 the helper if that marker is absent or a different integer (see Instructions
43 step 5).
44 - Idempotency key is **(pass_number, snapshot)**. Before (re)writing a
45 finding, scan its `history` array:
46 - **SNAPSHOT MODE OFF** (neither `--snapshot_id` was passed NOR is
47 `active_snapshot` readable in state): SKIP the review update iff a
48 `"stage": "reviewer"` entry already exists for the current `pass_number`
49 (byte-for-byte today's behavior).
50 - **SNAPSHOT MODE ON**: SKIP the review update iff a `"stage": "reviewer"`
51 entry exists whose `pass_number` equals the current pass AND whose
52 `snapshot` equals `SNAPSHOT_ID`. A reviewer entry that lacks `snapshot`
53 (legacy) or carries a different `snapshot` counts as UNKNOWN → RE-REVIEW
54 (do NOT skip), so a finding reviewed under the old skill is re-grounded
55 against the current pinned snapshot.
56
57## Instructions
58
59Read and evaluate the deduplicated findings against the actual source code of
60the repository. **Assume every finding is a false positive by default. Your job
61is to disprove the finding using an adversarial stance. Evaluate the claim based
62ONLY on the code and the raw claim itself. Explicitly ignore the original
63finder's prose reasoning and justification, as they may be hallucinated.**
64
65Execute your validation as follows:
66
67**Step 0 — Locator Resolution & Snapshot Provenance Gate (do this FIRST, before
68reading any finding's code):**
69
700a. **Resolve where to read code.** **Block A — Locator Resolution** here:
71
72```
73LOCATOR RESOLUTION (before reading ANY target code or artifact):
740. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
75 you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
76 state for provenance/annotation; NEVER stop merely because a code root is unset.
771. Determine CODE_ROOT, in this priority order:
78 a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
79 It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
80 (used when a caller hands you a prepared tree, e.g. a patched shadow).
81 b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
82 c. Else read state_root/workspace/.mantis_state.json (state_root from
83 --state_root if passed, else ./workspace/... relative to the current dir)
84 -> active_snapshot.root / .snapshot_id / .snapshot_pinned.
85 d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
86 treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
872. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
88 verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
89 or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
90 deliberately mutated and is sentinel-EXEMPT.)
913. PATH FIELDS:
92 - SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
93 that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
94 containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
95 NOT of the form <existing-path>:<integer> is a non-source LOCATOR
96 (symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
97 line-range and line-existence logic.
98 - STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
99 kb_references, repro_file_path, reattack_file_path, helper scripts, report
100 files, and all state/findings JSON.
1014. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
102 compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
103 (mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
104 cd into CODE_ROOT.
1055. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
106 run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
107 (the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
108 lacks .git/.hg/.repo.
1096. Every shell command uses ABSOLUTE paths and sets its own working directory on
110 that call. Do NOT assume the working directory persists between calls.
111```
112
113The reviewer READS target source, so it is NOT a findings-only stage: run all of
114Block A steps 1-6. `CODE_ROOT` is the pinned snapshot root you will read every
115`code_paths` entry under. Per Block A step 3, a `code_paths` entry containing
116`://` is a URL (existence check only), and any entry not of the form
117`<existing-path>:<integer>` is a non-source locator (check the artifact/symbol
118exists; skip all line-existence logic). Never STOP merely because `CODE_ROOT`
119lacks `.git`/`.hg` (Block A step 5).
120
121> [!NOTE] **CURRENT-PASS CHECK (defensive; the binding guarantee is on the
122> harness per `mantis-pipeline-adapter` Scenario 2):** if `active_snapshot` is
123> present AND `active_snapshot.pass != state.pass_number`, treat the snapshot as
124> STALE for this pass — STOP "stale active_snapshot: pass mismatch" or degrade
125> as HALT (`snapshot_pinned` effectively false: no authoritative verdicts, Block
126> B NOT_MATCHED, reproduce `not_attempted`). This catches a custom harness that
127> preserved `active_snapshot` across the Stage 15 pass increment without
128> re-pinning. The reference meta-agent re-pins every pass, so this check never
129> fires there. Block B itself cannot detect this (it is `snapshot_id`-only, not
130> `pass`-aware).
131
1320b. **Determine SNAPSHOT MODE (once, before touching findings):** - SNAPSHOT
133MODE is **OFF** iff `--snapshot_id` was NOT passed on this invocation AND
134`workspace/.mantis_state.json` has no readable `active_snapshot`. This is a
135legacy / non-sync run: do NOT run the Snapshot Provenance Gate below; review
136EVERY finding with steps 1-5 exactly as before. - Otherwise SNAPSHOT MODE is
137**ON**. From Block A you now hold `SNAPSHOT_ID` and `snapshot_pinned`. Apply the
138Snapshot Provenance Gate (0c) to every finding.
139
1400c. **Snapshot Provenance Gate (SNAPSHOT MODE ON only).** After Step 1 loads the
141findings, apply the match check to EACH finding F via **Block B — Snapshot Match
142Check**, applied to F:
143
144```
145SNAPSHOT MATCH CHECK for finding F (decides MATCHED vs NOT_MATCHED):
1461. If snapshot_pinned is false -> NOT_MATCHED. Stop.
1472. Read F.discovery_commit:
148 - missing OR empty OR the literal "MIXED" -> NOT_MATCHED.
149 - not exactly equal to SNAPSHOT_ID -> NOT_MATCHED.
150 - exactly equal to SNAPSHOT_ID -> MATCHED.
151There is no other route to MATCHED; never fuzzy-compare. The global "default the
152field and proceed" backward-compat rule does NOT apply to discovery_commit:
153absent = NOT_MATCHED. (There is NO separate "dirty" gate: a dirty tree's
154SNAPSHOT_ID already embeds the working-tree content hash, so within-pass findings
155MATCH and cross-pass bare-commit findings do not.)
156```
157
158Then, using the idempotency rule (Input/Output Contract → Idempotency Guarantee)
159to avoid double-writes:
160
161- **MATCHED** → F is grounded in the current pinned snapshot. Proceed to steps
162 2-5 (the full 13-rule review) for F.
163- **NOT_MATCHED** (includes: `snapshot_pinned` false / HALT / live-endpoint
164 pass; `discovery_commit` missing, empty, or the literal `MIXED`; or
165 `discovery_commit != SNAPSHOT_ID`) → F was discovered against a different (or
166 absent/unpinned) snapshot; its `code_paths` line numbers may no longer point
167 at the same code. **DO NOT run the 13 rules on F. DO NOT mark it
168 FALSE_POSITIVE.** Finalize F as a drift `NEEDS_RESEARCH` via the helper (step
169 5), writing EXACTLY:
170 - `"status": "NEEDS_RESEARCH"`
171 - `"reasoning"`:
172 `"Snapshot drift: finding discovered against snapshot <F.discovery_commit or 'unknown'>, which does not match the current pinned snapshot <SNAPSHOT_ID>. Not re-validated this pass; routed to re-research."`
173 - omit `"repro_hints"` (and, if F carried stale `repro_hints` from a prior
174 pass, leave them — they are ignored downstream because status is not
175 VALID/PROVISIONALLY_VALID).
176 - `"triage_checklist"`: all 13 constraints set to `UNKNOWN` (paste the object
177 below verbatim). This object is REQUIRED: appending a `reviewer` history
178 entry makes `triage_checklist` mandatory on a non-chain finding
179 (`schema.json` lines 365-398), and for a `NEEDS_RESEARCH` finding every
180 entry MUST avoid `FAIL`/`passes:false` (`schema.json` lines 418-470).
181 Setting `ensure_source_code_coherence` and
182 `verify_attacker_control_of_source` to `UNKNOWN` (never `FAIL`) is the whole
183 point: a line/path mismatch caused by DRIFT is NOT evidence of
184 hallucination, so Rules 12/13 must NOT fire on it.
185 - append the `reviewer` `"history"` entry (with `"snapshot"`, per step 5 / the
186 history JSON below). Then STOP processing F — skip steps 2-5 for it.
187
188Drift `triage_checklist` (paste verbatim; all 13 keys, all `UNKNOWN`):
189
190```json
191{
192 "ignore_hypothetical_misuse": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
193 "ignore_missing_hygiene": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
194 "require_strict_reproducibility": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
195 "avoid_pedantic_linting": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
196 "no_security_flaw_stretching": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
197 "evaluate_questionable_file_paths": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
198 "ignore_resource_exhaustion_dos": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
199 "intrinsic_security_flaws": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
200 "verify_mitigations_pragmatically": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
201 "refine_code_paths_strictly": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
202 "ignore_simd_vector_padding": { "outcome": "UNKNOWN", "reason": "snapshot drift: not re-validated against the current pinned snapshot" },
203 "ensure_source_code_coherence": { "outcome": "UNKNOWN", "reason": "snapshot drift: line/path mismatch may be caused by drift, not hallucination; not re-validated" },
204 "verify_attacker_control_of_source": { "outcome": "UNKNOWN", "reason": "snapshot drift: trust-boundary path not re-traced against the current pinned snapshot" }
205}
206```
207
208Findings finalized as drift `NEEDS_RESEARCH` in Step 0c are DONE — do not
209process them again in steps 2-5. Only MATCHED findings (SNAPSHOT MODE ON) or all
210findings (SNAPSHOT MODE OFF) flow into steps 2-5 below.
211
2121. **Load Clustered Findings:** Read the JSON files in the `workspace/findings/`
213 directory. If the directory is empty or missing, notify the user.
214
2152. **Source Code Inspection:** For each finding that reached this step (in
216 SNAPSHOT MODE ON, only findings that were **MATCHED** in Step 0c; findings
217 finalized there as drift `NEEDS_RESEARCH` are already done and are skipped),
218 read the file **under `CODE_ROOT`** (the pinned snapshot root resolved in
219 Step 0 / Block A — resolve every `code_paths` path relative to `CODE_ROOT`,
220 never the live tree) to inspect the exact files and line numbers listed in
221 `code_paths` and confirm the finding is grounded in the actual snapshot
222 state. Do not make assumptions about the validity of a path without
223 inspecting the source code first.
224
2253. **Strict Validation Filtering (Apply the 13 Negative Constraints):** Evaluate
226 each finding against these strict criteria. Mark a finding as
227 **FALSE_POSITIVE** if it violates any of the following rules:
228
229 01. **Ignore Hypothetical Misuse:** Do not flag security flaws that rely on a
230 calling API hypothetically misusing a function, writing bad fallback
231 logic, or sending invalid parameters if the function itself behaves
232 safely.
233 02. **Ignore Missing Hygiene / Defense-In-Depth:** Do not report missing HTTP
234 security headers (e.g., `X-Content-Type-Options`), missing authentication
235 on local-only test functions, or hardcoded mock databases as security
236 flaws.
237 03. **Require Strict Reproducibility:** Only mark a finding as VALID if a
238 direct, unambiguous, and triggerable flaw exists within the boundaries of
239 the code logic. If the finding is extremely fragile (e.g., relies on
240 unstable timing that cannot be automated or brute-forced, or requires
241 unrealistic environmental conditions to trigger), mark it as
242 FALSE_POSITIVE. *Note on Race Conditions:* Do NOT dismiss race conditions
243 or timing bugs simply because they have a low success probability (e.g.,
244 1 in a million), provided the attack path can be automated and repeatedly
245 attempted by an attacker to eventually trigger the exploit.
246 04. **Avoid Pedantic Linting:** If the code uses standard safe libraries
247 (such as `json.loads`, parameterised SQL queries, or secure standard
248 library hashes) but lacks extreme paranoia, mark it as FALSE_POSITIVE.
249 05. **No Security Flaw Stretching on Mitigations:** If you are reviewing a
250 mitigation or a safe variant of a function that successfully blocks the
251 original security flaw class, do NOT invent complex protocol-level
252 bypasses or adjacent security flaw classes (e.g., SSRF when reviewing
253 Command Injection fixes). If the primary security flaw is successfully
254 blocked, mark it as FALSE_POSITIVE.
255 06. **Evaluate Questionable File Paths:** Do NOT instantly dismiss a finding
256 simply because its path contains `/test`, `/experimental`, or `/mock`.
257 Code in these paths is sometimes compiled into production targets or
258 reachable via production endpoints. Do not blindly assume it is safe;
259 instead, take reasonable measures to trace its usage to confirm whether
260 it is actually exposed in production.
261 07. **Ignore Resource Exhaustion DoS:** Do not flag functions for lacking
262 recursion limits, input size boundaries, or cycle constraints unless the
263 primary stated purpose of the module is to defend against DoS attacks.
264 08. **Intrinsic Security Flaws:** If a function uses a fundamentally broken
265 algorithm (such as MD5, SHA1), hardcodes static secrets, or contains
266 direct injection paths in its own logic, mark it as VALID even if it is
267 not currently called anywhere in the codebase.
268 09. **Verify Mitigations Pragmatically:** Do not hallucinate flaws in active
269 mitigations. If the code adds trailing validation slashes or configures
270 safe parsing flags, accept that the mitigation works.
271 10. **Refine `code_paths` Strictly:** The `code_paths` field should only
272 include the exact `filename:line_number` of the flawed code block. Strip
273 out any helper files, test harnesses, or correct caller files from
274 `code_paths`.
275 11. **Ignore SIMD/Vector Padding Violations:** If a finding represents an
276 out-of-bounds read or write inside optimized vector routines (e.g., NEON,
277 SSE, AVX, VSX), verify if the library employs a global memory allocation
278 contract (such as trailing safety padding, like `row_bytes + 16`). If the
279 out-of-bounds access is mathematically guaranteed to reside entirely
280 within this pre-allocated padding buffer under all execution paths, mark
281 the finding as a FALSE_POSITIVE (By Design).
282 12. **Ensure Source Code Coherence (Anti-Hallucination):** Verify that every
283 file path listed in `code_paths` exists in the repository, and that
284 function names, variable names, or line numbers actually exist at those
285 locations. If references are missing or incorrect, immediately mark the
286 finding as a FALSE_POSITIVE to prevent downstream agents from wasting
287 resources on hallucinated bugs.
288 13. **Verify Attacker Control of the Source (Trust-Boundary Tracing):**
289 Before marking a data-flow finding VALID, identify and cite the file:line
290 where untrusted data enters the analyzed codebase (the "Ingress Point")
291 from which the specific tainted field's value flows to the sink, OR where
292 that field is populated by an untrusted writer.
293 - If you have access to the untrusted-side code (e.g. Guest/Client in a
294 multi-component repo), cite the writer.
295 - If you only have access to the trusted-side code, cite the Host/Server
296 ingress point on the data-flow path (e.g., reads from shared memory,
297 IPC handlers, HTTP request parameter retrieval).
298 - If the source data is proven to originate solely from trusted-side
299 origins (server-authored static config, host-plane internal state),
300 mark FALSE_POSITIVE.
301 - Exception: Do not apply this rule to Intrinsic Security Flaws (Rule 08)
302 where the vulnerability exists in library code independent of active
303 callers.
304
305 - **Status Resolution:**
306
307 - Mark as **FALSE_POSITIVE** if it violates any of the 13 rules above.
308 - Mark as **VALID** if it passes all rules and has a clear, triggerable
309 flaw.
310 - Mark as **PROVISIONALLY_VALID** if it passes the rules, but you are
311 uncertain of its feasibility without dynamic verification (e.g. requires
312 complex heap grooming or precise timing).
313 - Mark as **NEEDS_RESEARCH** if the review is inconclusive due to high
314 complexity, unresolved external APIs, or massive call graphs — OR because
315 the finding was **NOT_MATCHED** by the Step 0c Snapshot Provenance Gate
316 (snapshot drift). Drift findings are finalized in Step 0c and never reach
317 these 13 rules; do NOT re-classify a drift finding as `FALSE_POSITIVE`.
318 - **SCHEMA-CRITICAL:** `FALSE_POSITIVE` is the ONLY status for which a
319 `triage_checklist` entry may be `"FAIL"` (or `"passes": false`). For any
320 `VALID`, `PROVISIONALLY_VALID`, or `NEEDS_RESEARCH` finding, EVERY
321 checklist entry must be `PASS` / `NOT_APPLICABLE` / `UNKNOWN` — never
322 `FAIL` — or `schema.json` (lines 418-470) will reject the finding. If a
323 rule looks failed but you are NOT setting status to `FALSE_POSITIVE`
324 (e.g. Rule 12/13 references look off only because of snapshot drift), use
325 `UNKNOWN` with a `reason`, not `FAIL`.
326
327 - **Checklist Construction:**
328
329 - Construct the `triage_checklist` object evaluating all 13 negative
330 constraints. For each rule, set `outcome` to:
331 - `"PASS"`: if the finding satisfies the constraint (does not violate the
332 rule, meaning the bug remains potentially valid).
333 - `"FAIL"`: if the finding violates the rule. Setting ANY entry to
334 `"FAIL"` REQUIRES the finding's `status` to be `FALSE_POSITIVE`
335 (`schema.json` lines 418-470 reject `FAIL` on `VALID`/
336 `PROVISIONALLY_VALID`/`NEEDS_RESEARCH`). A `FAIL` entry also REQUIRES a
337 `reason` (`schema.json` lines 788-797).
338 - `"UNKNOWN"`: if the rule applicability is unresolved/needs research
339 (REQUIRES a `reason`). Use this — not `"FAIL"` — whenever the finding
340 is not being marked `FALSE_POSITIVE`, including all rules on a drift
341 `NEEDS_RESEARCH` finding (Step 0c).
342 - `"NOT_APPLICABLE"`: if this rule is entirely irrelevant to this class
343 of bug (REQUIRES a `reason`).
344 - Consistency rule: if `status` is `VALID`, every entry must be `PASS` or
345 `NOT_APPLICABLE` (no `UNKNOWN`, no `FAIL`) per `schema.json` lines
346 471-507.
347
3484. **Construct Reproduction Script Hints:** For every finding marked as
349 **VALID** or **PROVISIONALLY_VALID**, provide high-signal `"repro_hints"`
350 explaining how a reproducer agent can trigger the bug, what inputs or payload
351 parameters are required, and what crash condition, sanitizer trace
352 (ASan/UBSan/MSan/TSan), or functional validation result (e.g., an unexpected
353 HTTP 200 OK) is expected to confirm the security flaw.
354
3555. **Token-Optimized File Updates:** To minimize LLM output tokens, **do not
356 re-emit or manually rewrite the entire JSON object in your output.** Instead,
357 write a reusable helper script (e.g., `workspace/helpers/append_review.py`)
358 during your first finding update. For all subsequent findings, do not
359 regenerate the script; simply execute the existing helper script with the new
360 parameters to append the required fields.
361
362 **Helper version guard (mechanical):** the helper's FIRST line MUST be the
363 comment `# MANTIS_HELPER_VERSION = 2`. Before reusing an existing
364 `workspace/helpers/append_review.py`, check that first line (a one-line
365 grep): if the marker is ABSENT or a DIFFERENT integer, REGENERATE the helper
366 (an old persisted helper would silently omit the `snapshot` provenance field
367 and mishandle the drift path). The regenerated helper MUST:
368
369 - accept parameters for `status`, `reasoning`, optional `repro_hints`,
370 `triage_checklist` (JSON), `pass_number`, `timestamp`, and `snapshot`
371 (write it under key `"snapshot"`, never `"snapshot_id"`);
372 - write the reviewer `history` entry INCLUDING `"snapshot"` (the current
373 `SNAPSHOT_ID`; omit or write `""` only in SNAPSHOT MODE OFF, where no
374 snapshot is in play);
375 - enforce the (pass_number, snapshot) idempotency check (Idempotency
376 Guarantee): do nothing if a matching reviewer entry already exists.
377
378 You must append the following to the existing object:
379
380 - A `"status"` field (one of `"VALID"`, `"FALSE_POSITIVE"`,
381 `"PROVISIONALLY_VALID"`, or `"NEEDS_RESEARCH"`).
382
383 - A `"reasoning"` field.
384
385 - A `"repro_hints"` field (optional for `"NEEDS_RESEARCH"` or
386 `"FALSE_POSITIVE"`).
387
388 - A `"triage_checklist"` object containing evaluations for all 13 negative
389 constraints (each key in the object maps to the constraint of the matching
390 name from Section 3 above):
391
392 ```json
393 {
394 "ignore_hypothetical_misuse": { "outcome": "PASS" },
395 "ignore_missing_hygiene": { "outcome": "PASS" },
396 "require_strict_reproducibility": { "outcome": "FAIL", "reason": "Requires unstable 1-in-a-million race condition that cannot be automated." },
397 "avoid_pedantic_linting": { "outcome": "PASS" },
398 "no_security_flaw_stretching": { "outcome": "PASS" },
399 "evaluate_questionable_file_paths": { "outcome": "PASS" },
400 "ignore_resource_exhaustion_dos": { "outcome": "PASS" },
401 "intrinsic_security_flaws": { "outcome": "PASS" },
402 "verify_mitigations_pragmatically": { "outcome": "PASS" },
403 "refine_code_paths_strictly": { "outcome": "PASS" },
404 "ignore_simd_vector_padding": { "outcome": "PASS" },
405 "ensure_source_code_coherence": { "outcome": "PASS" },
406 "verify_attacker_control_of_source": { "outcome": "PASS" }
407 }
408 ```
409
410 For backward compatibility, the schema also permits `"passes": <bool>` as
411 an alternative to `"outcome"`, but `"outcome"` is preferred. The `reason`
412 must be provided if the outcome is `FAIL`, `UNKNOWN`, or `NOT_APPLICABLE`
413 (or if `passes` is `false`) to explain the evaluation; it should be omitted
414 for `PASS` / `true` to save tokens.
415
416 - An entry to the `"history"` array (now carrying the snapshot the review was
417 performed against, for `(pass_number, snapshot)` idempotency):
418
419 ```json
420 {
421 "stage": "reviewer",
422 "action": "reviewed",
423 "details": "Determined status as [VALID/FALSE_POSITIVE/PROVISIONALLY_VALID/NEEDS_RESEARCH] because [reason]",
424 "pass_number": <current_pass_number>,
425 "snapshot": "<SNAPSHOT_ID>",
426 "timestamp": "<current_iso8601_timestamp>"
427 }
428 ```
429
430 In SNAPSHOT MODE OFF (no snapshot in play), set `"snapshot": ""` (or omit the
431 field). `schema.json`'s `history_entry` has no `additionalProperties:false`,
432 so this extra field validates unchanged.
433
434When complete, notify the user.