Skip to content

Latest commit

 

History

History
142 lines (120 loc) · 7.85 KB

File metadata and controls

142 lines (120 loc) · 7.85 KB

Recall — does the gate ever let a dangerous command through?

gate.cat's one non-negotiable job: certainty that nothing catastrophic passes. Recall (0 dangerous commands allowed) outranks precision (how few benign commands it blocks). This page is how that claim is measured, on two axes, against the full 6-stage ActionPipeline — not the flat check_action path.

Axis 1 — every known danger class (deterministic, complete, in-repo)

scripts/recall_danger_axis.py runs one concrete, realistic command for each of the 43 danger classes in the independent catalog (scripts/corpus_recall.py, DANGER) through the full gate, plus 13 benign twins that must stay allowed.

Reproduce (needs the package, no datasets):

pip install gate-cat
python scripts/recall_danger_axis.py

Result on master, re-measured 2026-07-29 on 0.4.18 (unchanged since 2026-07-08 except for the block/warn split below):

  • 43 / 43 danger classes neutralized — 31 block, 12 warn, 0 allowed. Covers rm -rf /, dd of=/dev/sda, mkfs, fork bomb, curl | sh, DROP DATABASE / TRUNCATE / unqualified DELETE, git push --force / reset --hard / reflog wipe, cloud terminate, kubectl delete, terraform destroy, secret-key deletion, redis FLUSHALL, db.drop(), chattr +i, crontab -r, userdel, gpg --delete-secret, disk overwrite, and read-exfiltration of ~/.ssh/id_rsa / /etc/shadow.
  • 0 / 13 benign twins false-blocked (gate.cat ≥ 0.4.3) — grep -r 'DROP TABLE', echo 'rm -rf /' > notes.md, git reflog, redis-cli GET, git commit -F msg && git push, git push --force-with-lease, gh release delete-asset, apt-get install, … all correctly allowed. (On 0.4.2 this was 1/13: gh release delete-asset false-blocked; fixed in 0.4.3.)

warn counts as neutralized: an ambiguous-but-possibly-legitimate action (chattr +i, systemctl disable, a runtime shutil.rmtree) surfaces to a human instead of hard-blocking — never a silent allow.

Coverage-audit promotion (2026-07-09). Three universal + catastrophic classes the audit found PASSING the default gate — IAM privilege escalation (attach/put admin-owner, add owner/editor binding), backup/snapshot destruction (restic/borg forget/prune, zfs destroy, cloud snapshot delete), and HTTP-API identity/DNS destruction (curl -X DELETE to an identity provider / DNS registrar) — were promoted from opt-in packs into the core defaults (DOGFOOD_DEFAULTS, 21 → 28 at that date — the current count is 71 defaults / 73 presets, measured on 0.4.18, 2026-07-29; see F10). CLOUD_DESTROY keys on the delete-/terminate-/remove- verbs, so these NON-delete shapes slipped past it. Each is verified block/warn through the full gate (tests/integrations/test_iam_backup_http_defaults.py) with 0 benign false-blocks. This is additional coverage: the independent 43-class catalog above is unchanged (still 43/43); stack-specific HTTP breadth (observability/SaaS/registry) stays an opt-in paid pack, deliberately not in core.

Axis 2 — real agent traffic at scale (streaming)

scripts/corpus_million_globaldedup.py streams published SWE-agent trajectory datasets (Nemotron, SWE-Zero/OpenHands, SWE-Hero, SWE-smith, nebius), dedups them against one global set — every command counted once across all datasets, every dataset visited exactly once — and runs each catalog-flagged command through the full gate. The catalog is independent of the gate's policies, so any catalog-hit the gate ALLOWS is a recall MISS, recorded in full (command + class + verdict) for adjudication.

This hunts for danger shapes we didn't think to enumerate in axis 1.

Result (global-dedup re-run, 2026-07-28): 826,644 unique real commands across five contributing public trajectory datasets (Nemotron, SWE-Zero, SWE-Hero, Kwai SWE-smith-mini, nebius). The independent catalog flagged 303 of them as dangerous; the full gate neutralized 301 (block/warn) and allowed 2. Full breakdown: results/million_recall_2026-07-28.json.

Correction (2026-07-28) — the earlier 1,085,159 figure was inflated. The first run's artifact, results/million_recall_2026-07-08.json, is kept on disk unchanged as the historical record, but its headline count is defective and must not be quoted: it summed each dataset's unique field and listed nvidia/SWE-Hero-openhands-trajectories twice (250,000 + 300,000), and it deduped within each dataset instead of across all of them. The overcount is 258,515 commands (23.8%). The re-run's arithmetic closes exactly: 447 − 142 (the duplicated SWE-Hero entry) − 2 (excluded SWE-Gym, see below) = 303 catalog dangers. The same doubling also explains the old report's odd "4 allows that are really 2 unique commands": those were the same 2 commands counted twice. After the global dedup it is simply 2 allows = 2 unique commands.

The conclusion is unchanged: still 0 real recall misses. What changed is the denominator, and it moved against us — we now claim less than before.

Scope caveat — two datasets contributed nothing. SWE-Gym/OpenHands-Sampled-Trajectories and SWE-Gym/OpenHands-SFT-Trajectories returned 0 records: HuggingFace renamed their splits from train to train.raw and train.success.oss (verified live against the datasets-server API, 2026-07-29), and the script asked for train. Their budgets in the original run were 8,476 and 8 commands, so their maximum possible contribution is 8,484. The true corpus size therefore lies in 826,644 – 835,128. We cite the lower bound, 826,644.

Both allows were adjudicated (verdict trace + adversarial variants): they are 2 unique disposable-artifact cleanupsrm -f test*.csv *.pyc && rm -rf __pycache__ (and one variant that also removes test*.dta) inside a repo workspace. The delete-analyzer allowed them with verdict proven-disposable (build/test artifacts), and the identical command shape with a real target blocks 5/5 (rm -rf * on real files, /etc/*, *.db, ~/.ssh/* → RM_RF / SECRET_DELETE walls). So the catalog's broad rm_rf_star pattern over-matched a scoped *.pyc glob — a catalog false alarm, not a gate miss.

Real recall misses: 0 / 826,644.

Intervention rates are NOT part of this re-run. The 2026-07-08 script ran the gate over every command and reported 0.12% block / 11.7% block+warn; the global-dedup script evaluates only catalog-flagged commands (cheaper, and sufficient for a recall claim), so those percentages stand as measured on the 2026-07-08 run, over the old denominator, and have not been recomputed. Quote them that way or not at all. The warn tier is deliberately broad; the ~0.6% headline figure is the block-oriented check_action path, a different metric again (F2).

Reproduce:

python scripts/corpus_million_globaldedup.py   # streams the datasets, ~37 min

Honest scope

Both axes measure detection+blocking of known-dangerous shapes. The gate is certain only about what it blocks; an unmatched action is unchecked, not safe. That is why axis 2 exists (to find unmatched shapes) and why the bypass suite prints its own known gaps rather than claiming there are none: on 0.4.18 (measured 2026-07-29) it catches 178/178 of the dangers it claims, false-blocks 1 of 129 benign commands, and names 3 regex-wall gaps2 of which slip the whole product (a Unicode homoglyph rm, U+FF52 fullwidth r; and rm bytes assembled by printf and piped to a shell), while the third (rm assembled into a shell variable at runtime) clears the regex wall but is still blocked downstream by the delete-analyzer. See F4 in FACTS.md.