fix(accounting,gate): the conversion claim comes from the run's ledger
Chose the side channel over neutralising pointer-shaped document text, because the second fix changes what every document SAYS in order to defend a tool outside the build: a source quoting a bundle listing would come out altered and existing bundles would move bytes. This reads a file the run already writes. `assets.conversion` names the pair, `DocumentAssets.conversions` carries it out of the run, `DocumentAccount.conversions` books it, and the accounting JSON states it per document. `_declared_conversions` reads it; `_conversions` now believes a pair only when the RUN booked it AND a pointer block confirms it for the asset it names. The confirmation can be forged and the ledger cannot, which is why the ledger decides. Measured through the real `okf build`: the three arms PM reproduced (two `<p>`, one `<p>` with `<br>`, a markdown note beside the carrier) go forged -> refused, 3 of 3, with the known-positive True in all three. The text-level regression guard goes 3 arms to 13, the two new ones being a perfectly written pointer block the run never booked. R761, rebuilt: 25 BMP sources, 19 held, 19 of 19 conversions confirmed against 19 declared, 50 assets (29 JPEG + 21 PNG, 0 BMP), SHY 71, u = 0, d = 0, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa2abe8293
commit
1c958ab8d6
5 changed files with 226 additions and 59 deletions
|
|
@ -887,6 +887,23 @@ def digest(data: bytes) -> str:
|
|||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def conversion(image: ExtractedImage) -> tuple[str, str] | None:
|
||||
"""`(the source's digest, the carried asset's digest)`, or `None`.
|
||||
|
||||
THE RUN'S OWN RECORD OF WHAT IT REWROTE, for a reader that must not have
|
||||
to take the bundle's word for it. `render_block` states the same pair on
|
||||
the pointer's second line, which is where a person reads it -- but that
|
||||
line is markdown in a concept body, and measured by PM 2026-09-19 an
|
||||
ordinary HTML document with two `<p>` elements produces the same two
|
||||
lines. A judge reading the claim off the bundle text is therefore reading
|
||||
an untrusted document; a judge reading it off the accounting is reading
|
||||
this function's output, which no document can reach.
|
||||
"""
|
||||
if image.converted_from is None or image.source_sha256 is None:
|
||||
return None
|
||||
return (image.source_sha256, digest(image.data))
|
||||
|
||||
|
||||
def _reduce(text: str) -> str:
|
||||
return _SEPARATOR_RUN.sub("-", unicodedata.normalize("NFC", text).lower()).strip("-")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue