jcp-receipt: Seal a flow verdict as jcp/3 #41

Closed
dcharlot wants to merge 1 commit from jcp-receipt-flow-seal into jcp-runtime-flow-gate

2026-07-22

Transaction Science
jcp-receipt: Seal a flow verdict as jcp/3
The runtime gate decides a call against its argument's provenance; this makes
that decision a sealed, replayable artifact. A new jcp/3 profile carries a flow
block — the folded label, its origins and readers, the witness commitment, the
ceiling it was tested against, the below/above verdict, and the monitor's own
evaluation energy — so a third party can see not just that a call was allowed or
denied but on what provenance grounds.

The compatibility property is load-bearing and byte-exact: jcp/3 is minted only
when a call is actually tainted. A clean call — no facts, or facts that were
computed and came back bottom — seals as jcp/2, byte-for-byte identical to the
plain path, so a flow deployment and a non-flow one share a receipt stream and
every existing receipt is unmoved. A test pins that seal_flow of a clean seal
equals seal.

The flow energy is sealed as its own field, flow_uj, never folded into cost_uj:
a call's tool energy keeps its exact meaning, and the cost of running the monitor
is accounted separately and honestly. The witness is a commitment, not the
artifact — the cut is disclosed out of band, so the receipt stays small and the
disclosure boundary stays where jcp-cite already put it.

verify_flow recomputes the jcp/3 core from the same seal, so a jcp/3 receipt
round-trips; a jcp/2 clean call verifies through it too. The chain path
(append_flow) keeps seq/prev identical regardless of profile, so a mixed
jcp/2 + jcp/3 log verifies end to end via verify_log, and extract reads a jcp/3
core generically because it is jcp/2 plus a block. Four tests cover the
byte-identity, the tainted seal and its block, the above verdict on a flow
denial, and the mixed-profile chain.

Deferred, and NOT the plan's §4D fix: replay_spend under-counts a cost-breached
call, but the plan's proposed predicate (count caveat-unsatisfied denies toward
spend) is unsound — a caveat deny debits in the charge path yet not in the decide
path, and the receipt cannot tell them apart, so counting them over-counts the
decide path. The correct fix needs an explicit debited_uj field on the wire, a
separate change with its own compatibility analysis; it is left untouched here
rather than replaced with a broken heuristic.

Increment 4 of the FL-2 plan; the gateway relay that computes the facts and the
receipt-stream replay follow.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 04:17:15 -04:00