docs(readme): a visible table for all 13 file types, pinned to the registry

The extractor registry reads 13 extensions. The README's opening line named
five of them, and the full list existed only in a hidden
`<!-- extract-formats: ... -->` comment, which no reader reads -- so the README
undersold what the code does and stated no evidence class anywhere a consumer
would look.

A `## Supported file types` table now carries one row per extension: reader,
dependency (core or the `[extract]` extra), the evidence class `_EVIDENCE`
records for the row, and one honest note. The three `constructed` office rows
carry their denominators (N = 1, N = 2, N = 1) in the table itself, so a row
that has met no document anyone wrote cannot read as a supported one; `.htm`
does not borrow `.html`'s 828-file class, because the code records none for it.
A `Not read today` section states the absences (`.doc`, `.epub`, `.eml`/`.msg`,
image files, source files, `.one`/`.vsd`) as facts, not as a queue.

Test first, red before the table existed: four assertions in
`tests/test_docs_promises.py` pin the table's row set to
`_CORE_EXTRACTORS | _OPTIONAL_EXTRACTORS`, each evidence cell to `_EVIDENCE`
(and to a fixed `stdlib, no corpus class` where the code records none), the
core/extra split to the registries, and the opening to the table.

No change to `extract.py` and no version bump: nothing about what is read
moved, only what the README says about it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-12 21:26:15 +02:00
commit 2d3c2707c7
3 changed files with 151 additions and 3 deletions

View file

@ -114,3 +114,82 @@ def test_the_readme_recursion_claim_matches_the_door() -> None:
gate=lambda body: GateDecision(sanitized_text=body, disposition="warn", reasons=()),
)
assert [item.source_file for item in result.persisted] == ["sub/deep.md"]
# --- the visible table, K3-26 ----------------------------------------------
#
# The comment marker above is machine-readable and invisible to a reader: the
# README's own prose named FIVE of the thirteen types the registry reads, and
# nothing went red, because the marker test only asks that the hidden list is
# complete. A reader does not read the marker. So the table a reader does see
# is pinned to the same registry, row for row, and to the evidence class the
# code records for each row.
_TABLE_HEADING = "## Supported file types"
# The evidence cell for a row `_EVIDENCE` does not carry. Those five are the
# stdlib rows: `_EVIDENCE` records a CORPUS class, and a row that has never
# been given one must not borrow `measured` from the row beside it.
_NO_CLASS = "stdlib, no corpus class"
def _table_rows() -> dict[str, list[str]]:
"""The table's data rows, keyed by suffix, with markup stripped per cell.
Backticks and asterisks are removed rather than matched, so the table can
be formatted freely and this test still reads what it says.
"""
text = README.read_text(encoding="utf-8")
assert _TABLE_HEADING in text, (
f"README.md carries no `{_TABLE_HEADING}` section; the format list is "
"then visible only in a hidden comment, which is what K3-26 fixed"
)
rows: dict[str, list[str]] = {}
for line in text.split(_TABLE_HEADING, 1)[1].splitlines():
stripped = line.strip()
if not stripped.startswith("|"):
if rows:
break
continue
cells = [re.sub(r"[`*]", "", cell).strip() for cell in stripped.strip("|").split("|")]
if cells and cells[0].startswith("."):
rows[cells[0]] = cells
return rows
def test_the_readme_table_names_every_type_the_registry_reads() -> None:
assert set(_table_rows()) == set(_CORE_EXTRACTORS) | set(_OPTIONAL_EXTRACTORS)
def test_the_readme_table_states_the_evidence_class_the_code_records() -> None:
rows = _table_rows()
assert rows, "no data rows found under the supported-file-types heading"
for suffix, cells in rows.items():
assert len(cells) >= 4, f"the {suffix} row has no evidence column: {cells}"
assert cells[3] == _EVIDENCE.get(suffix, _NO_CLASS), (
f"the {suffix} row says {cells[3]!r}; the code records "
f"{_EVIDENCE.get(suffix, _NO_CLASS)!r}"
)
def test_the_readme_table_separates_core_from_the_extract_extra() -> None:
"""Which rows need the optional extra is the first thing a consumer asks."""
for suffix, cells in _table_rows().items():
gated = "[extract]" in cells[2]
assert gated == (suffix in _OPTIONAL_EXTRACTORS), (
f"the {suffix} row's dependency cell reads {cells[2]!r}"
)
def test_the_readme_opening_does_not_name_five_of_thirteen() -> None:
"""The first thing a reader sees must not undersell what the code reads.
Either form passes: a pointer to the table, or the whole set spelled out.
A partial list -- the state before K3-26 -- passes neither.
"""
intro = README.read_text(encoding="utf-8").split("## Install", 1)[0]
if "#supported-file-types" in intro:
return
every = set(_CORE_EXTRACTORS) | set(_OPTIONAL_EXTRACTORS)
named = {s for s in every if re.search(rf"\b{s.lstrip('.')}\b", intro, re.IGNORECASE)}
assert named == every, f"the opening names {sorted(named)}, not all of {sorted(every)}"