Skip to content

fix(economic): the debit locator is a Transfer fact; live DLV cutover recorded as blocked - #745

Merged
cryptskii merged 1 commit into
mainfrom
fix/transfer-only-debit-locator
Aug 29, 2026
Merged

fix(economic): the debit locator is a Transfer fact; live DLV cutover recorded as blocked#745
cryptskii merged 1 commit into
mainfrom
fix/transfer-only-debit-locator

Conversation

@cryptskii

Copy link
Copy Markdown
Collaborator

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_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 (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 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 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)

Core DLV economics                       Live DLV routing
    Create write set     PROVEN              dlv.create    BLOCKED
    Close write set      PROVEN              dlv.close     BLOCKED
    Settle    0x0026     PROVEN              dlv.settle    BLOCKED (transitively)
    Owner apply 0x0027   PROVEN              dlv.reconcile BLOCKED (transitively)

Two independent blockers, either sufficient on its own:

  • A — existing identities carry legacy device-state balances, so validated_root_or_activate refuses with UnsupportedLegacyEconomicState and admission never reaches build_write_set.
  • B — a fresh identity can legitimately bootstrap ERA through the faucet's finite ticket allocation, but there is no legitimate second-asset source into R_econ, and DlvCreateFundedV2 needs two admitted balance pre-leaves of two DISTINCT assets.

Every other origin into a validated lineage is closed by construction, deliberately: CreateToken with initial_supply > 0 is refused at write_set.rs:397, Mint yields IssuancePredicateUndefined, the AuthorizedIssuance arm fails closed because class 0x0029 is unwritten, ValidatedPeerDebit is recursive, and SameTransitionMove is same-asset.

Measured empirically before stopping: with dlv.create admission-gated, 19 of 24 dlv_routes tests 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 to dsm-test while only dsm-testnet resolves. 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

NO synthetic admitted heads          NO test-only provenance
NO "both legs ERA"                   NO implicit legacy snapshot
NO 0x0029 invented to unblock a PR   NO second faucet/bootstrap invented to save tests
NO bypass around validated_root_or_activate

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_econ history.

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_births and a_close_round_trips_and_leaves_terminal_zero_reserves_present build against explicitly constructed valid pre-states and round-trip through the builder, verify_mutation_sequence, and verify_operation_write_set, alongside their near-miss and pre-state refusal controls.

Boards (exact CI commands, final tree, pinned 1.98.0)

  • Workspace: cargo test --locked --workspace --exclude dsm_storage_node -- --nocapture --test-threads=13896 passed / 0 failed across 71 suites (dsm lib 1675/0, dsm_sdk lib 1792/0 + 7 ignored), exit 0
  • Node (repo root): cargo test --locked -p dsm_storage_node --no-default-features --features local-dev,strict -- --nocapture270 passed / 0 failed, exit 0
  • make lint (repo root) — exit 0; pinned repo-root cargo clippy --all-targets — exit 0
  • bash ci/production_safety_checks.sh — exit 0

…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.
@cryptskii
cryptskii merged commit 40eca6f into main Aug 29, 2026
18 checks passed
@cryptskii
cryptskii deleted the fix/transfer-only-debit-locator branch August 29, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant