fix(economic): the debit locator is a Transfer fact; live DLV cutover recorded as blocked - #745
Merged
Merged
Conversation
…fer fact `build_dsm_admission` derived `debit_mutation_index` by scanning the built write set for the first mutation whose amount fell. That scan is exact for the one shape it exists to serve — an online Transfer sender's write set has exactly one balance debit, and the online-transfer wire is its only consumer — and silently wrong for any multi-leg write set, where it names one arbitrary leg. It is now structurally confined to `Operation::Transfer`; every other operation yields `None`, so a caller needing a locator for one of them gets no answer rather than a wrong one. No observable behaviour changes today: nothing reads the value for a non- Transfer operation, so Burn and the CreateToken fee simply stop carrying a `Some(0)` that was never true of anything. This removes a wrong-by-construction value rather than fixing a live defect, and turns a hazard the 3.6 plan carried as a comment into one the type system carries. Also records the live DLV routing boundary. Exploring the 3.6 create/close admission cutover established that it cannot proceed: `DlvCreateFundedV2` requires two admitted balance pre-leaves of two DISTINCT assets, and only ERA can currently enter a validated lineage. The route scaffolding built during that exploration was reverted rather than shipped — unreachable code that looks implemented is worse than an honest gap. Core DLV economics stay complete and proven (#740-#744); only the producer side is blocked.
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 debit locator is a Transfer fact — and the live DLV cutover is blocked
Two things, both outcomes of exploring the 3.6 create/close admission cutover: one small correction worth keeping, and the recorded boundary explaining why the cutover itself is not here.
The correction
build_dsm_admissionderiveddebit_mutation_indexby scanning the built write set for the first mutation whose amount fell. That scan is exact for the one shape it exists to serve — an onlineTransfersender's write set has exactly one balance debit, and the online-transfer wire is its only consumer (wallet.send) — and silently wrong for any multi-leg write set, where "the first amount that fell" names one arbitrary leg. A funded vault creation debits two balances; a close draws down two reserves.It is now structurally confined to
Operation::Transfer. Every other operation yieldsNone, so a caller needing a locator for one of them gets no answer rather than a wrong one.No observable behaviour changes today. Nothing reads the value for a non-Transfer operation, so
Burnand theCreateTokenfee simply stop carrying aSome(0)that was never true of anything. This removes a wrong-by-construction value and moves a hazard the 3.6 plan carried as a prose comment into the type system; it does not fix a live defect, and it is not presented as one.The boundary (
docs/plans/2026-08-29-live-dlv-cutover-blocked-on-second-asset-origin.md)Two independent blockers, either sufficient on its own:
validated_root_or_activaterefuses withUnsupportedLegacyEconomicStateand admission never reachesbuild_write_set.R_econ, andDlvCreateFundedV2needs two admitted balance pre-leaves of two DISTINCT assets.Every other origin into a validated lineage is closed by construction, deliberately:
CreateTokenwithinitial_supply > 0is refused atwrite_set.rs:397,MintyieldsIssuancePredicateUndefined, theAuthorizedIssuancearm fails closed because class0x0029is unwritten,ValidatedPeerDebitis recursive, andSameTransitionMoveis same-asset.Measured empirically before stopping: with
dlv.createadmission-gated, 19 of 24dlv_routestests go red (my static estimate of 7 undercounted — most reach the chokepoint through helpers), failing first at register-profile resolution because the DLV fixture is pinned todsm-testwhile onlydsm-testnetresolves. Fixing that only exposes blocker A, and fixing that only exposes blocker B.The route scaffolding built during exploration was reverted, not shipped. Unreachable code that looks implemented is worse than an honest gap.
What must not be done to unblock it
The DLV route tests that fail under a cutover are not a security problem and must not be "fixed" — they correctly show that the present market setup depends on balances with no admissible
R_econhistory.When an honest second-asset origin exists (its own design, its own decision), beta exercises the live path on fresh identities funded through admitted origins. No legacy migration protocol is required or wanted, and balance-loaded identities continue to fail activation by design.
Already proven, unchanged
The core valid-pre-state proofs this boundary rests on landed in PR1 and are untouched:
a_funded_create_round_trips_two_debits_and_two_reserve_birthsanda_close_round_trips_and_leaves_terminal_zero_reserves_presentbuild against explicitly constructed valid pre-states and round-trip through the builder,verify_mutation_sequence, andverify_operation_write_set, alongside their near-miss and pre-state refusal controls.Boards (exact CI commands, final tree, pinned 1.98.0)
cargo test --locked --workspace --exclude dsm_storage_node -- --nocapture --test-threads=1— 3896 passed / 0 failed across 71 suites (dsm lib 1675/0, dsm_sdk lib 1792/0 + 7 ignored), exit 0cargo test --locked -p dsm_storage_node --no-default-features --features local-dev,strict -- --nocapture— 270 passed / 0 failed, exit 0make lint(repo root) — exit 0; pinned repo-rootcargo clippy --all-targets— exit 0bash ci/production_safety_checks.sh— exit 0