Knip 5 is effectively frozen: 5.88.1 (2026-03-19) was its last release,
with only three patches after 6.0.0 shipped and none since.
The reason for the earlier downgrade (968cc72) was misdiagnosed. The 6 GiB
allocation is not the Rust-side arena tracked in oxc-project/oxc#20513, but
a JS-side `new ArrayBuffer(BLOCK_SIZE + BLOCK_ALIGN)` in oxc-parser's
raw-transfer path, allocated by V8. Linux refuses it under heuristic
overcommit on the CI runner (3.7 GB RAM, no swap). The upstream allocator
work that has landed does not touch this path, so waiting on it would not
have helped.
Set KNIP_DISABLE_RAW_TRANSFER=1 in the `knip` script instead, and route
lefthook and `check` through the script rather than the bare binary — the
default path would otherwise crash with an opaque RangeError. Raw transfer
is worth ~5% on a repo this size (3.1s vs 3.15s); the upstream 2-4x figure
applies to large codebases. Knip 6 is still ~20% faster than 5 overall.
No change in unused-code detection. Verified under overcommit_memory=0 on
Linux as well as locally.
Closes#11
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
.jscpd.json set pattern to an array, but jscpd's --pattern takes a single
glob string. An array matches nothing, so the gate had reported success
without reading a file since 2793a66 introduced it — its 0.074ms
"detection time" and absent stats table were the tell. Bisecting the
config confirmed that key alone reduces the run to zero files.
The ignore entries were also bare names rather than globs, so once the
pattern worked it swept apps/web/dist and .pnpm-store — 948 files.
Excludes __tests__, matching what .jsinspectrc already does. Duplication
between test cases is usually deliberate: parallel arrange/act/assert
blocks read better than shared setup, and the factories under
apps/web/src/__tests__/factories cover the deduplication worth having.
Real duplication is 1.72% across 209 source files, so the threshold drops
from 5% to 3%. jscpd measures a ratio rather than blocking each new clone,
and a 5% budget left roughly 3x headroom before it would ever fire.
Gives jscpd explicit paths behind `pnpm jscpd`, so lefthook and the check
script share one invocation, as jsinspect already does.
Also guards the pattern key in check-gates.mjs, since an array there fails
silently rather than erroring.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two separate defects, both of which made the gate pass without checking:
lefthook ran `pnpm oxlint -- --deny warnings`. pnpm forwards arguments
after `--` to the script, so oxlint received its own `--` terminator and
read the rest as file paths — the pre-commit oxlint job linted 0 files.
The check script used `--deny warnings` rather than `--deny-warnings`.
`--deny` takes a rule or category and `warnings` is neither, so it was
accepted and ignored. Without `--deny-warnings` the run reports warnings
but still exits 0, so CI was equally non-blocking.
Both now call `pnpm oxlint`, keeping the flags in one place.
Introduced 2026-03-29 in b6ee4c8, which claimed warnings would fail the
build. 9b0cb38 diagnosed the invalid flag but fixed only the npm script,
leaving both actual gates broken.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Slim Vitest pre-commit output with dot reporter and coverage summary.
Ignore .agent-tests/ and docs/agents/research/ in git.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds void to floating promise in bestiary-cache.ts, extracts shared
polyfillDialog() helper to eliminate unbound-method warnings in 3 test
files. Adds --deny warnings to oxlint so future warnings fail the
build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Independent checks (audit, knip, biome, jscpd, jsinspect, custom
scripts) now run in parallel. Type-dependent checks (oxlint, vitest)
remain sequential after tsc --build via a piped group. Also reorder
pnpm check for fast-fail on cheap checks first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>