Skip to content

OI-43 step 6: size the ERROR-tree question before answering it - #60

Merged
BrettCrawley merged 1 commit into
mainfrom
oi43-step6-sizing
Aug 10, 2026
Merged

OI-43 step 6: size the ERROR-tree question before answering it#60
BrettCrawley merged 1 commit into
mainfrom
oi43-step6-sizing

Conversation

@BrettCrawley

Copy link
Copy Markdown
Collaborator

Step 6 was framed as a noise question — report a file whose tree contains ERROR
nodes per file, or count them per repo — with the sizing left as an input to that
choice. Measured, the sizing moves the question one step earlier: has_error
is not one population but two
, and reporting it raw would be false.

No scanner code changed. No version moves.

The instrument

scripts/measure_parse_errors.py mirrors _scan_repo's file selection exactly —
same walk, size cap, per-repo file cap, prescreen, config diversion, extension
table — and applies the test-path skip that extract_from_file performs before
it parses. That skip alone is worth 36% of the denominator; without it the
measurement counts files no run has ever parsed.

It records the parent node type of every error, which is what separated the
two populations and is the reason it is not a bare count.

Deliberately outside the ci chain: it needs a real fleet on disk and produces a
number to reason about, not a threshold to pass. ruff, mypy --strict and
bandit all cover scripts/, so it is held to the same standard as the gates
without pretending to be one.

What the sample says

21 repos, 2,349 parsed files, 15 with an ERROR tree (0.64%). 31 of the 48 error
sites are a bare & in JSX:

where the error lands sites what it is
tsx:error/jsx_element 13 valid, shipping source
javascript:error/jsx_opening_element 12 valid, shipping source
tsx:error/string 6 valid, shipping source
java:error/local_variable_declaration + missing/ twin 8 genuinely broken source
java:error/formal_parameters 2 genuinely broken source

<h2>Costs & Admin</h2> and href="/api/x?format=csv&limit=500" are ordinary
React that compiles and ships; tree-sitter-typescript's TSX grammar rejects both
and accepts &amp; — checked against the grammar, not inferred. The Java sites
are the opposite and the grammar is right: String alias, , byte[][] certData
does not compile. Reporting the merged number tells a reader 4.23% of their TSX
has a parse problem when none of it does.

And it costs extraction nothing today

Repairing only the bytes inside each ERROR span and re-extracting recovered
zero nodes across six files, node sets identical — including the Java file
hand-repaired until it compiles (47 → 47). tree-sitter's recovery is local enough
that the surrounding declarations and calls still extract, so a note keyed on
has_error would report something that is not happening.

What is still outstanding

The fleet run. The threshold cannot be chosen from this corpus and the write-up
says so: it is 1.3% of the fleet's file count, Python- and TSX-heavy where the
fleet is Java/Kotlin-heavy, 12 of its 15 hits come from one React application,
and its two Java hits are the same file in two near-duplicate checkouts.

uv run python scripts/measure_parse_errors.py --repos-root <fleet> --depth 2 -o out.json

Checks

lint, typecheck (89 files, strict), test (1112 passed, 90.38%), srtm,
complexity, detection, bandit, mutation (155/155 killed) all pass.

Step 6 was framed as a noise question - report a file whose tree contains ERROR
nodes per file, or count them per repo - with the sizing left as an input to
that choice. Measured, the sizing moves the question one step earlier:
has_error is not one population but two, and reporting it raw would be false.

scripts/measure_parse_errors.py is the instrument. It mirrors _scan_repo's file
selection exactly - same walk, size cap, per-repo file cap, prescreen, config
diversion, extension table - and applies the test-path skip that
extract_from_file performs before it parses. That skip alone is worth 36% of the
denominator; without it the measurement counts files no run has ever parsed.
It records the parent node type of every error, which is what separated the two
populations and is the reason it is not a bare count.

Deliberately outside the ci chain. It needs a real fleet on disk and produces a
number to reason about, not a threshold to pass. ruff, mypy --strict and bandit
cover scripts/, so it is held to the same standard as the gates without
pretending to be one.

On a 21-repo sample, 15 of 2,349 parsed files carry an ERROR tree - and 31 of
the 48 error sites are a bare & in JSX. <h2>Costs & Admin</h2> and
href="/api/x?format=csv&limit=500" are both ordinary React that compiles and
ships; tree-sitter-typescript's TSX grammar rejects them and accepts &amp;.
The Java sites are the opposite and the grammar is right - String alias, ,
byte[][] certData does not compile. Reporting the merged number tells a reader
4.23% of their TSX has a parse problem when none of it does.

It also costs extraction nothing today. Repairing only the bytes inside each
ERROR span and re-extracting recovered zero nodes across six files, node sets
identical, including the Java file hand-repaired until it compiles.
tree-sitter's recovery is local enough that the surrounding declarations and
calls still extract, so a note keyed on has_error would report something that is
not happening.

What that makes the fix is severity-gated and per repo, in the same manifest
pass as counts.unparsed and counts.resolution_gaps. The threshold cannot be
chosen from this corpus: it is 1.3% of the fleet's file count, Python- and
TSX-heavy where the fleet is Java/Kotlin-heavy, 12 of its 15 hits come from one
React application, and its two Java hits are the same file in two near-duplicate
checkouts. The fleet run is still outstanding and is recorded as such.

No scanner code changed. No version moves.
@BrettCrawley
BrettCrawley merged commit 81108e8 into main Aug 10, 2026
10 checks passed
@BrettCrawley
BrettCrawley deleted the oi43-step6-sizing branch August 11, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant