fix(accounting): a corpus that measures no class says so in row 6 (H6)
`measures_no_class(units)` returns a sentence when EVERY document of a corpus has no declared fate, and row 6 prints it beside that corpus's tally. On N200 that is 16 549 elements of `u` which look like a finding about the build and are a finding about the run: the build exits 2 on 0 proposed plans before the accounting door is reached, so no accounting file exists to read a fate from. The function's docstring carries what it would take, because that is a capability and not a threshold: `.json` is read as generic JSON, and the publisher's STS delivery in that form would have to reach the markdown grammar `_extract_xml` writes for the XML one. Measured 2026-09-19, with the query validated against a known positive: `standardContent` occurs 0 times in `src/` and 4 in the witness. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e6d9f16107
commit
280d6bd48e
2 changed files with 39 additions and 2 deletions
|
|
@ -505,6 +505,11 @@ class Unit:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#: The note `_document_unit` leaves when the run declared no fate at all for a
|
||||||
|
#: document -- because the build never reached the accounting door.
|
||||||
|
NO_DECLARED_FATE = "no declared fates"
|
||||||
|
|
||||||
|
|
||||||
def _conservation_held(build: Build) -> bool:
|
def _conservation_held(build: Build) -> bool:
|
||||||
return build.exit_code == 0 and "K1b FAILED" not in build.log
|
return build.exit_code == 0 and "K1b FAILED" not in build.log
|
||||||
|
|
||||||
|
|
@ -552,7 +557,7 @@ def _document_unit(
|
||||||
images: list[Mapping[str, Any]] = list(entry.get("images", []))
|
images: list[Mapping[str, Any]] = list(entry.get("images", []))
|
||||||
total = sum(elements.values())
|
total = sum(elements.values())
|
||||||
if declared is None:
|
if declared is None:
|
||||||
return Unit(name, "document", total, 0, notes=["no declared fates"])
|
return Unit(name, "document", total, 0, notes=[NO_DECLARED_FATE])
|
||||||
if not version_ok:
|
if not version_ok:
|
||||||
return Unit(
|
return Unit(
|
||||||
name,
|
name,
|
||||||
|
|
@ -1010,6 +1015,35 @@ def clean_in_every_run(runs: Sequence[Sequence[Unit]]) -> int:
|
||||||
return sum(1 for parts in zip(*runs) if all(unit.clean for unit in parts))
|
return sum(1 for parts in zip(*runs) if all(unit.clean for unit in parts))
|
||||||
|
|
||||||
|
|
||||||
|
def measures_no_class(units: Sequence[Unit]) -> str | None:
|
||||||
|
"""Did this corpus fail to measure ANY element class at all? (H6)
|
||||||
|
|
||||||
|
Reproduced on N200 Vegbygging:2024, 2026-09-19: `okf build` proposes 0
|
||||||
|
plans on it, prints `FAILED - no segmentation plans` and exits 2 BEFORE
|
||||||
|
the accounting door -- no accounting file is written. Every element then
|
||||||
|
lands as `u` with no declared fate, and 16 549 unaccounted reads like a
|
||||||
|
finding about the build when it is a finding about the run.
|
||||||
|
|
||||||
|
What it would take is a capability and not a threshold: `.json` is read as
|
||||||
|
generic JSON, and the publisher's STS delivery in that form would have to
|
||||||
|
reach the same markdown grammar `_extract_xml` writes for the XML one. No
|
||||||
|
such reader exists in the package -- `standardContent` occurs 0 times in
|
||||||
|
`src/` and 4 times in this gate's witness (measured 2026-09-19).
|
||||||
|
"""
|
||||||
|
documents = [u for u in units if u.kind == "document"]
|
||||||
|
if not documents:
|
||||||
|
return None
|
||||||
|
blank = [u for u in documents if NO_DECLARED_FATE in u.notes]
|
||||||
|
if len(blank) != len(documents):
|
||||||
|
return None
|
||||||
|
return (
|
||||||
|
f"{len(blank)} of {len(documents)} document(s) have no declared fate: the build "
|
||||||
|
"did not reach the accounting door, so this corpus measures no element class. "
|
||||||
|
"`.json` is read as generic JSON; an STS delivery in that form would have to "
|
||||||
|
"reach the markdown grammar the XML reader writes."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def refused_whole(documents: Mapping[str, Any], build: Build) -> str | None:
|
def refused_whole(documents: Mapping[str, Any], build: Build) -> str | None:
|
||||||
"""Did this run persist NOTHING of a corpus that holds documents?
|
"""Did this run persist NOTHING of a corpus that holds documents?
|
||||||
|
|
||||||
|
|
@ -1095,6 +1129,9 @@ def row6(r761: Path | None, n200: Path | None, ci: bool) -> Row:
|
||||||
f" {len(doubled)} file(s) carried through the document AND rejected, "
|
f" {len(doubled)} file(s) carried through the document AND rejected, "
|
||||||
f"e.g. {doubled[0].name}"
|
f"e.g. {doubled[0].name}"
|
||||||
)
|
)
|
||||||
|
blank = measures_no_class(units)
|
||||||
|
if blank is not None:
|
||||||
|
details.append(f" gate {label}: {blank}")
|
||||||
if label == "default":
|
if label == "default":
|
||||||
whole = refused_whole(documents, build)
|
whole = refused_whole(documents, build)
|
||||||
if whole is not None:
|
if whole is not None:
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ MUTANTS: tuple[Mutant, ...] = (
|
||||||
"X2 a report may declare a document rejected while the bundle holds it",
|
"X2 a report may declare a document rejected while the bundle holds it",
|
||||||
GATE,
|
GATE,
|
||||||
' if status == "rejected" and persisted:\n invalid += 1',
|
' if status == "rejected" and persisted:\n invalid += 1',
|
||||||
' if False:\n invalid += 1',
|
" if False:\n invalid += 1",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue