Skip to content

Commit 0196fe9

Browse files
committed
Add conformance-scenario table to pipeline-adapter
Six edge-case scenarios (colocated state, stale active_snapshot, pin failure, patched shadows, cross-pass duplicates, absent sink evidence) with an INV-1..6 invariant legend, quick-reference table, and per-scenario prose. Also restores a deleted contract bullet and removes underscore thematic-break corruption. TAG=agy CONV=aab01c59-a0bc-4e12-b8d8-07a15022423a Change-Id: I42cf3d49fab2f317027a1c59de9deab5de6f632d
1 parent ea655bd commit 0196fe9

1 file changed

Lines changed: 112 additions & 12 deletions

File tree

‎mantis-pipeline-adapter/SKILL.md‎

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ Follow these guidelines during the consultation:
8484
`--snapshot_root`/`--snapshot_id` normally; Block A (Locator Resolution) is
8585
universal across all code-reading stages.
8686

87-
---
88-
8987
## Reference Architecture Guidelines
9088

9189
Use the following guidelines as your technical reference when advising the user.
@@ -179,8 +177,6 @@ graph TD
179177
Ref -.-> ModelB
180178
```
181179

182-
---
183-
184180
### 1. UUID-Based Referencing Pattern
185181

186182
To prevent the LLM from repeating large blocks of text (which increases latency,
@@ -236,8 +232,6 @@ them back, use the following pattern:
236232
- **Harness Action (Deterministic):** Programmatically update the
237233
`workspace/findings/<UUID>.json` file with the validation status and reason.
238234

239-
---
240-
241235
### 2. Adaptable Reproducers via Custom MCP
242236

243237
When validating findings, the agent may need to interact with diverse
@@ -255,8 +249,6 @@ to expose a clean, restricted API.
255249
manually register these tools in the API's schema format and handle
256250
dispatching tool calls to the MCP server.
257251

258-
---
259-
260252
### 3. Decomposition & Multi-Model Strategy
261253

262254
#### A. Pipeline Decomposition & Concurrency
@@ -289,8 +281,6 @@ Emphasize that using cheaper models for utility stages (like deduplication or
289281
calibration) must be validated with empirical evaluations against a benchmark
290282
dataset to ensure quality is not degraded.
291283

292-
---
293-
294284
### 4. The Planning Stage and workspace/plan.json
295285

296286
The planning stage plays a critical role in structuring the security campaign.
@@ -302,8 +292,6 @@ structured contract, the orchestrator can easily direct subagents, parallelize
302292
sweeps, and maintain historical context across pipeline runs without repeating
303293
work.
304294

305-
---
306-
307295
### 5. The Pass Lifecycle Contract (Living / Synced Codebases)
308296

309297
A custom orchestrator (a bespoke CLI, an ADK agent, an MCP-native pipeline, or
@@ -371,3 +359,115 @@ PIN step and passes `--snapshot_root`/ `--snapshot_id` normally; Block A
371359
read `active_snapshot` for provenance/annotation. When the harness archives
372360
and increments, retried findings must keep their **original**
373361
`discovery_commit`.
362+
363+
#### Conformance scenarios
364+
365+
The scenarios below expose nearly every issue in the snapshot model. They are
366+
**reference checks**, not features: the harness is responsible for preventing or
367+
handling each one in its own environment. The table is a quick-reference; prose
368+
detail follows for each scenario. The **State** column uses the 3-STATE RULE
369+
(MODE-OFF / HALT / PINNED, branched on `active_snapshot` presence — see the
370+
global backward-compat rule in [schema.json](../schema.json) and the advisory
371+
notes above); `SNAPSHOT_ID` formats follow the ladder in the advisory notes
372+
above (e.g. `live:<ts>` signals an unpinned/HALT pass).
373+
374+
**Invariant legend** (the labels below name safety properties enforced by the
375+
blocks and the global backward-compat rule in [schema.json](../schema.json)):
376+
377+
| Label | Property | Enforced by |
378+
| ----- | ------------------------------ | --------------------------------------------- |
379+
| INV-1 | No false `VERIFIED_SECURE` | Block G + HALT ceiling |
380+
| INV-2 | No false `failed_to_reproduce` | Block F + HALT ceiling |
381+
| INV-3 | No dropped regression | Block B NOT_MATCHED + POSSIBLE REGRESSION |
382+
| INV-4 | Within-pass consistency | Block A sentinel + single pinned snapshot |
383+
| INV-5 | No user data loss | Block C non-destructive sync + Block A step 4 |
384+
| INV-6 | Fail-safe on missing data | Global backward-compat rule |
385+
386+
**Quick-reference table:**
387+
388+
| # | Scenario | State | Harness behavior | Stage behavior | Block / INV | Key fields |
389+
| --- | --------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------- |
390+
| 1 | Colocated state | PINNED | Relocate `state_root` outside `CODE_ROOT`; `SNAPSHOT_ROOT` path must not contain `/workspace/` | `mantis-patch` state-vs-code guard misfires; Block A step 3 confuses SNAPSHOT- vs STATE-relative paths | A:3, D:3; INV-5 | `active_snapshot.root`, `snapshot_root`, `state_root` |
391+
| 2 | Stale active_snapshot | PINNED → STOP | Block D step 0: if `snapshot_pinned=true` but dir missing → STOP, yield to user | Block A step 2 sentinel mismatch → STOP; Block B NOT_MATCHED | A:2, D:0, B; INV-4, INV-6 | `active_snapshot.{root, snapshot_id, snapshot_pinned}`, `discovery_commit` |
392+
| 3 | Pin failure | HALT | Block D step 2/4: skip copy on ENOSPC/error → step 5b; still write `active_snapshot` + pass roots | Authoritative verdicts forbidden; Block B always NOT_MATCHED; reproduce `not_attempted`; patch `VERIFICATION_INCOMPLETE` | D:2, D:4, D:5b; INV-1, INV-2, INV-6 | `active_snapshot.{snapshot_id, snapshot_pinned}` |
393+
| 4 | Patched shadows | PINNED (pass); `--snapshot_pinned=false` arg | Pass `--target_root=<PATCHED_SHADOW_ROOT>` + `--snapshot_pinned=false` to reattack sub-agent | Block A step 1a: `CODE_ROOT=--target_root` (authoritative); step 2 sentinel SKIPPED (sentinel-EXEMPT) | A:1a, A:2; INV-4 | `target_root`, `snapshot_pinned` (arg), `snapshot_root`, `discovery_commit` |
394+
| 5 | Different-snapshot duplicate candidates | PINNED | No special action — both passes pinned correctly; dedupe handles it | Block B pairwise: `discovery_commit` differs → NOT_MATCHED → keep ACTIVE + `possible_duplicate_of`; POSSIBLE REGRESSION if archived was RESOLVED | B; INV-3, INV-6 | `discovery_commit`, `possible_duplicate_of`, `status`, `patch_status` |
395+
| 6 | Absent sink evidence | Any | No special action — Block F is a stage-level mechanical gate | Block F: evidence absent (build error, exit 127, sink unreached) → `not_attempted` (retry-eligible), NEVER `failed_to_reproduce`; HALT ceiling additionally forces `not_attempted` | F; INV-2, INV-6 | `repro_status`, `reattack_status`, `repro_hints` |
396+
397+
**Per-scenario detail:**
398+
399+
**1. Colocated state** (`state_root` nested inside `CODE_ROOT` / snapshot root)
400+
— The pinned `SNAPSHOT_ROOT` must live under
401+
`<state_root>/.mantis_snapshots/pass_<N>` (or a clean-VCS worktree/archive), and
402+
its path **must not** contain the segment `/workspace/` — otherwise
403+
`mantis-patch`'s state-vs-code path guard misfires (state files appear to be
404+
"under `CODE_ROOT`"). If `state_root` itself is inside `CODE_ROOT`, the harness
405+
must relocate it outside the snapshot before pinning. Block A step 3
406+
distinguishes SNAPSHOT-RELATIVE path fields (read under `CODE_ROOT`) from
407+
STATE-RELATIVE fields (read under `state_root/workspace`, never prefixed with
408+
`CODE_ROOT`); colocation breaks this separation.
409+
410+
**2. Stale active_snapshot** (`active_snapshot` points at a snapshot from a
411+
prior pass that no longer exists or doesn't match the current tree) — Block D
412+
step 0 (crash-resume): if `snapshot_pinned` was `true` but the dir is now
413+
missing → STOP and yield to the user (never re-pin to a possibly-drifted live
414+
tree). Block A step 2 sentinel check: verify `CODE_ROOT/.mantis_snapshot_id`
415+
exists and equals `SNAPSHOT_ID`; missing or different → STOP "snapshot sentinel
416+
mismatch". Block B returns NOT_MATCHED because the finding's `discovery_commit`
417+
won't match the stale `SNAPSHOT_ID`.
418+
419+
**3. Pin failure** (snapshot copy fails — disk full, permissions, too-large
420+
tree) — Block D step 2 (free-space precheck): compare `du -s` of the live tree
421+
to `df` free space at `state_root`; if it won't fit → skip copy → step 5b. Block
422+
D step 4 (failure-tolerant verify): check copy exit status + sanity check (file
423+
count/size within ~90%); on failure → step 5b (unpinned/HALT). Step 5b:
424+
`SNAPSHOT_ROOT=<live root>`, `snapshot_pinned=false`,
425+
`SNAPSHOT_ID="live:"+ISO8601`. The harness still writes `active_snapshot` and
426+
still passes `--snapshot_root`/`--snapshot_id` to stages so they see the HALT
427+
signal. Every stage then degrades conservatively: authoritative verdicts
428+
forbidden (`VERIFIED_SECURE`, `failed_to_reproduce`, `DUPLICATE`,
429+
`FALSE_POSITIVE`, `NON_VIABLE`); Block B always returns NOT_MATCHED; reproduce
430+
records `not_attempted`; patch's best attainable is `VERIFICATION_INCOMPLETE`.
431+
432+
**4. Patched shadows** (`--target_root` pointing at a pre-mutated tree;
433+
sentinel-exempt path 1a in Block A) — `mantis-patch` passes
434+
`--target_root=<PATCHED_SHADOW_ROOT>` and `--snapshot_pinned=false` to the
435+
reproduce sub-agent for re-attack verification. Block A step 1a:
436+
`CODE_ROOT = --target_root` (authoritative override, overrides `--snapshot_root`
437+
and state fallback). Block A step 2: sentinel check SKIPPED (a `--target_root`
438+
tree is deliberately mutated and is sentinel-EXEMPT). The
439+
`--snapshot_pinned=false` argument is the sentinel-exemption, NOT a HALT signal
440+
— detect HALT by reading STATE (`active_snapshot.snapshot_id` starts with
441+
`live:`, equivalently `active_snapshot.snapshot_pinned` is `false` in state),
442+
never from the argument passed on this invocation. The finding's
443+
`discovery_commit` is unaffected — it retains the pass-level `SNAPSHOT_ID` from
444+
when it was discovered; only the `--snapshot_pinned=false` argument is local to
445+
the reattack invocation.
446+
447+
**5. Different-snapshot duplicate candidates** (cross-pass dedupe where
448+
`discovery_commit` differs — the pairwise Block B NOT_MATCHED path) — Both
449+
passes pinned correctly; the findings simply come from different snapshots.
450+
`mantis-dedupe` Block B pairwise check compares the CURRENT finding's
451+
`discovery_commit` against the ARCHIVED finding's `discovery_commit` (NOT
452+
against the global `SNAPSHOT_ID`). If they differ → NOT_MATCHED. NOT_MATCHED
453+
keeps the current finding ACTIVE and sets `possible_duplicate_of` (a soft,
454+
non-terminal hint — the finding is NOT filtered or trashed). If the archived
455+
finding was RESOLVED (`patch_status` in {`VERIFIED_SECURE`,
456+
`MITIGATION_PROPOSED`} OR `status`==`FALSE_POSITIVE` OR
457+
`production_viability`==`NON_VIABLE`) AND the pair is NOT_MATCHED → POSSIBLE
458+
REGRESSION: keep ACTIVE, add a history note, never filter (a reverted fix
459+
re-discovered on new code must never be trashed).
460+
461+
**6. Absent sink evidence** (Block F — PoC compiles but produces no reached-sink
462+
evidence; `not_attempted` vs `failed_to_reproduce`) — `mantis-reproduce` Block
463+
F: if EVIDENCE is ABSENT (any compiler/build nonzero exit, exit 127
464+
command-not-found, exit 2 "No such file", or the sink was never reached) →
465+
`repro_status = not_attempted` (retry-eligible), STOP. NEVER
466+
`failed_to_reproduce`. In `--reattack` mode: leave `reattack_status` UNSET with
467+
a history note "setup_failed" — NEVER `failed_to_bypass`. `failed_to_reproduce`
468+
is reserved for when the harness PROVABLY reached the vulnerable entrypoint but
469+
the bug did not fire. Evidence is recorded in `repro_hints` (sidecar file
470+
containing `MANTIS_REACHED_ENTRYPOINT`, or crash backtrace/ASan naming the
471+
sink). In HALT mode, the HALT ceiling additionally forces `not_attempted` (no
472+
`failed_to_reproduce`), since a negative result on an unpinned tree cannot be
473+
trusted as authoritative.

0 commit comments

Comments
 (0)