Skip to content

v1.108.306 — A count taken after the page, and a field nobody read

Choose a tag to compare

@jgravelle jgravelle released this 29 Aug 00:20
· 38 commits to main since this release

Four issues from @lilubot, two sharing a root cause and a third falling out of the first.

A count taken after the page was cut (#559)

get_untested_symbols computed untested_count = len(symbols) after the max_results slice and derived reached_pct from it. get_repo_health calls it with max_results=1 under the comment "we only need the count".

So the published health/radar test axis read ~100% reach on every repository with untested code. Measured by the reporter: 4,893 untested of 6,352 (23.0% reached), published as 100. The axis feeds radar, so it reached the grade and the observatory.

The sweep for other instances found none, and that is the finding. find_importers, find_references and get_dead_code_v2 all count before slicing. The property is now held across all four, because this defect is invisible to any single call — one call's number is self-consistent, and only two page sizes over the same repo can see it.

A field written at index time and read by nobody (#561, #562)

detect_framework persists entry_point_patterns into context_metadata; for Next.js that is exactly route.ts, page.tsx, layout.tsx, middleware.ts. A tree-wide search found that key written in one place and read in none. Every consumer answered "is this a root?" from a list of eleven Python filenames plus Makefile.

So on a Next.js repo get_dead_code_v2 detected zero entry points and returned dead_symbols: [] — which downstream reads as proof of zero dead code — and 203 of 366 "unstable" files were route handlers whose Ca is 0 by construction.

Consuming that field naively would have been far worse than the defect. Flask and FastAPI have carried "*.py" in their entry-point lists for their whole lives; under fnmatch a * crosses /, so the first reader would have declared every Python file in a Flask repo a live root — dead-code detection off across an ecosystem, silently. Removed at the source and refused by the reader.

Coupling exclusions apply to numerator and denominator both. Numerator-only shrinks a count without shrinking what it is a fraction of — the sign error that took a tree 84.0 B → 88.8 B against a truth of 77.3 C in 1.108.305, pointing the other way.

A refusal is not a zero (#562)

get_repo_health turned get_dead_code_v2's honest signal_warning into dead_code_pct: 0.0 and a dead_code axis of 100 — the strongest possible claim, assembled from an explicit admission that nothing was established. It now withholds the composite and the grade through 1.108.305's own unmeasurable_axes mechanism. Toolchain manifests also leave the dead-code population by name: nothing imports a lockfile by design, and package.json was being reported dead by the same run that reads it to find entry points.

Verified, not changed (#560)

All four TypeScript type-only import spellings resolve, including the barrel hop. Tested anyway, because the claim rested on nothing — no test named the syntax.

Found on the way

Three consumers reading keys their producers never emit, two in one renderer. The post-task untested diagnostic and assemble_task_context's audit stage were dark for their whole lives.

The test guarding the first was the reason nobody noticed: its mock returned the invented key. A fabricated producer makes an absent-key defect structurally invisible to a test written about that exact code path.


Full detail in CHANGELOG.md. Thanks to @lilubot for four measured reports with reproductions.

pip install --upgrade jcodemunch-mcp