fix(accounting): a document refused whole is never clean, and the run says how many (H1)
The gate gains a FIFTH column, `Unit.refused`, and it is the only one that is not a defect in the report: the elements of a document the build read and persisted nothing of. Their fate is declared honestly, so `unaccounted` and `double_booked` both stay 0 -- which is exactly why nothing else could see the loss. `refused_whole` asks its question only for a corpus that persisted NOTHING, so one refused source beside an accepted one, the ordinary case on a heterogeneous corpus, reached row 3 as clean. Row 3's reason now carries `N element(s) lost with R of D document(s) refused whole`, and each unclean unit's detail line carries `refused=` beside u, d, unverified and invalid, with the document's own rejection code in the note. On the build side `Accounting.refused` is written into the JSON and into the `**Accounting**` bullet of `log.md` as `R of D document(s) refused whole`. The exit code is NOT moved: it belongs to the whole run, and a corpus holding one unreadable file among many is ordinary, so the order's other half -- state it in the accounting -- is the one taken. `okf build` still exits 1 when it persisted nothing at all. `test_a_corpus_refused_whole_under_the_default_gate_is_red` kept its point and lost its premise: the numbers still balance, and that is now asserted as u = 0 and d = 0 rather than as a clean unit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
5d1060d467
commit
d27ca503c8
4 changed files with 51 additions and 6 deletions
|
|
@ -864,7 +864,10 @@ def test_a_corpus_refused_whole_under_the_default_gate_is_red(tmp_path: Path) ->
|
|||
}
|
||||
build = _build(accounting=declared, sources=set(), exit_code=1)
|
||||
units = gate.account(inventory, build, tmp_path)
|
||||
assert all(u.clean for u in units), "every element has a coded fate"
|
||||
# The NUMBERS still balance -- that is what made the row green, and since
|
||||
# H1 the loss has its own column instead of hiding behind them.
|
||||
assert all((u.unaccounted, u.double) == (0, 0) for u in units)
|
||||
assert not any(u.clean for u in units)
|
||||
assert gate.refused_whole(inventory["documents"], build) is not None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ def test_the_door_writes_the_accounting_into_the_log(tmp_path: Path) -> None:
|
|||
_, bundle, _ = _build(CORPUS, tmp_path, "--accounting", str(tmp_path / "a.json"))
|
||||
log = (bundle / "log.md").read_text(encoding="utf-8")
|
||||
assert "* **Accounting**: 20 document(s) and 2 other file(s);" in log
|
||||
assert "6 unaccounted, 0 double-booked." in log
|
||||
assert "6 unaccounted, 0 double-booked; 0 of 20 document(s) refused whole." in log
|
||||
|
||||
|
||||
def test_a_rejected_document_is_logged_with_what_its_source_held(tmp_path: Path) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue