test(accounting-gate): the published door contract is behind the gate, and a doorless bundle is silent

RED, 3 of 117 on assert about behaviour, 0 on import.

Two rests from PM's checkpoint on 44ad845, both about what a reader OUTSIDE
this repository is told.

The contract sketch in the gate's own module docstring is what a consumer
implements the `--accounting` door from. It does not name `conversions`,
which the gate now DEPENDS on, nor `normalised_soft_hyphen`, `unaccounted`
or `double_booked`, which the door has written for longer. A consumer
following it writes a ledger this gate reads as "nothing was converted", and
every converted image in their bundle is reported claimed-and-not-found.

The first test measures what the gate READS rather than what its source
mentions: the ledger is handed to `_declared_conversions` as a mapping that
records every lookup at any depth, so the assertion is about lookups and not
about grep. The second measures the other direction, from the DOOR's own
serialisation, so the fix cannot be "publish everything": contract and
output must be the same set.

The third is N5. Without the door there is no ledger, so a converted image
cannot be proved carried and is counted claimed-and-not-found -- the reading
the ledger round removed, back again for every reader who builds without the
flag, and stated nowhere. Asserted through `row3`, not through a signature
that does not exist yet, so the red is behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-19 22:51:54 +02:00
commit 7e5248aa84
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q

View file

@ -1790,3 +1790,122 @@ def test_the_real_gate_names_what_the_build_does_not_account_for(
# And no false red from the gate's own reading: every element the build
# DOES book as carried was found in the bundle.
assert "0 claimed and not found" in real_rows[2].details[0]
# --- the published door contract, and what it leaves a consumer to guess -----
class _Watched(dict): # type: ignore[type-arg]
"""A mapping that records which keys were LOOKED UP, at any depth.
The question the test below asks is not "which keys does the gate's source
contain" -- that is grep, and it reads a rejection code as a JSON key. It
is "which keys does the gate take out of a run's accounting". So the gate
is handed a ledger that answers normally and writes down every lookup.
"""
def __init__(self, data: dict[str, Any], seen: set[str]) -> None:
super().__init__(data)
self.seen = seen
def _wrap(self, value: Any) -> Any:
if isinstance(value, dict):
return _Watched(value, self.seen)
if isinstance(value, list):
return [self._wrap(item) for item in value]
return value
def get(self, key: Any, default: Any = None) -> Any: # type: ignore[override]
self.seen.add(key)
return self._wrap(super().get(key, default))
def __getitem__(self, key: Any) -> Any:
self.seen.add(key)
return self._wrap(super().__getitem__(key))
def _contract_keys() -> set[str]:
"""Every key named in the JSON sketch of the gate's module docstring."""
doc = gate.__doc__ or ""
start = doc.index('{"accounting_version"')
end = doc.index("`inventory` is taken BEFORE")
# Keys, never values: the sketch writes `"status": "persisted" | "rejected"`,
# and a regex that cannot tell those apart would demand the door write a
# key called `persisted`.
return set(re.findall(r'"([a-z_]+)":', doc[start:end]))
def test_the_published_contract_names_every_key_the_gate_reads() -> None:
"""The door contract this module publishes is what a consumer implements.
Measured by PM on `44ad845`: `conversions` was absent from the sketch while
`_declared_conversions` had come to depend on it, so a consumer building
the door from the contract writes a ledger this gate reads as "nothing was
converted" -- and every converted image in their bundle comes out
claimed-and-not-found. `normalised_soft_hyphen` was missing too, older
drift by a round.
"""
seen: set[str] = set()
ledger = _Watched(_ledger(("a" * 64, "b" * 64)), seen)
gate._declared_conversions(_build(accounting=ledger))
assert {"documents", "conversions", "from", "to"} <= seen, seen
published = _contract_keys()
assert seen <= published, (
f"the gate reads keys the contract does not publish: {seen - published}"
)
def test_the_published_contract_names_no_key_the_door_does_not_write() -> None:
"""The other direction, so the fix cannot be "publish everything".
The keys come from the door's own serialisation rather than from a list
written here: a contract is only worth reading if the run it describes
writes exactly that.
"""
from llm_ingestion_okf import accounting as door
account = door.Accounting(
documents=[
door.DocumentAccount(
source_file="a.md",
status="persisted",
code=None,
counts={"paragraph": 1},
fates={"paragraph": door.Fate(carried=1)},
conversions=(("a" * 64, "b" * 64),),
normalised_soft_hyphen=3,
)
],
files=[door.FileAccount("graphics/x.png", "carried", None)],
)
data = account.to_json()
written = set(data) | set(data["documents"][0]) | set(data["files"][0])
written |= set(data["documents"][0]["fates"]["paragraph"])
written |= set(data["documents"][0]["conversions"][0])
published = _contract_keys()
assert written == published, (
f"the door writes keys the contract omits: {written - published}; "
f"the contract names keys the door does not write: {published - written}"
)
def test_a_bundle_with_no_ledger_says_why_a_converted_image_cannot_be_proved() -> None:
"""N5: without the door, `asset_holds` falls back to its first route alone.
That is the honest reading, and until now it was a silent one: the images
concerned are counted as claimed-and-not-found with no statement that the
run carried no ledger to prove them by. R761 read 19 that way the day
before the ledger existed. The gate itself always passes the flag, so this
is for every OTHER reader of a doorless bundle.
"""
claimed = [
gate.Unit(name="a.md", kind="document", unaccounted=0, double=0, verified=1, unverified=2)
]
found = [gate.Unit(name="a.md", kind="document", unaccounted=0, double=0, verified=1)]
said = " ".join(gate.row3(claimed, door=False).details)
assert "no `--accounting` ledger" in said, said
# Two known-negatives, so the sentence is conditional and not decoration:
# a run WITH the door proves its conversions, and a run with nothing
# claimed-and-not-found has no unproved image to explain.
assert "no `--accounting` ledger" not in " ".join(gate.row3(claimed, door=True).details)
assert "no `--accounting` ledger" not in " ".join(gate.row3(found, door=False).details)