Skip to content

v1.108.183 - a receipt says what it proves, and only that

Choose a tag to compare

@jgravelle jgravelle released this 26 Jul 21:06

#377 Phase 2, P1 + P2. Exact immutable evidence receipts, and the producer registration that decides who may mint one. Both together, because an envelope without registration is a contract anything can mint into.

The Phase 1 caveat, closed

handoff._validate_evidence attested a reference matching a served symbol id or the file component of one:

served this session:  src/auth/session.py::refresh_token#function
attests:              src/auth/session.py::refresh_token#function   correct
attests:              src/auth/session.py                           over-broad

A claim citing a whole file was attested when one unrelated symbol from it was the only thing retrieved, and a reader of the finalized handoff could not tell those two citations apart.

What a receipt is

jcodemunch.evidence/v1, read at munch://evidence/<id>. One canonical subject (symbol id, file, line range, content_sha256) bound to one snapshot (index generation, indexed and live revisions, four-state freshness, working-tree state, coverage digest, scorer pin, and the conditions the response was produced under) and to the operation that actually ran, with the id derived from exactly those three. Different snapshot means a different id.

Opt in with receipt: true on search_symbols, get_symbol_source, get_ranked_context or search_text. The response carries only the id in _meta.receipts; the body is read from the resource on demand. No new tool and no INDEX_VERSION change. Default false is byte-for-byte today's response, pinned by a test.

limitations states what a receipt cannot prove. A row served without a body carries an identity, not its bytes, and says so.

Producer registration is the load-bearing half

get_ranked_context once asserted "Do not claim this feature exists" from an early return that never called build_verdict, so eight shipped absence gates were invisible to it until 1.108.179 went looking. An early return is a second implementation of the answer and inherits nothing.

Registration makes that structural rather than remembered: minting requires a verdict of the shape the producer registered, so an exit that asserts an answer without building one cannot mint. Not as a listed exception, but because it never produced the thing a receipt is derived from. Minting also runs at the dispatcher chokepoint, so an early return cannot bypass it at all.

The input picks the contract

A handoff citing no receipt keeps the historical broadening and renders byte-identically, so no shipped caller changes. What it gains is that the finalization receipt now names the broadened reference and what backed it (evidence_precision, broadened_refs).

A handoff that does cite a receipt is held to the subject its evidence proves: a file-level reference backed only by a served symbol from that file is refused as over-broad, with its own error and its own fix.

Notes worth reading

  • Phase 3 refs keep working. An absence receipt links to the scan note_absence recorded rather than re-deriving whether it proves anything, so absence_refusal stays the single implementation of the refusal rules and a receipt read hours later cannot disagree with the gate that issued it.
  • build_symbol_verdict reports channels.index: fresh for a plain folder that has no revision at all, because it never got the four-state treatment. A get_symbol_source receipt therefore probes freshness directly; trusting that channel would repeat the 1.108.176 mistake of believing a signal that answers a slightly different question.
  • A hidden-but-honored argument was being reported as a caller mistake. compact_schemas strips rarely-used params from the published schema while the handler still accepts them, and it popped them out of the same dicts the argument contract was built from, so source_start_line and friends were flagged as ignored arguments under that setting, which downgrades the verdict and costs a well-formed call its absence evidence. Fixed by snapshotting the declared surface before the strip.
  • Not shipped, so nobody builds on it: session keying, the rest of the expiry taxonomy and finalization deep-freeze (P3); redacted rendering and the absence_scans_attested rename (P4); suite parity for jdocmunch and jdatamunch (P5).
  • Two ungated absence assertions found and not fixed here: search_symbols's semantic exit asserts absence in prose with no verdict at all, and both fusion exits emit neither. Neither can mint, which is the gate working, and tests pin that against the source.

Design by @mightydanp on #377. Suite 6025 passed plus a known 12 local-ONNX environment failures that are green in CI; Tests 9/9 and Replay green before publishing. core_compact unchanged at 3996.