Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
9e8c48c
feat(benchmark): size --workers from the machine and flag dropped LLM…
will-exaforce Oct 26, 2026
c3cc13f
docs(exaforce): record why upstream 2.13.1 upgrades are on hold
will-exaforce Oct 26, 2026
e3434f8
feat(benchmark): persist finding tags and run config
will-exaforce Nov 2, 2026
81690bf
docs: recall improvement program spec and plans P0-P7
will-exaforce Nov 2, 2026
04c3f72
feat(benchmark): scan an explicit unit list with --units-file
will-exaforce Nov 2, 2026
47cdc4e
feat(benchmark): health gate for poisoned or degraded runs
will-exaforce Nov 2, 2026
f29f3f5
feat(benchmark): replay scoring policies over stored findings
will-exaforce Nov 2, 2026
d4888e2
feat(benchmark): derive SkillHarm injected files
will-exaforce Nov 2, 2026
4c2a59f
fix(benchmark): attribute new PDFs in redirect_to_new_pdf fallbacks
will-exaforce Nov 2, 2026
669930d
feat(benchmark): report health, STB split, validity tiers, attribution
will-exaforce Nov 2, 2026
ee46dbf
feat(benchmark): same-day arm comparison with pre-registered verdicts
will-exaforce Nov 2, 2026
ccf30f1
feat(benchmark): deterministic evaluation sets
will-exaforce Nov 2, 2026
6134a95
fix(benchmark): refuse resuming a run under different flags
will-exaforce Nov 2, 2026
c3e415a
fix(benchmark): align replay doc cap with P1 semantics
will-exaforce Nov 2, 2026
503b024
feat(benchmark): show run provenance in arms
will-exaforce Nov 2, 2026
51354d3
fix(benchmark): add TP/TN/precision to splits table
will-exaforce Nov 2, 2026
68cdaee
chore(benchmark): ignore duckdb WAL files
will-exaforce Nov 2, 2026
1db355d
fix(benchmark): store out-of-range issue line numbers as NULL
will-exaforce Nov 2, 2026
e2023f4
fix(benchmark): record each scan result atomically
will-exaforce Nov 2, 2026
be5bb79
docs(benchmark): baseline-v2 run and P0 overview
will-exaforce Nov 2, 2026
4b40778
docs(benchmark): P1 offline policy selection
will-exaforce Nov 2, 2026
89959bf
feat(exaforce): patchlib helper that intercepts call arguments
will-exaforce Nov 2, 2026
a749728
feat(exaforce): flag-gated semantic block gate and doc-finding cap
will-exaforce Nov 2, 2026
760e96d
docs(benchmark): P1 dev arms
will-exaforce Nov 2, 2026
11c8a0b
docs(benchmark): P1 overview
will-exaforce Nov 2, 2026
9cbd855
docs(benchmark): P1 verdict sensitivity and handoffs
will-exaforce Nov 2, 2026
debc284
test(benchmark): close replay parity blind spots
will-exaforce Nov 2, 2026
0def329
test(exaforce): pin the llm-unconfirmed tag
will-exaforce Nov 2, 2026
ead32f4
feat(exaforce): stdlib PDF/OOXML text extractor with hidden-text dete…
will-exaforce Nov 2, 2026
7bca8f5
fix(exaforce): bound PDF/OOXML parsing time and honour text matrix
will-exaforce Nov 2, 2026
6dc92e6
feat(exaforce): flag-gated extracted text for PDF/office files
will-exaforce Nov 2, 2026
3312516
feat(exaforce): analyzer registry and hidden-text rules EXA-HT1..3
will-exaforce Nov 2, 2026
e5de1bf
fix(exaforce): linear HT3 scan and comment-aware fences
will-exaforce Nov 2, 2026
25e5baf
docs(benchmark): P2 evalsets and partial dev arms (incomplete)
will-exaforce Nov 3, 2026
434e229
feat(exaforce): skill reference detection and instruction bundle
will-exaforce Nov 3, 2026
17b4068
fix(exaforce): reject parent-directory prefix in skill path references
will-exaforce Nov 3, 2026
5439b4e
feat(exaforce): flag-gated skill-context header for referenced files
will-exaforce Nov 3, 2026
d22fc89
feat(exaforce): flag-gated per-skill instruction-flow analyzer EXA-IF1
will-exaforce Nov 3, 2026
0c580f3
feat(exaforce): revise instruction-flow prompt from B1 dev errors (P3…
will-exaforce Nov 3, 2026
ad52aec
docs(benchmark): P3 dev arms
will-exaforce Nov 3, 2026
d6bc6b1
docs(benchmark): P3 overview
will-exaforce Nov 3, 2026
c65f3fb
fix(exaforce): lock skill-context header map across analyzer threads
will-exaforce Nov 3, 2026
5a5082d
perf(exaforce): linear SKILL.md truncation and single bundle build
will-exaforce Nov 3, 2026
f4f65f3
revert(exaforce): restore B1 instruction-flow prompt (P3 B3 rejected)
will-exaforce Nov 3, 2026
aa84e08
docs(benchmark): P3 final-review corrections
will-exaforce Nov 3, 2026
1b950d7
revert(exaforce): roll back P3 skill-context and instruction-flow code
will-exaforce Nov 4, 2026
80daf70
feat(exaforce): flag-gated SSD-5 necessity category
will-exaforce Nov 4, 2026
e320a72
feat(exaforce): flag-gated per-skill necessity analyzer EXA-NE1
will-exaforce Nov 4, 2026
6d093d7
fix(exaforce): drop dataset-skewed word from necessity prompt
will-exaforce Nov 4, 2026
8fbdfa8
feat(benchmark): arms accepts multi-run replicates (a+b)
will-exaforce Nov 4, 2026
dd69e34
feat(benchmark): screen command for sequential futility screening
will-exaforce Nov 4, 2026
065bd3a
docs: pre-register sequential futility screen and adopt it in P4-P7
will-exaforce Nov 4, 2026
0e8b3cd
fix(benchmark): screen persists run ids, handles signals, sturdier tests
will-exaforce Nov 4, 2026
c8c2a91
docs: clarify screen control replicates and validation limits
will-exaforce Nov 4, 2026
5580e7a
docs: remove duplicated spec sections from screen validation fix
will-exaforce Nov 4, 2026
422a489
feat(benchmark): verdict-targeted screen rule (v2) and pooled union h…
will-exaforce Nov 4, 2026
80891a8
docs: amend screen pre-registration to v2 with validation
will-exaforce Nov 4, 2026
2eea2ea
fix(benchmark): screen v2 checks control replicates, FP clause off on…
will-exaforce Nov 4, 2026
71c440f
docs: screen v2 evidence and floors-mode wording
will-exaforce Nov 4, 2026
ff6a41e
docs: screen-first candidate wording in P4/P5/P7; add sequential scre…
will-exaforce Nov 4, 2026
6825fa3
feat(exaforce): revise necessity prompt from B dev errors (P4 B-rev)
will-exaforce Nov 4, 2026
75f9f82
fix(exaforce): narrow necessity prompt exclusions (P4 B-rev)
will-exaforce Nov 4, 2026
23951f4
docs(benchmark): P4 dev arms
will-exaforce Nov 4, 2026
4bf5a48
docs(benchmark): P4 overview
will-exaforce Nov 4, 2026
384992f
docs(benchmark): P4 final-review fixes
will-exaforce Nov 4, 2026
b935482
revert(exaforce): roll back P4 SSD-5 and necessity analyzer code
will-exaforce Nov 4, 2026
553b7d0
feat(benchmark): rulelab offline rule prototyping; P5 lure candidates
will-exaforce Nov 4, 2026
067cdd0
docs: P5 replay precision bar and 10% health threshold (user decisions)
will-exaforce Nov 4, 2026
29929aa
feat(benchmark): rulelab replay precision bar (P5 amendment)
will-exaforce Nov 4, 2026
256b294
feat(benchmark): health dropped-call threshold 10% (spec amendment)
will-exaforce Nov 4, 2026
7d196c5
feat(exaforce): flag-gated lure rules EXA-LU*
will-exaforce Nov 4, 2026
a6f05b4
docs(benchmark): P5 dev arms
will-exaforce Nov 4, 2026
5369ec5
docs(benchmark): P5 overview
will-exaforce Nov 4, 2026
21e3720
docs: P5 acceptance judged on rule-affected units (user decision)
will-exaforce Nov 4, 2026
f8ed943
fix(exaforce): bound lure regex gaps (final review I1, M1)
will-exaforce Nov 4, 2026
3433ba9
fix(exaforce): window long lines instead of skipping them (final revi…
will-exaforce Nov 4, 2026
8ab36a8
fix(exaforce): exact positions and bounded chains for windowed lure m…
will-exaforce Nov 4, 2026
45fb951
feat(exaforce): enable lure rules by default (P5 accepted)
will-exaforce Nov 4, 2026
c0e4cca
docs(benchmark): P5 overview
will-exaforce Nov 4, 2026
568d284
docs(benchmark): P6 paired threshold sweep
will-exaforce Nov 5, 2026
0b018c6
feat(exaforce): flag-gated block threshold
will-exaforce Nov 5, 2026
4e6863d
feat(exaforce): block threshold 49 by default (P6 accepted)
will-exaforce Nov 5, 2026
f52d23a
docs(benchmark): P6 overview
will-exaforce Nov 5, 2026
33271de
fix(exaforce): clamp score at the block threshold so CLI and MCP agre…
will-exaforce Nov 5, 2026
3f0de98
docs(benchmark): P6 overview after the final-review fix wave
will-exaforce Nov 5, 2026
910859e
docs: P7 candidate models pre-registered (user decision)
will-exaforce Nov 5, 2026
c6fa968
docs(benchmark): P7 model probe
will-exaforce Nov 5, 2026
79176a3
fix(benchmark): store a non-string issue explanation as JSON instead …
will-exaforce Nov 5, 2026
9428f3f
docs(benchmark): P7 dev arms
will-exaforce Nov 5, 2026
2ca0528
docs(benchmark): P7 overview and recall program summary
will-exaforce Nov 5, 2026
9270dad
docs(benchmark): P7 final-review fixes
will-exaforce Nov 5, 2026
0702a6d
docs(benchmark): P7 report, correct the B1 bound sentence (re-review)
will-exaforce Nov 5, 2026
cb417b5
revert(benchmark): roll back P7 model-split records
will-exaforce Nov 6, 2026
5a0bbb0
revert(exaforce): roll back P1 semantic gate and doc-MEDIUM cap
will-exaforce Nov 6, 2026
6803265
revert(exaforce): roll back P2 document text and hidden-text rules
will-exaforce Nov 6, 2026
543806e
docs(benchmark): consolidated write-up of the recall improvement prog…
will-exaforce Nov 6, 2026
525a426
fix(exaforce): block threshold defaults to upstream 51; P6's 49 is op…
will-exaforce Nov 6, 2026
08190ae
docs(benchmark): original run passes today's 10% health threshold
will-exaforce Nov 6, 2026
56da898
docs(benchmark): next lever #2 no longer proposes restoring P1's gate
will-exaforce Nov 6, 2026
f5e4112
docs(benchmark): rulelab's cut comment matches the 51 default
will-exaforce Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions benchmark/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
__pycache__/
# DuckDB result files written by the harness (benchmark_<id>.duckdb, -o targets).
*.duckdb
*.duckdb.wal
*.db
# Local report / stats output from the `report` command and ad-hoc runs.
*_report.md
Expand Down
92 changes: 90 additions & 2 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Or from inside this directory:
cd benchmark
uv run benchmark /path/to/MalSkillBench/Dataset
uv run benchmark .../Dataset/Prompts/indirect-injection -o out.duckdb
uv run benchmark .../Dataset/Skills/malware --limit 50 --workers 8
uv run benchmark .../Dataset/Skills/malware --limit 50 --workers 16
uv run benchmark .../Dataset --no-llm # static analysis only
```

Expand Down Expand Up @@ -70,7 +70,7 @@ uv run remove-run results.duckdb ab12 9f3 c7 --yes # several at once, no promp
| `--no-llm` | static analysis only (no LLM calls) |
| `--categories` | comma-separated unit categories to scan; default `skill,code`. **Prompts are excluded by default** — they're raw prompt-injection samples, not the repo config files this tool classifies (PI embedded in a skill is still covered via the `skill` units). Pass `--categories skill,code,prompt` to include them. |
| `--limit N` | cap units **per group** — a unit's parent directory (e.g. `--limit 20` on `Dataset/Skills` keeps 20 from `Skills/malware` *and* 20 from `Skills/benign`); 0 = no cap |
| `--workers N` | concurrent scan processes (default 8) |
| `--workers N` | concurrent scan processes; default is sized from the machine (half the RAM at 256 MB per worker, 6 per CPU, capped at 96 -- 96 on a 48 GB / 16-core Mac). Measured steady-state on the same units: 32 workers ~2 units/s, 64 ~2.6-3.0, 96 ~3.7, 128 ~3.1 -- past ~96 Bedrock queues calls (p99 wait ~46s) and slow scans approach `--timeout`. If the run summary reports scans that **lost LLM calls**, the provider is throttling: lower it. |
| `--run-id` | extend an existing run instead of starting a new one (requires `-o`); re-scans only its unfinished units and appends into the same run |
| `--from-run` | re-scan the units of a previous run instead of a `DATASET_PATH` (requires `-o`; reads that run from the `-o` DB and appends a new run there). Omit the positional path. |
| `--failures-only` | with `--from-run`, re-scan only that run's **failed** units (FN, FP, timeouts, and errors) |
Expand All @@ -82,6 +82,10 @@ uv run remove-run results.duckdb ab12 9f3 c7 --yes # several at once, no promp
Every invocation is a **new run** by default (multiple runs coexist in one DB).
To extend an interrupted run, re-run with `--run-id <id>` (printed when the run
is created): already-classified units are skipped and only failures re-scanned.
The resume is refused when its `SKILLSPECTOR_EXA_*` flags, `SKILLSPECTOR_MODEL`,
`SKILLSPECTOR_PROVIDER`, `MODEL_OVERRIDE` or `--units-file` (path and sha256) differ from
what the run recorded in `runs.config_json`; re-export the same env and pass the same
`--units-file`. Runs recorded without `config_json` resume with a warning.

### Re-checking a previous run

Expand Down Expand Up @@ -147,6 +151,90 @@ CTE at the top to target a different run or span all of them.
| `13_label_coverage.sql` | How ground-truth labels were resolved (bounds trust in 03/05) |
| `14_top_rules.sql` | Which rules fire, on malicious vs benign (false-positive drivers) |

## Screening a candidate (`screen`)

`uv run screen` rejects a failing dev-arm candidate early. It splits a units file into stratified batches of about 150
units (no unit repeats; seed 29), scans one batch at a time with the `benchmark` command as a subprocess, pairs
treatment with same-day control on every unit judged so far, and applies the pre-registered futility boundary from the
spec (`docs/superpowers/specs/2026-10-29-recall-improvement-program.md`, "Sequential futility screen"). It stops only to
reject; it never accepts. A candidate that passes goes on to the standard dev verdict with `arms`.

The recall-kind rule (v2) projects the final dev verdict from the units judged so far. Per judged unit it takes
`dtp`, `dfp` and `g = dtp − 8·dfp` (treatment minus control mean), projects each dev-set total as `F = N·mean` with
`SD = sd·½·(sqrt(N(N−n)/n) + sqrt(N(N+n)/n))`, and after at least 3 batches stops when either the TP clause
`F_dtp + z·SD_dtp < 2·N_TP` holds, or both FP conditions `F_g + z·SD_g < 0` and `F_dfp − z·SD_dfp > N_FP` hold.
`N_TP`/`N_FP` are `arms`' noise floors over the reused control runs when `--control-runs` names at least 2 replicates
(TP/FP totals over the units file). Otherwise (per-batch control, or 1 control replicate) the screen runs in floors
mode: `N_TP = 3`, N_FP is unknown, and the FP clause is off, so only the TP clause can stop. The floor is conservative
for the TP clause only; a floor `N_FP = 2` would make FP stops too easy. Reuse 2 complete same-day control replicates
for recall screens. The `--kind fp` rule is unchanged: `D + z·SE < 0` on `d = 2·Δtp − Δfp`.

```bash
uv run screen /path/to/MalSkillBench/Dataset --db results/recall.duckdb \
--units-file results/evalsets/p4-dev.txt --ref-run <baseline run> --label p4-B \
--control-runs <c1>,<c2> --treatment-env SKILLSPECTOR_EXA_NECESSITY=on
```

Options:
- `--db`, `--units-file`, `--ref-run` (its `evaluation` rows give the strata), `--label` (names the screen dir and the
scans' descriptions): required.
- `--kind recall|fp` (default `recall`): `fp` uses the FP-reducing score, mirroring `arms --kind`.
- `--treatment-env K=V`, `--control-env K=V`: env for the scans (repeatable).
- `--control-runs`: reuse these same-day control runs (replicates by comma, unions by `+`) instead of scanning control
per batch. Each replicate, as the union of its members, must cover every unit of the units file, and its members
must not overlap; otherwise the screen refuses (in normal mode and with `--simulate`).
- `--batch-size` (150), `--seed` (29), `--z` (2.8), `--min-batches` (3): the pre-registered constants; do not tune.
- `--stall-seconds` (1200): a scan whose log has not grown for this long is killed (whole process group) and resumed
with `--run-id`, at most twice; then the screen stops with an error naming the run.
- `--auth-wait-seconds` (0): passed through to the scans. At 0 an SSO expiry aborts the scan (and so the screen)
instead of waiting for a re-login.
- Reused control runs that also hold units outside the units file are warned about: the screen proceeds, but `arms`
will refuse the printed line because the control and treatment unit sets differ.
- `--out-dir` (default `results/screens`): the screen writes to `<out-dir>/<label-slug>/`.

Outputs:
- A header line with the units, batches and constants; for `--kind recall` also `N_TP`, `N_FP` and their source
(`range over k reused control replicates`), or in floors mode `N_TP` with `floors: 1 control replicate` or
`floors: per-batch control` and `FP clause off: N_FP unknown`.
- After each batch, a table of the look. Recall kind: units scanned, units judged, errors excluded, dTP, dFP,
`F_dtp ± SD_dtp`, `F_dtp + z·SD_dtp` against `2·N_TP`, `F_g + z·SD_g` against 0, `F_dfp − z·SD_dfp` against
`N_FP` (in floors mode the two FP columns say `FP clause off`), and the stop (`FUTILE (TP)`, `FUTILE (FP)`,
`FUTILE (TP+FP)` or `no`). SDs and bounds are `n/a` below 2 judged units. FP kind: units scanned, judged, errors,
dTP, dFP, `D`, `SE`, `D + z·SE`, the boundary, and FUTILE or no.
- Files in the screen dir: `manifest.json` (batches, run ids, `n_tp`/`n_fp` (`n_fp` null in floors mode) and their
source, every look's fields, warnings, result), `batch-NN.txt` (each batch's units file), and the per-scan logs
`bNN-<arm>.log` (a resumed scan after a stall logs to `bNN-<arm>.retryN.log`). A screen refuses to reuse a dir that
already has `manifest.json`; pick another `--label` or `--out-dir`. There is no automatic resume.
- The last line is `SCREEN: FUTILE at batch k (m units)`, where m is the units scanned so far. On PASSED the last
two lines are `SCREEN: PASSED (n units)` and an `arms:` line with the `--control` and `--treatment` run ids to pass
to `arms`. The union of the batch runs is treatment replicate 1.
- Replicates after a PASSED screen:
- When control runs are reused, they are the control replicates (×2); only the treatment gets one more full
same-day run (screen union + T2).
- When control was scanned per batch, its union is control replicate 1; make one more full control run and one more
full treatment run the same day.
Then `arms` judges.
- Warnings (not refusals) when the control's date or git sha differs from the treatment's.

`--simulate` judges existing full runs without scanning: pass the treatment runs with `--treatment-runs` and the
control with `--control-runs`. It writes no files and runs no scans, so it is a safe way to check what the screen would
have done on past runs.

Notes:
- The DB must have no other writer during a screen. The scans hold the DuckDB write lock, and a concurrent writer makes
a batch scan fail or the screen's read-only open raise.
- `arms` checks a union replicate's health pooled over its member runs, as the one full run it stands in for: scans,
dropped calls and ERRORs summed, semantic issues counted over all members, the median run_time over the union, and
the LLM checks applied if any member used the LLM. Two ERROR units in one 150-unit batch fail only if the union as a
whole exceeds 1%. ERROR units can be re-scanned with `uv run benchmark … --units-file <batch file> --run-id <batch
run>`. Dropped-call scans cannot be repaired that way.

If a screen dies (SSO expiry, a third stall, a DB lock conflict, a closed terminal), there is no automatic resume. The
manifest holds each batch's run ids (the failing scan's id is recorded with `"incomplete": "<arm>"` when its log named
one). Finish a batch scan with `uv run benchmark … --units-file <screen dir>/batch-NN.txt --run-id <id>` (same env as the
screen's `--treatment-env`/`--control-env`), then either judge what exists with `--simulate`, or start a new screen
under a new `--label`.

## Comparing two runs (PR-ready report)

The `report` command compares two runs in a DB and emits a markdown summary —
Expand Down
Loading
Loading