Skip to content

OI-43 step 4: say which languages a repo could only partly read - #57

Merged
BrettCrawley merged 1 commit into
mainfrom
feat/oi43-language-coverage-note
Aug 8, 2026
Merged

OI-43 step 4: say which languages a repo could only partly read#57
BrettCrawley merged 1 commit into
mainfrom
feat/oi43-language-coverage-note

Conversation

@BrettCrawley

Copy link
Copy Markdown
Collaborator

OI-43 step 4 — say it in the output, not only in a changelog

The gate records the matrix and the changelog explains it, but neither reaches
someone reading a repo's findings
. A Go or TypeScript repo looked exactly like a
Java one: findings present, confidence stated, and nothing to say that T1 and T2
resolution could not fire at all for it.

go: limited extraction across 40 file(s) — declared field types, so T1
resolution cannot fire; supertypes, so T2 resolution cannot fire. Findings for
this language are incomplete rather than absent; see OI-43.

One note per repo per language, never per file. Scala alone would otherwise
put a note on every Scala file in an estate, and a signal that loud stops being
read — the noise question that kept this out of OI-36 phase 1. A Java or Kotlin
repo stays quiet, because those are the covered ones, and a signal that fires
on success is not a signal.

The gaps are computed, never restated

A hand-maintained list of "languages we do not fully support" is exactly what
rotted into OI-43, and it would go stale the moment a table gained an entry.
coverage_gaps() reads the live grammar tables, so a note cannot claim a
limitation that has since been fixed, nor stay silent about one that has not.

test_a_filled_table_silences_its_gap fills a table and asserts the gap
disappears — proving the derivation is real rather than incidental.

One pass, not two

run-manifest.json gains counts.resolution_gaps — repos affected per language
— computed in the same pass as counts.unparsed. Reading the fleet twice to
produce two numbers would be OI-41's defect reintroduced for the sake of
tidiness, so _unparsed_counts became _record_counts and folds both.
_fold_record splits the per-record work out to stay under the complexity
ratchet.

The two numbers in that block are deliberately sourced differently:
unparsed matches note markers (shared constants, so wording cannot drift);
resolution_gaps is recomputed from each record's language_breakdown against
the live tables, because deriving cannot go stale the way string matching can.

Verified end to end

A repo holding Go, Java and Scala:

notes:  go   — limited extraction across 1 file(s) — ...T1... ...T2...
        scala — limited extraction across 1 file(s) — no tree-sitter grammar...
        (java: silent)
manifest: "resolution_gaps": {"go": 1, "scala": 1}

Rescan

DETECTION_VERSION 16 → 17 — notes are record content. 3.1.0 shipped
detection 13, so 14 through 17 all fall in the same unreleased window:
still one rescan.

Gates

1098 tests (6 new), 148 mutants (2 new, both killed non-vacuously), ruff,
mypy --strict, complexity ratchet, fingerprint gate — green locally. Catalogue
budget 148 → 150; both new mutants are ordinary, so the slow tail stays at two.

The gate records the matrix and the changelog explains it, but neither reaches
someone reading a repo's findings. A Go or TypeScript repo looked exactly like a
Java one: findings present, confidence stated, nothing to say that T1 and T2
resolution could not fire at all for it.

One note per repo per language whose extraction is limited, never per file.
Scala alone would otherwise put a note on every Scala file in an estate, and a
signal that loud stops being read - the noise question that kept this out of
OI-36 phase 1. A Java or Kotlin repo stays quiet, because those are the covered
ones, and a signal that fires on success is not a signal.

  go: limited extraction across 40 file(s) - declared field types, so T1
  resolution cannot fire; supertypes, so T2 resolution cannot fire. Findings for
  this language are incomplete rather than absent; see OI-43.

The gaps are computed from the grammar tables, never restated. A hand-maintained
list of "languages we do not fully support" is exactly what rotted into OI-43,
and it would go stale the moment a table gained an entry. coverage_gaps() reads
the live tables, so a note cannot claim a limitation that has since been fixed
nor stay silent about one that has not - and a test fills a table to prove the
derivation is real rather than incidental.

run-manifest.json gains counts.resolution_gaps, repos affected per language,
computed in the SAME pass as counts.unparsed. Reading the fleet twice to produce
two numbers would be OI-41's defect reintroduced for the sake of tidiness, so
_unparsed_counts became _record_counts and folds both. The per-record work is
split into _fold_record to stay under the complexity ratchet.

Note that resolution_gaps is recomputed from each record's language_breakdown
rather than parsed back out of the note prose. Deriving from the tables cannot
go stale the way string matching can, and the two numbers in that block are
deliberately sourced differently for that reason.

DETECTION_VERSION 16 -> 17: notes are record content. 3.1.0 shipped detection
13, so 14 through 17 all fall in the same unreleased window and one rescan
covers the lot.

Verified end to end on a repo holding Go, Java and Scala: two notes, Java
silent, and counts.resolution_gaps = {"go": 1, "scala": 1}.

Two mutants added (OI43-M4, OI43-M5), catalogue 148 -> 150. 1098 tests, 148
mutants, ruff, mypy --strict, complexity ratchet, fingerprint gate all green.
@BrettCrawley
BrettCrawley merged commit 63cff73 into main Aug 8, 2026
10 checks passed
@BrettCrawley
BrettCrawley deleted the feat/oi43-language-coverage-note branch August 8, 2026 16:29
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