fix(2c-F): a lost receipt obligation is rediscovered after release — the #859 merge condition - #860
Merged
Merged
Conversation
…ever lost 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.
The #859 merge condition — a lost receipt obligation is never lost
Why this is a separate PR. The owner's ruling made this change a precondition for merging #859. #859 merged at
f29284c5, but this commit (f0b14ac2) reached the branch after the PR object's head was fixed, so it is not inmain../scripts/check-pr-head-sync.sh 859reports exactly that divergence. This PR carriesf0b14ac2cherry-picked unchanged ontomain, following the recovery the script prescribes, as was done for #699 and #701.Until this merges,
mainhas the behaviour the owner blocked on: a failed receipt freeze is logged, the fence releases, and a crash then loses the Def 14.2 publication obligation.The question, answered from source before any code changed (2c-F §7.3)
After certification, a failed receipt write, a release and a crash — what durable state lets the next process discover the owed publication?
Releasedis reachable only throughSuccessorAcceptedcarrying the exact permitted successor. Its sole production caller iscomplete_settlement's release step, which runs only aftermay_certify()for exactlyb. Fence rows are never deleted, and each carriesaddr(B)and the bind set.CCB(B)has been at quorum since before binding.TA_Band its locator locally.Nothing read those facts for this purpose: D-f lists only unreleased fences, and the sweep replays only rows already frozen.
The mechanism
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: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 closure 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, as ruled.
Tests (the owner's A–J)
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_nothingMutation controls — executed
bBcommitsBneed not sit at the fence'saddr(B)a_lost_obligation_is_rebuilt_after_releaseproved falseEach source was restored from a byte copy and checked with
cmp.Verification (pinned 1.98.0,
--release, targeted)handlers::storage_routes(sync now runs the recovery pass)dlv_regression_guards+vault_funding_routesmake lint+ci/production_safety_checks.shDSMSofiReceipt.leanwith freeze failure + recoveryCI is the board.