argotbenchmarks

Benchmarks

argot flags what a linter structurally can't: code that is valid, typed and lint-clean but doesn't fit this repo — the kind of thing an AI agent drags in. It has five distinct detectors: four get their own scorecard below, each with its own catch metric and its own false-alarm metric; the fifth catches an AI agent gaming a test to force a failing suite green, benchmarked separately (154/164 (93.9%) — detector-specific fixture catch; controls and accepted-history results are separate; accepted-history controls are reported separately below).

1 · Foreigngated

A dependency, API or runtime the repo has never used. The statistical voice model, learned from your git history.

2 · Reinventionrule redundant

A function that reimplements one you already have. The local code-embedding index.

3 · Misplacementrule misplaced

The right code filed in the wrong package — its nearest peers live elsewhere.

4 · Architecturerule layering

A module edge foreign to the repo's own layering — a reversed dependency, a cycle, or an edge out of a sink.

What the headline metric covers. All these detectors fire as ordinary rules — error severity by default (the check fails; test-weakened and the migration-awaresuperseded ship warn), each one configurable to warn oroff in [rules]. The headline catch/over-fire numbers argot is judged on cover detectors 1 & 4; detectors 2 & 3 are measured separately below, and the test-integrity group has its own separate benchmark — none of the three fold into the headline. Every catch number is held-out; every false-alarm number is a leak-free temporal holdout (fit at an old commit, replay only unseen commits). Higher catch, lower false-alarm.

1 · Foreign-pattern detection · the gate

The base voice model, learned entirely from your git history. It fires on two gated classes of 0-usage foreign pattern: a foreign import / dep(a package the repo never imports — the import stage catches it by construction; a foreign concurrency lib is just a dep and folds in here) and aforeign API / unfamiliar callee (a call into a foreign library that isn't an explicit import — the harder call-receiver stage). Catch isvisible (620/637 (97.3%) — detector-specific fixture recall; not a product-wide accuracy claim, the foreign symbol is in the diff) vs masked (a name colliding with one of your own, or a dynamic import() — a documented statistical limit). Numbers are per-corpus, fed from CI so they can't drift from what ships.

How to read the false-alarm numbers

A fire is not automatically a false alarm. We split every one two ways:

And we split by where the change lands. Existing filesis the "does it stay quiet on my stable code?" number — the one that matters most. New files introduce new dependencies far more often, so most new-file fires are detections; the new-file over-fire column (true false alarms) stays near zero.

Commit-level bootstrap 95% CIs. Numbers published before July 2026 were measured train-on-test and were materially optimistic — seeissue #92. Fed from CI, so the numbers can't drift from what ships.

Public claim provenance: foreign 36 corpora / 12 languages / visible foreign-import and foreign-api fixture symbols after excluded-host purge · d1007f50; generated_at=2026-07-28; integrity 23 corpora / 12 languages; authored test-gaming fixtures, production fit→check · 1b0de32d; just integrity-verify, 2026-07-28. The combined brief has no approved aggregate public claim.

97%
catch · visible foreign, gated classes (620/637)
85%
catch · every class & tier, incl. ungated (645/756)
1.75%
worst false alarm · existing files
0.00%
worst false alarm · new files

catch by difficulty across 756 graded fixtures / 34 corpora: easy 378/383 (99%) · medium 242/254 (95%) · masked 25/119 (21%) — name collisions & dynamic imports, documented limit

run d1007f50 · 2026-07-28 · ⚠️ marks corpora under the 300-hunk sample bar (excluded from the worst-FP tiles) · false-alarm = over-fire on the repo's own code; novel-pattern detections shown muted

97%
foreign-pattern catch · argot's one job— visible tier, 620/637 across all corpora

Of code that introduces a 0-usage foreign pattern, the share argot flags. This is the gated number; the two tiles below split it by capability. Masked (hard) tier: 21% (25/119) — the documented name-collision / dynamic-import limit.

99%
foreign import / dep · visible catch
masked (hard) 24% — name collisions & dynamic imports, a documented statistical limit
95%
foreign API · visible catch
masked (hard) 20% — name collisions & dynamic imports, a documented statistical limit

Catch is split by whether the foreign symbol is visible in the diff (easy/medium — an explicit import, FQN call, or distinct API name — the pattern an agent introduces in the open) or masked (hard — a foreign call whose name collides with one of the repo's own, an attested root namespace, or a dynamic import()). Masked foreign is the documented statistical limit of a name-based guardrail. In-vocabulary misuse of a library the repo already uses is a separate, deliberately-ungated class (below), not counted here.

Read the two columns honestly. Foreign import / depvisible catch is near-100% on nearly every repo — an explicit foreign import is caught by construction, so it is the easy, reliable half (foreign concurrency libs are folded in here: they are deps, caught the same way, and gave no distinct signal as their own column). The half that actually varies isforeign API (70–100%): catching a foreign callee that isn't an explicit import is the harder job. Each cell's second line (“N/M hard”) is the masked tier — where the real difficulty hides (import/dep ~22%, API ~20% on the hard cases) — surfaced so no column reads as a clean 100% while its hard cases quietly miss.

CorpusLanguageImport / dep catchAPI catchOver-fire · existingOver-fire · new-file
batRust100% (13/13)
0/1 hard
100% (6/6)
0/2 hard
0.30%
+6.80% detections
0.00%
castle-enginepascal100% (7/7)100% (4/4)0.00%
+0.30% detections
0.00%
commanderJavaScript100% (11/11)
1/1 hard
100% (5/5)
0/1 hard
0.00%
+5.09% detections
0.00%
composerPHP100% (12/12)
0/2 hard
100% (7/7)
0/1 hard
0.00%
+0.21% detections
0.00%
curlC92% (12/13)
0/1 hard
100% (6/6)
0/2 hard
0.00%0.00%
dagsterPython100% (6/6)100% (3/3)
0/2 hard
0.00%0.00%
eslint ⚠️JavaScript100% (11/11)
0/1 hard
100% (5/5)
1/1 hard
0.00%0.00%
excalidrawTypeScript100% (12/12)
1/1 hard
91% (10/11)
0/3 hard
0.09%
+1.04% detections
0.00%
express ⚠️JavaScript100% (11/11)
0/1 hard
100% (5/5)
0/1 hard
0.00%
+15.38% detections
0.00%
faker ⚠️Python100% (11/11)
0/1 hard
92% (11/12)
3/6 hard
0.92%0.00%
faker-jsTypeScript100% (10/10)
0/1 hard
100% (8/8)
1/3 hard
0.00%0.00%
fastapiPython100% (11/11)100% (9/9)
1/5 hard
1.75%
+0.87% detections
0.00%
fmt ⚠️C++100% (13/13)
0/1 hard
86% (6/7)
0/2 hard
0.00%
+3.12% detections
0.00%
gh-cliGo100% (10/10)
0/1 hard
89% (8/9)
0/3 hard
0.00%0.00%
guavaJava100% (12/12)
0/2 hard
71% (5/7)
1/3 hard
0.17%
+0.17% detections
0.00%
homebrewRuby100% (11/11)
2/2 hard
100% (8/8)
3/3 hard
0.00%0.00%
honoTypeScript92% (11/12)
0/2 hard
100% (11/11)
1/5 hard
0.00%0.00%
hugoGo100% (12/12)
1/1 hard
100% (7/7)
0/2 hard
1.18%
+0.39% detections
0.00%
ideupascal0.55%
+0.17% detections
0.00%
inkTypeScript100% (11/11)
0/1 hard
100% (9/9)
2/2 hard
0.00%
+6.08% detections
0.00%
jellyfinC#100% (12/12)
0/1 hard
88% (7/8)
0/2 hard
0.00%
+0.45% detections
0.00%
junit5Java92% (11/12)
0/2 hard
100% (7/7)
0/1 hard
0.27%
+0.53% detections
0.00%
laravelPHP100% (12/12)100% (10/10)
1/4 hard
0.00%
+0.63% detections
0.00%
mormot2pascal100% (6/6)100% (5/5)0.00%
+0.75% detections
0.00%
mseide-mseguipascal100% (5/5)60% (3/5)0.61%
+0.79% detections
0.00%
outlineTypeScript100% (11/11)80% (8/10)
0/6 hard
0.11%
+0.32% detections
0.00%
powershellC#100% (13/13)
1/2 hard
89% (8/9)
1/2 hard
0.06%
+0.22% detections
0.00%
redisC100% (11/11)
2/3 hard
100% (8/8)
0/1 hard
0.18%
+0.18% detections
0.00%
richPython100% (12/12)100% (8/8)
1/4 hard
0.00%
+0.51% detections
0.00%
ripgrepRust100% (11/11)
0/1 hard
100% (8/8)
0/2 hard
0.00%
+0.63% detections
0.00%
rocksdbC++100% (9/9)
0/2 hard
100% (12/12)
0/3 hard
0.18%
+1.00% detections
0.00%
rubocopRuby100% (13/13)
0/1 hard
83% (5/6)
0/2 hard
0.63%
+0.51% detections
0.00%
saleorPython100% (13/13)
0/1 hard
90% (9/10)
0/2 hard
0.00%0.00%
scrapyPython100% (12/12)
0/3 hard
100% (6/6)
0/3 hard
0.00%
+0.68% detections
0.00%
uospascal0.00%
+0.29% detections
0.00%
wagtailPython100% (13/13)
1/1 hard
100% (12/12)
0/3 hard
0.00%0.00%

Novel-pattern catch aggregates the two gated foreign classes (foreign import / dep — incl. concurrency libs — and foreign API) — this is the metric argot gates on.False alarm is over-fire: a fire on the repo's own existing code (0 new symbols) — the true false alarm, held near zero.Detections (muted, “+x%”) are fires on a symbol that is 0-usage at fit — a real new dependency or API argot correctly flags for review — so they never count against the score. Reinvention and misplacement (below) are measured separately and are not folded into these numbers. ⚠️ marks corpora under the 300-hunk sample bar.

2 · Reinvention · rule redundant

A local code-embedding index — built with a 15.6 MB model compiled into the binary, nothing to download — finds a new function that reimplements one the repo already has.Catch is high — parallel agents write faithful reimplementations of a repo's own functions (renamed, restructured); planted as new code, argot flags them redundant at ≥ 72% on every corpus (median 94%). False-fire is calibrated away, not hidden. Real repos hold real parallel code, and a naïve embedding sense fires on all of it (5–14% of real-commit hunks). argot filters the shapes that aren't reinventions — thin wrappers, interface / family methods (a linter'son_send across 271 cops), dense sibling clusters, co-located protocol-variant families (curl's cf_h3_*next to cf_h2_*) — and atfit it measures itself against your own history: a mini-replay of the repo's recently added functions estimates its false-fire rate, and repos that practice systematic parallel implementation (saleor's checkout/order mirrors) automatically get a stricter mode. On the leak-free clean-commit replay this lands at amedian 0.4%/hunk, ≤ 2% on 30 of 31 corpora — jellyfin the lone exception at 4.5% (its C# tree at the pinned commit both over-fires and under-catches; the twin-rate guard holds every other repo).redundant is measured separately — never folded into the headline catch/over-fire numbers: argot names the nearest existing function and lets you decide. (Like every rule it fails the check by default; set it to warn oroff in [rules], or mute the hit.)

CorpusLanguageCatch (recall)False-fire / hunk
batRust100% (18/18)0.89% (2/225)
commanderJavaScript100% (18/18)1.49% (6/404)
composerPHP100% (18/18)2.04% (14/686)
curlC89% (16/18)0.47% (2/423)
dagsterPython95% (19/20)2.03% (20/987)
eslintJavaScript89% (16/18)0.00% (0/210)
excalidrawTypeScript75% (15/20)1.94% (39/2006)
expressJavaScript94% (17/18)0.00% (0/39)
fakerPython100% (20/20)0.00% (0/163)
faker-jsTypeScript90% (18/20)0.14% (2/1420)
fastapiPython90% (18/20)0.00% (0/66)
fmtC++89% (16/18)0.00% (0/23)
gh-cliGo94% (17/18)3.49% (81/2320)
guavaJava89% (16/18)1.84% (56/3041)
homebrewRuby94% (17/18)3.20% (19/594)
honoTypeScript100% (20/20)0.99% (6/604)
hugoGo89% (16/18)2.59% (18/694)
inkTypeScript100% (22/22)0.61% (3/493)
jellyfinC#72% (13/18)4.74% (35/739)
junit5Java100% (18/18)3.50% (7/200)
laravelPHP89% (16/18)3.92% (23/587)
outlineTypeScript100% (20/20)0.18% (2/1088)
powershellC#100% (18/18)0.00% (0/109)
redisC89% (16/18)1.04% (9/863)
richPython100% (20/20)0.42% (3/707)
ripgrepRust94% (17/18)1.23% (5/405)
rocksdbC++89% (16/18)2.66% (51/1915)
rubocopRuby100% (18/18)1.29% (5/388)
saleorPython90% (18/20)0.78% (9/1161)
scrapyPython95% (19/20)1.93% (17/882)
wagtailPython95% (19/20)0.31% (1/324)

Catch = recall over planted faithful reimplementations (caught/total). False-fire / hunk = share of replayed-commit hunks that fired redundant (fires / hunks scanned); the muted line is the judged-true rate after three independent reviewers removed the genuine reinventions (majority vote, default false-alarm). Shown for every corpus; window 150, leak-free holdout. Measured separately — never folded into the headline catch/over-fire metric.

3 · Misplacement · rule misplaced

The same index judges where a function belongs: if its nearest peers nearly all live in a different package than the one it's filed under, it's probably misplaced. The "package" isn't a fixed directory depth — atfit, argot walks each repo's tree to its real package granularity (descending through containers likesrc/ or src/Illuminate/),merges packages that are semantically entangled (a header-only library's src/ and include/are one thing, not two), and calibrates the vote against itself: a transplant simulation on the repo's own functions picks the thresholds, and when no configuration reaches usable recall the sense is disabled for that repo— a flat single-package library gets silence, not noise (marked “—” below).Catch = transplant recall: a real function re-filed into a foreign but existing package fires misplaced at 85–99% on every judging repo (median 96%)— up from a median of 66% (and literally 0% on composer, whose whole tree sat in one fixed-depth area) before the self-calibration. False-fire = the leak-free clean-commit holdout: ≤ 1.2% of hunks on every repo. The former outliers are gone the honest way — fmt (20%: a header-only layout with no separable architecture) now abstains, and junit5 (5.5%: near-identicaljunit-platform-* siblings) merges them and lands at 0.

CorpusLanguageCatch (transplant recall)False-fire / hunk
batRust (n=0)0.00% (0/225)
commanderJavaScript (n=0)0.00% (0/404)
composerPHP94% (n=602)0.15% (1/686)
curlC97% (n=536)0.00% (0/423)
dagsterPython96% (n=1129)1.01% (10/987)
eslintJavaScript98% (n=541)0.00% (0/210)
excalidrawTypeScript88% (n=584)0.50% (10/2006)
expressJavaScript (n=0)0.00% (0/39)
fakerPython95% (n=720)0.00% (0/163)
faker-jsTypeScript (n=0)0.00% (0/1420)
fastapiPython96% (n=650)0.00% (0/66)
fmtC++ (n=0)0.00% (0/23)
gh-cliGo99% (n=544)0.00% (0/2320)
guavaJava97% (n=504)0.07% (2/3041)
homebrewRuby98% (n=508)0.00% (0/594)
honoTypeScript (n=0)0.00% (0/604)
hugoGo97% (n=517)0.86% (6/694)
inkTypeScript (n=0)0.00% (0/493)
jellyfinC# (n=0)0.00% (0/739)
junit5Java99% (n=519)0.00% (0/200)
laravelPHP95% (n=517)0.17% (1/587)
outlineTypeScript94% (n=521)0.28% (3/1088)
powershellC#96% (n=501)0.00% (0/109)
redisC99% (n=516)0.00% (0/863)
richPython (n=0)0.00% (0/707)
ripgrepRust92% (n=529)0.00% (0/405)
rocksdbC++95% (n=503)0.37% (7/1915)
rubocopRuby95% (n=507)0.00% (0/388)
saleorPython97% (n=542)1.03% (12/1161)
scrapyPython94% (n=716)0.00% (0/882)
wagtailPython97% (n=1250)0.00% (0/324)

Catch = transplant recall (n = functions sampled); “—” marks a repo where the fit-time self-calibration disabled placement — flat single-package or semantically-fused layouts (bat, commander, express, ink, rich, fmt) with no separable architecture to judge; their false-fire is 0 by construction (the sense abstains). False-fire / hunk = replayed-commit hunks that firedmisplaced (fires / hunks scanned), window 150. Measured separately — never folded into the headline catch/over-fire metric.

4 · Architecture · gated

argot builds a directed graph of the repo's own internal module dependencies at fit time — which layer is allowed to import which — and learns the layering the repo actually follows. At check time it flags a module-dependency edgethat breaks it: a reversed dependency (a low-level module reaching back up into a caller), a cycle the edge closes, or an edge out of a sink layer (a models/ file importing views/, a utility reaching into the app layer). It's the relational analog of Foreign-pattern detection above — Foreign catches a foreign import; this catches a foreign edge between the repo's own modules, the shape an agent produces when it wires code together without noticing how the repo is layered. Pure-Rust, no added runtime dependency, and it gates at the same mildest (unusual) tier as Foreign above.

97.1%
real recall · a planted foreign layering edge, caught on replay— 264/272 across all corpora

0% false positives on held-out clean edges (0/148 controls fired) · 0.37% mean over-fire on replayed history (worst 2.7%) ·25 corpora across 12 languages.

CorpusLanguageReal recallControl-FPOver-fire
saleorPython100% (12/12)0/62.67%
scrapyPython100% (12/12)0/60.00%
wagtailPython100% (12/12)0/50.00%
fastapiPython100% (10/10)0/60.17%
fakerPython100% (10/10)0/50.00%
dagsterPython100% (12/12)0/80.67%
composerPHP92% (11/12)0/81.75%
laravelPHP92% (11/12)0/80.00%
ripgrepRust90% (9/10)0/50.00%
batRust100% (12/12)0/80.00%
guavaJava100% (12/12)0/80.00%
junit5Java100% (12/12)0/80.33%
powershellC#90% (9/10)0/50.00%
jellyfinC#92% (11/12)0/80.00%
rubocopRuby100% (7/7)0/20.00%
gh-cliGo88% (7/8)0/51.06%
hugoGo92% (12/13)0/60.00%
honoTypeScript100% (10/10)0/60.00%
eslintJavaScript100% (8/8)0/40.00%
excalidrawTypeScript100% (12/12)0/82.00%
faker-jsTypeScript100% (12/12)0/60.00%
curlC90% (9/10)0/10.00%
rocksdbC++100% (12/12)0/80.67%
mormot2Pascal100% (10/10)0/40.00%
castle-enginePascal100% (10/10)0/40.00%

Real recall = planted foreign layering-edge fixtures caught / total (caught/total). Control-FP = planted clean, in-layering edges that should not fire, fires / total —0/148 across every corpus. Over-fire = false-alarm rate on the repo's own replayed history (leak-free holdout, same protocol as Foreign above). Fed from CI so the numbers can't drift from what ships; gated at the mildest (unusual) tier.

What argot deliberately does not gate on

Two more classes are reported for interest but never gated — they are a documented local limit, and not the danger an LLM poses (an agent drags in a whole foreign pattern; it doesn't subtly misuse your own vocabulary):naming-shape breaks (camelCase in a snake_case repo) andin-vocabulary misuse — a wrong choice among constructs the repo already uses: a bare ValueError where the repo raisesHTTPException, die vs throw, or araw-builtin concurrency antipattern (a barepthread/Thread where the repo has its own thread wrapper, a blocking call inside async code, a busy-wait poll). The line is the same everywhere: a foreign concurrency library — an async runtime or thread pool the repo never depends on — is a foreign dep, gated under import/dep above; misusing the concurrency builtins the repo already hasis this ungated class, caught only about half the time — the same proven local limit as the other misuse breaks. Seewhat it catches.

History

DateCommitCatch (gated)Worst false alarm · existingWorst false alarm · new-file
2026-07-055e533bcc86%0.98%0.00%
2026-07-079276d52e85%1.17%0.00%
2026-07-147be8b1eb86%1.46%0.00%
2026-07-28d1007f5085%1.75%0.00%