Tooling excludes on the JavaScript corpus: measured, decision: do not build
Superseded in part (0.29.5): ESLint flat-config
ignoresplus.prettierignore, corroborated per directory, now ship. Re-measured on this same corpus they still exclude nothing; see 2026-10-19.
Date: 2026-08-11
Build under test: crimes 0.25.3
Question: 0.25.0 shipped honourToolingExcludes for pyproject.toml
only. Sprint 0.26 S6 proposed the other three sources (.gitattributes linguist-vendored, tsconfig exclude, and
.eslintignore) with the instruction to measure them on hono,
cal.com, n8n and posthog first, and to close the entry with a
measurement if nothing corroborates.
Decision: nothing corroborates, on any of the four. Do not build the three readers. One separate thing is worth reading, under a different mechanism, and is sized at the end.
What is actually present
Section titled “What is actually present”| repo | .gitattributes | root tsconfig.json | .eslintignore | .prettierignore |
|---|---|---|---|---|
| hono | absent | no exclude (solution-style, references only) | absent | absent |
| cal.com | 4 lines | absent at root | absent | absent |
| n8n | 1 line (*.sh text eol=lf) | **/dist/**/*, **/node_modules/**/* | absent | 19 patterns |
| posthog | 42 lines | frontend/dist/**/*, **/*.mdx | absent | absent |
Three findings before any corroboration arithmetic runs.
.eslintignore does not exist on this corpus. ESLint 9 replaced it
with an ignores key inside flat config, and all four repos have moved
on. The plan named a dead format. hono has eslint.config.mjs with no
ignores block at all.
Root tsconfig.exclude contributes nothing beyond crimes’ own
defaults. Every pattern present names dist or node_modules, which
are already excluded, or **/*.mdx, which is not scanned as source.
The substance lives in the 12 / 28 / 85 / 86 nested tsconfigs each repo
carries, and the root-only rule the pyproject.toml reader established
deliberately does not follow those: a nested config governs its own
tree, and following it is a separate decision with its own failure modes.
The plan named the wrong .gitattributes attribute.
linguist-vendored appears exactly once across the four repos
(/.yarn/** in cal.com). linguist-generated appears 30 times (29 in
posthog, 1 in cal.com) and names real generated source: protobuf
_pb2 modules, an ANTLR-emitted parser, posthog/schema.py,
frontend/src/generated/**.
Corroboration: zero, everywhere
Section titled “Corroboration: zero, everywhere”Applying the shipped rule: a pattern counts only when two independent tools name it, with two keys of one tool counting once:
| repo | distinct normalised patterns | corroborated by ≥2 tools |
|---|---|---|
| hono | 0 | 0 |
| cal.com | 2 | 0 |
| n8n | 21 | 0 |
| posthog | 29 | 0 |
The mechanism would exclude nothing, on any repo, however many readers were written. That is the measured answer to S6’s question, and it is cheaper than shipping something nothing triggers.
The corroboration rule is not a formality: it is load-bearing
Section titled “The corroboration rule is not a formality: it is load-bearing”n8n’s .prettierignore ends:
# Handled by biome**/*.ts**/*.js**/*.json**/*.jsoncA reader that treated a formatter’s ignore file as a maintenance claim would exclude 18,783 TypeScript files (the entire n8n codebase) on the strength of a line that means “a different formatter owns these”. The code is maximally maintained. Nothing in the file’s syntax distinguishes that from “this directory is dead”.
This is the general shape of the hazard, and it is why the answer to “decide what corroborates what” is not a table of weights:
.eslintignore,.prettierignoreandtsconfig.excludeexpress a tool’s preferences.linguist-vendoredis a display hint for GitHub’s language bar. None of them is a claim about whether the code is maintained — that is an inference the reader adds, and n8n shows what it costs when the inference is wrong.
Corroboration works on pyproject.toml because four tools read one file
and agreeing on a path there is cheap evidence. It does not rescue a
signal that never meant maintenance in the first place; it only makes a
weak signal harder to trigger. On this corpus it makes it impossible.
The one thing worth reading, and why it is a different mechanism
Section titled “The one thing worth reading, and why it is a different mechanism”linguist-generated is not a preference. It is a factual claim about
provenance that the repository makes about its own file: the same
kind of claim as an @generated banner or a Code generated by … DO NOT EDIT header, both of which util/scope-class.ts already trusts from a
single source. Provenance does not need corroborating; maintenance
does. That is the line.
So it belongs in the generated scope class, not in
manifest/tooling-excludes.ts, and it needs no corroboration rule.
Sized against what the heuristics already catch: files carrying
findings that posthog declares generated and GENERATED_RE misses:
posthog 4 files, 69 findings 52x frontend/src/queries/validators.js 14x frontend/src/products.tsx 2x services/mcp/src/api/generated.ts 1x frontend/src/lib/posthog-typed.tscal.com 0 files (its one entry, /.pnp.*, is not scanned)None of the four matches the path heuristics: validators.js and
products.tsx look like ordinary source, and api/generated.ts misses
because the pattern wants generated as a directory segment or a
.generated.ts suffix. 69 findings on four files a repo has explicitly
labelled machine-written is a real result for a reader of about twenty
lines.
Done in 0.25.10, as its own change with its own before/after
rather than carried in on the back of this negative result. The reader
lives in manifest/gitattributes.ts and feeds isNeverReportable: one
policy, no new schema surface, and no coverage.warnings[] entry,
matching the existing generated-code behaviour. The distinction that
settles the warning question: a tooling-excluded path is never analysed,
so silence about it is a gap the user cannot see past; a generated file
is analysed and its findings simply are not the team’s to fix.
Measured on a clean paired scan, both runs clock-pinned:
posthog 14,250 → 14,181 −69 findings, 0 added, 0 surviving score movedcal.com 4,633 → 4,633 unchanged (its one entry, /.pnp.*, is not scanned)
removed by detector: large_function 43, exact_duplicate_block 8, negative_flag_maze 5, option_bag_junk_drawer 5, large_file 4, boolean_naming_drift 2Exactly the four files predicted, and the detector breakdown is the
point: a machine-written validator accused of having a God Function and
badly-named booleans. No eval fixture declares anything generated
(04-monorepo has a .gitattributes, but only * text=auto), so
evals:ranking is unchanged.
linguist-vendored is still not read: one occurrence across the
four repos, and a display hint rather than a claim about authorship.
Implementation note, if anyone does return to tsconfig
Section titled “Implementation note, if anyone does return to tsconfig”Its exclude is JSONC, and parsing it is not a one-liner. posthog’s root
tsconfig.json defeated a comment-stripper that handled /* */ before
//, and survived one that handled only //: by luck, since neither
copes with // inside a string. A real reader needs a JSONC parser, not
a regex. Cost worth knowing before quoting the entry as “small”.