feat(2c-F): the Def 14.2 SofiReceipt — frozen rulings, 0x0034, and a publication obligation that never gates the release - #859
Merged
Conversation
The owner ruled 2026-09-11 on the draft merged as #858. This records the rulings verbatim and carries them into the normative text, before the code that implements them. - 2c-F: status FROZEN; the four answers quoted; two corrections applied in place — S_v is the authenticated consumed parent's committed set, never one read off B's proposed successor, and proof material never refuses a receipt. Recovery replays the frozen bytes and never re-certifies. R2, R4 and R7 had no competing option and are adopted as proposed. - Spec: Def 14.2 is SofiReceipt with rho_B under DSM/sofi-receipt/v1 and the publication set {receipt, B, A_B}; Req 14.6-14.10 (quorum over the authenticated S_v, ordering, determinism, recovery, non-authority); §9.3 and §7.2 ratify X = H(DSM/ext ‖ RC*); §16.2 re-quotes instead of retrying a pre-committed alternative; the tag table retires DSM/route-set. - Registry: 0x0034 SofiReceipt (§5.42, 137 bytes); 0x000C and 0x0017 burned; §2.10 names RC* as a second foreign grammar, on its own ground; §4 counts; stale TradeIntent field citations (I-1) and schema headings (I-2) corrected. - 2c-D: C2-R1 point 9 marked discharged; I-3 (the Rev 15 text is in-repo). - 2c-A Ruling 2: Q is the signed RouteCommit that B already carries.
… of (B, TA_B) dsm::dlv::sofi_receipt: a pure projection of the canonical market bundle and the certified acceptance identity — b, X, a_B, and one successor commitment per transition with witness_hash always absent in schema 1. It carries no signature, entropy, clock or node order, so every holder of (B, TA_B) produces identical bytes. It has a strict decoder, and verify re-derives and compares field by field; neither is authority for anything (2c-F R7). Proof material never refuses a receipt. - TAG_DSM_SOFI_RECEIPT_V1 = "DSM/sofi-receipt/v1", registered (count 350). DSM/receipt stays the stitched receipt: its recovery rollup already reaches sealed capsules and signed tombstones. - ccb: class 0x0034 allocated; RouteSet 0x000C and RouteCommitmentBody 0x0017 move from declared_unencoded to burned_class (R1 ratified the shipped X). - Class-1 vectors: the 137-byte receipt of the pinned market bundle, from the pinned identities alone; and RC* -> X from hand-written protobuf bytes, so a protobuf-library refactor that moved X is caught.
…gates the release
After the walk certifies a market settlement, complete_settlement projects the
SofiReceipt from the certified fold's own acceptance, and freezes the closure
{receipt, CCB(B), CCB(TA_B)} for the composed V_n's committed storage set,
before the release step. The generic sweep then publishes it. A failure to
project or freeze is logged and never holds the fence. Publication may land
after the release. Nothing re-fences, re-binds, re-admits or re-certifies
(owner ruling on R6).
- FoldedParent carries certified_acceptance: the exact TA_B 2c-D §7 accepted,
so the receipt is built from what certified.
- MarketCompletion carries CCB(B); both the settle route and D-f supply it.
- sofi_receipt_publication: closure / freeze / publication. publication()
reports BoundToAnotherSet rather than counting another set's quorum as the
vault's (I-5; unreachable in beta).
- Tests: the published receipt is exactly the projection, frozen for the
vault's own set; with receipt PUTs refused the fence still releases, and the
sweep alone publishes afterwards with no binding round and no transition; an
uncertified settlement has no receipt.
- Mutation controls MS1-MS3 executed: each named test red, each source
restored and cmp-verified.
The 19th Lean module restates C2's completion pass with the 2c-F obligation and proves: - the fence follows C2's rule alone, and neither the receipt's state nor its reachability moves it; - a receipt obligation is created only by a certified pass; - the sweep alone finishes a frozen obligation, after the release, and touches nothing else; - a second pass and a second sweep change nothing. The samples show a release with the receipt still owed and the sweep then publishing it. Two mutation controls were executed, each with the kernel proving the named sample false. CI Lean pin 18 -> 19.
cryptskii
added a commit
that referenced
this pull request
Sep 11, 2026
…ever lost (#860) The owner's merge condition on #859: once a settlement has certified, a failure to construct, freeze or publish its Def 14.2 receipt may delay evidence, but must never permanently lose the obligation. The receipt still never gates the fence. The durable facts already survived a crash, but nothing read them. A released trader fence is the durable record that certification happened: Released is reachable only through SuccessorAccepted, which only the certified completion records, and the row carries addr(B) and the bind set. CCB(B) is at quorum from before binding, and this device's own admission froze TA_B and its locator locally. Before this change, D-f listed only unreleased fences and the sweep replayed only rows already frozen, so a failed freeze followed by a release and a crash lost the obligation. - recover_owed_receipts, run from storage.sync beside D-f: for each released fence on the device's own market chain that has no receipt row for b, it rebuilds the byte-identical closure. B is fetched by b and checked against the fence's addr(B); S_v is the fence's set and must match B's successor; TA_B is the device's own, re-hashed, and must accept exactly b. It never composes, binds, advances, admits or touches a fence. - The three-row closure freeze is atomic (savepoint), so a receipt row always means all three are recorded. - list_released_fences; find_artifact_by_purpose_and_bound_root; immutable_object_key_for_inner (one key format). - Tests: the restart test (A-H, J) with an injected freeze failure and a second router over the same database; the substitution test (I); the part-way-failure rollback. - Lean DSMSofiReceipt: the freeze may fail without moving the fence; recovery records the obligation once the fence is released (L3 control executed). - 2c-F §7.3 and spec Req 14.9 record the answer and the mechanism. (cherry picked from commit f0b14ac)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
2c-F — the Def 14.2 settlement receipt, frozen and implemented
This implements the owner's 2026-09-11 rulings on the 2c-F draft (#858). The first commit freezes them: they are recorded verbatim in
docs/papers/amendment-2c-f-sofi-receipt-rulings.mdand carried into the spec and the registry. The later commits implement them. There are no other changes.Rulings → implementation
X = H(DSM/ext ‖ RC*). No bytes move.Qis the signed RouteCommit thatBalready carries.0x000Cand0x0017are burned.ccb/mod.rs; registry §2.10 (exception 2), §3, §5.12, §5.14; spec §7.2, §9.3, §16.2B's pre-bind durability stays pre-bind. "After certification" applies to the SofiReceipt only.DSM/sofi-receipt/v1.DSM/receiptstays the stitched receipt, which signed tombstones already depend on.domain_tags/dsm/core.rssuccessor_hash = c_{n+1}.witness_hashis always absent in schema 1, and proof material never refuses a receipt.dlv/sofi_receipt.rs0x0034 SofiReceiptschema 1, 137 bytes.S_v, never a set read offB.B's existing durability counts when it was achieved over that set.sofi_receipt_publication.rs;complete_settlementfreezes forcomposed.storage_set_idcomplete_settlement;DSMSofiReceipt.leanpublication()is a report onlyR2, R4 and R7 had no competing option in the draft. They are adopted as proposed and are open to objection before merge.
How the obligation works
After the walk certifies exactly
b,complete_settlementprojects the receipt from the certified fold's ownTA_B. The fold now carries it ascertified_acceptance. The pass then freezes{receipt, CCB(B), CCB(TA_B)}for the composedV_n's committed set, before the release step. The generic sweep publishes those exact bytes. A projection or freeze failure is logged, never returned, so C2's release condition is unchanged. A receipt can only be built from a certified fold, because the acceptance it binds exists nowhere else.One set per frozen row (I-5). If
TA_Bwas admitted under a different set thanS_v,publication()reportsBoundToAnotherSetrather than counting that set's quorum. In beta every consumer resolves the one catalog set, so this case cannot occur. Per-set rows are left owed.Mutation controls — executed
the_def_14_2_receipt_never_gates_the_release_and_publishes_after_ita_realized_settlement_publishes_its_def_14_2_receipt_on_the_vaults_seta_Bother than the certified acceptance'sverify), anda_closure_is_a_pure_projection_of_its_inputsthe_release_does_not_wait_for_the_receiptproved falsean_uncertified_settlement_has_no_receiptproved falseEach source was restored from a byte copy and verified with
cmp. The first attempt at MS3 did not compile (an unused binding), so it was discarded and re-run with a mutation that compiles; the table shows the re-run.Merge condition (owner, 2026-09-11) — a lost obligation is never lost
In the first version, a failed receipt freeze was logged and the fence still released. D-f lists only unreleased fences, and the sweep replays only rows that are already frozen. So a failed freeze followed by a release and a crash lost the obligation. The owner's question — what durable state lets a restarted process rediscover it — was answered from source before any code changed (2c-F §7.3):
Releasedis reachable only throughSuccessorAccepted, whose sole production caller is the certified completion. Fence rows are never deleted, and the row carriesaddr(B)and the bind set.CCB(B)has been at quorum since before binding.TA_Band its locator locally.recover_owed_receiptsruns fromstorage.sync, beside D-f. For every released fence on the device's own market chain that has no receipt row forb, it rebuilds the byte-identical closure from those facts:Bis fetched byband must sit at the fence'saddr(B).S_vis the fence's set, and must equal the setB's successor commits.TA_Bis this device's own, re-hashed, and must accept exactlyb.It never composes, binds, advances, admits or touches a fence, and needs no signing key. The three-row freeze is now atomic (a savepoint), so a receipt row always means all three are recorded. The fence still never waits on any of this.
a_receipt_whose_freeze_failed_is_recovered_after_release_and_restart: an injected freeze failure; the fence still releases; a second router over the same database recovers a byte-identical receipt; it is published on the vault's set; a second pass does nothing; fence, frontier, head and binding log are unchangeda_recovered_receipt_cannot_be_rebuilt_from_substituted_facts: anotheraddr(B), another storage set, or a locator naming another bundle's acceptance are each refused, with nothing frozena_closure_that_fails_part_way_freezes_nothingbBcommitsBneed not sit at the fence'saddr(B)a_lost_obligation_is_rebuilt_after_releaseproved falseVerification
All runs used the pinned
1.98.0toolchain and--release, targeted by module per project policy. CI is the board.make lint(fmt + clippy--all-targets)ci/production_safety_checks.shsofi_receipt,domain_tags,ccb::settlement_bundle_conformance(full binary)route_commitment_x_conformance(new)handlers::dlv_routes,sdk::vault_state_composition,handlers::artifact_republish,sdk::sofi_receipt_publicationdlv_regression_guards+vault_funding_routesDSMSofiReceipt.lean(-DwarningAsError=true, v4.23.0)propextonly; nosorryAxhandlers::storage_routes(sync now runs the recovery pass)dlv_regression_guards+vault_funding_routesmake lint+ci/production_safety_checks.shThe first
make lintfailed on rustfmt alone, and that hid clippy. Clippy then found two no-op..Default::default()struct updates and one needlessmut, all in new dsm test code; all three are fixed. The dsm_sdk suites ran on the tree before rustfmt. The only changes since are whitespace and those dsm test-only fixes, and lint, the safety checks and the affected dsm tests were re-run on the final tree.The existing D-f suite, including the resume test that asserts "every PUT the resume made is the receipt", passes unchanged: the receipt closure is published during the settle pass, not the resume.
Not in this PR
docs/plans/2026-04-24-*.md"DeTFi → SoFi" edits that appeared in the working tree from an unknown source. They were left untouched and excluded.