Skip to content

predict: envelope (interval) arithmetic for derived contract values (DBU-628)#1154

Draft
0xaslan wants to merge 13 commits into
mainfrom
at/predict-interval-arithmetic
Draft

predict: envelope (interval) arithmetic for derived contract values (DBU-628)#1154
0xaslan wants to merge 13 commits into
mainfrom
at/predict-interval-arithmetic

Conversation

@0xaslan

@0xaslan 0xaslan commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Every derived value in the Predict contracts — boundary prices, range probabilities, walk liabilities, corrections, reserves, free cash, market NAV, pool value — is computed as a sound envelope (fixed_math::interval::Interval{lo,hi}: the true value provably inside, maintained by directed rounding), with persistent storage kept exact-scalar and every envelope→scalar collapse an explicit site with an economically chosen side.
  • New fixed_math surface: the directed pair mul_up/div_up and the interval module (no store ability — envelopes are transaction-local by the type system).
  • Trade lanes commit at doctrine corners: the mint tuple commits jointly at the protocol-favored corner with its integer identity exact (entry_value = mul_up(P.hi, Q), net_premium = div_up(E, lev), floor_shares by identity; 1x zero-floor structural); redeems commit at the low corner; the trading fee now rounds up (protocol inflow); admission gates are definite-in-band; the liquidation knock-out test reads the gross envelope's low side through one predicate shared by the close classifier, the ambient sweep, and the flush scan.
  • The pool flush runs entirely on envelopes: interval price memo (guard aborts only on definite surface inversion), interval walks and kill scan, per-market NAV as the per-corner defined quantity max(0, free_cash − liability), corner-wise lp_pool_value, and a two-mark drain — supply queue at the pool value's high bound, withdraw queue at its low bound, per-side executability. FlushExecuted publishes the (lo, hi) mark pair; the width is the flush's bid/ask spread.
  • Backing asserts and surplus releases compare the definite (high) side of every hold (required_cash_hi).
  • Design doc: packages/predict/predeploy/interval-arithmetic.md (definitions, storage classes, collapse taxonomy, side doctrine, abort inventory).

Why

  • Setting: Predict prices digital range options with fixed-point math and marks an LP pool whose one frozen NAV mark prices both share supply and share withdrawal each flush.
  • Problem: scalar rounding produced a recurring defect class — silent one-unit bias toward or against the pool, dust underflows able to abort settlement or valuation paths, and rounding-direction proofs that couple distant code so one edit silently invalidates another expression's safety argument. The single-scalar mark also structurally cannot favor both supply and withdrawal at once.
  • Trigger: the NAV dust-invariant unwind — proving subtractions safe one at a time did not scale, and the mark-direction conflict has no scalar solution (DBU-628).

Key decisions

  • Soundness once, not per site: the interval library is property-verified (directed rounding, truth containment, width laws); call sites never re-argue arithmetic safety. Aborts fire only on definite violations of the oracle vendor's monotone-surface guarantee — the flush-lane abort inventory is enumerated in the design doc and none is reachable through rounding or any admissible book.
  • Storage cannot hold widths: Interval has no store ability; stored values are exact atoms, realized commitments, or defined recurrences.
  • Public API criterion: transact-answers return the committed scalar; worth-answers return primitive (u64, u64) bounds; the envelope type never enters a public signature.
  • Pool value is evaluated corner-wise, justified by a monotonicity argument (slope 1 or 1−share; the integer floor only absorbs steps), so the gross and exclusion terms cannot double-count width.
  • The evaluation-error tiers on up_price are measured against an independent float64 reference across the admissible SVI envelope (saturated/healthy/degenerate = 8/48/1e6 raw at the 0.01 total-variance threshold, ≥2.5× pad over p99); an analytic certificate is planned hardening.

Scope / Descoped

  • DRAFT for contract-shape review. Deliberately not here: unit-test re-pin (33 expectations assert pre-envelope values and the plp flow tests reference pre-envelope signatures — CI is known-red), gas measurement of the interval flush, the scalar read-lane disposition (superseded scalar flush lane still present, no production callers), sibling fee sides (builder fee, congestion penalty), oracle confidence as input width, and the oracle-surface tolerated-domain work.
  • Stacked on predict: value knocked-out orders at liquidated worth in the NAV correction (DBU-605) #1153 (liquidate-during-flush): base is at/dbu-605-liquidate-during-flush, so this diff shows only the envelope work.

Test plan

  • sui move build --path packages/predict --warnings-are-errors clean; packages/fixed_math suite 159/159 green (new interval property tests included)
  • packages/predict/predeploy/check.py — 0 warnings
  • Unit-test re-pin (separate phase; known-red set enumerated in the commit message)
  • Localnet gas measurement of the full-pool interval flush (separate phase)

Pricing finalization (follow-up commits)

The interval valuation lane needs a sound pricing envelope. These commits finalize how one up_price evaluation is bounded:

  • High-precision variance path. compute_nd2_terms computes total variance, sqrt(w), and d2 in u128 at 1e18 instead of flooring the b*inner product to 1e9. That flooring discarded the entire signal at short expiry (a 5-minute surface has total variance ~1e-8, about ten raw units at 1e9), inflating pricing error to ~0.4%. It now stays near the arithmetic floor.
  • One certified widen. The scalar price is widened by a single constant (up_price_evaluation_error, 3e-4) to form the sound interval. One value suffices because the admission gate bounds the pricing error across the whole admitted domain; a variance-keyed table was removed as premature and, as reviewed, unsound at mid-variance.
  • Admission gate + tight caps. assert_inputs_pricing_safe enforces beta^2 <= 9 * min_tv (skew vs variance, keeping the skew correction clear of the [0,1] clamp) and tight SVI caps (|a|,|m|,sigma <= 1, b <= 0.1) so the deep-ITM/OTM digital-limit saturations are genuinely exact. Real Block Scholes surfaces clear every bound with wide headroom.
  • Certificate. packages/predict/predeploy/pricing_error_certificate.py is a self-contained harness (fixed-point mirror vs mpmath, verified leaf constants, the gated-box error envelope over the full moneyness range) documenting how the widen, gate, and caps were derived.

Reviewed by two independent passes (a fresh reviewer and a codex subagent); the low-level fixed-point mechanics are confirmed correct. The unit-test suite compiles against the interval-lane signatures; value expectations re-pin as the next phase. Interval-branch-and-bound verification of the widen is planned hardening before audit.

0xaslan and others added 13 commits July 21, 2026 18:51
… (DBU-605)

The pool flush's NAV mark previously carried liquidatable-but-unswept
leveraged orders (gross in (floor, floor/ltv]) at holder value, understating
recoverable value by up to the LTV buffer and diluting incumbent LPs on a
same-flush supply (open-item P-10, previously accept-and-disclose).

The flush valuation lane now enforces the mark invariant directly: every
active leveraged order at or below its knock-out threshold at the valuation
prices is liquidated in the same pass, so the mark never prices a claim the
protocol would not honor.

- liquidation_book: is_under_liquidation_floor (single-sourced knock-out
  test) and scan_compact — one fused visit of the active leveraged book that
  accumulates the survivor floor correction and compacts killed orders out
  in place, preserving page sort order.
- strike_payout_tree: walk_linear_cached — re-walks the pruned tree reading
  prices from the flush's memo (no re-pricing), with exactly walk_linear's
  rounding and clamp.
- pricing: cached_up_price promoted to package visibility for the re-walk;
  the finite-tick miss-abort is unchanged.
- strike_exposure: revalue_with_liquidations (walk -> scan -> settle each
  kill via the extracted settle_liquidation shared with the close flow and
  ambient sweep -> cached re-walk), returning the main-style clamped
  liability. Zero-kill books return the first walk directly, bit-identical
  to exact_live_liability.
- expiry_market: package-only current_nav_with_liquidations mirrors
  current_nav over the liquidating liability; public current_nav unchanged.
- plp: value_expiry switches to the liquidating lane; quotes and devInspect
  reads stay on current_nav.

Docs: response-policies RP-17 (resolves P-10), P-10 removed from
open-items, risks.md updated to the enforced-exactness framing.

Tests: unit boundary pins on scan_compact (exact-threshold kill, one-unit
survivor, correction_value equivalence, page compaction), walk_linear_cached
bit-identity/prune/miss-abort/clamp pins, and flow pins for kill-during-flush
(mark exclusion, book+tree removal, events, Liquidated holder close),
zero-liquidatable bit-identity with current_nav, and 1x immunity.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
Interval arithmetic needs both directions of every scaled op. mul_up mirrors
the lane's Ring-0 primitive; div_up completes the pair (asserts EInputZero
like mul_div_up). Hand-derived boundary tests for both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…local by ability

Interval{lo,hi} over non-negative 1e9 fixed point: directed add/sub/mul/div,
pointwise min/max, widen for certified error constants. No store ability:
envelopes cannot reach persistent state by construction — storage stays exact
scalars. lo-side underflow clamps to 0 (non-negative domain); only definite
negativity or hi-side overflow aborts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…-regime error tiers

compute_nd2 becomes compute_nd2_terms, returning the total variance it used so
callers can classify the evaluation's conditioning regime (none = pre-variance
ratio saturation on an exact digital limit). up_price_interval widens the scalar
evaluation by the tier bound and intersects with [0, 1]; infinity sentinels stay
zero-width. Scalar up_price/range_price are untouched — valuation lanes migrate
to the interval lane knot by knot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…can, liability

The envelope twins of the flush valuation path, parallel to the scalar lane
(no consumers switched yet): IntervalPriceMemo with the guard weakened to
definite inversion only (envelope-overlapping inversions are honest width);
walk_linear_interval / walk_linear_cached_interval accumulating directed
per-side totals whose combine clamps the low side at zero and lets the high
side's underflow abort stand as a definite-surface-violation check;
scan_compact_interval killing on the gross envelope's LOW side (an order that
might be at or below threshold is never counted above it — protocol-favored);
revalue_with_liquidations_interval returning the pruned book's liability
envelope, with the liquidation event reporting the decision-side gross.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…ner; knock-out predicate unified on the low side

Mint admission takes the price envelope: definite-in-band probability gates,
leverage cap checked at the envelope's adverse side, and the committed tuple
(entry_value = mul_up(P.hi, Q), net_premium = div_up(E, lev), floor_shares by
exact identity) puts the one free dust unit on the unconditional inflow. At 1x
div_up(E, F) = E so the zero-floor invariant holds structurally. The budget
search probes the committed-corner premium so fills never exceed the budget.
Close flow: the classifier, ambient sweep, and flush scan now all read the
gross envelope's LOW side (one predicate, three lanes); live-close redeem
commits at the low corner; fees price the committed trade probability.
Config tests mechanically adapted (zero-width wraps); 33 suite expectations
now assert pre-envelope values and re-pin at the suite pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
… bounds; storage-class docs

Backing asserts and surplus releases now compare against the DEFINITE side:
the rebate reserve and λ-buffer carry their fixed-point rounding ulp as
envelope width, and required cash anchors at both holds' high sides
(required_cash_hi), so a release can never strand a hold behind rounding.
payout_liability_interval / exact_live_liability_interval / rebate reserve
envelope added as the read-side lane; current_liability_bounds exposes the
liability envelope as primitive (lo, hi) — valuation reads expose both bounds,
no envelope type in the public ABI. Rebate-claim chain documented as a single
low-corner collapse (cash-conserving split); EWMA state documented as
recurrence-exact (stored scalars are the defined quantity, no envelope).
Red set unchanged at 33 (pre-envelope value expectations; re-pin at suite pass).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…DBU-628)

Pool-layer completion of the interval lanes: PoolValuation carries the NAV
envelope; lp_pool_value evaluates corner-wise (monotone in active NAV, so the
scalar pipeline at each corner is the exact envelope); the drain prices the
supply queue at the pool value's high bound and the withdraw queue at its low
bound with per-side executability; FlushExecuted publishes the (lo, hi) mark
pair — the width is the flush's bid/ask spread. Trading fee flips to round-up
(protocol inflow). predeploy/interval-arithmetic.md carries the definitions:
soundness contract, storage classes, collapse-site taxonomy, side doctrine,
and the flush-lane abort inventory.

Known-red: unit tests are deliberately untouched this phase — 33 expectations
assert pre-envelope values and the plp flow tests reference pre-envelope
signatures; the suite re-pins as its own phase.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
… admission gate

Compute total variance, sqrt(w), and d2 at u128/1e18 in compute_nd2_terms:
flooring the b*inner product to 1e9 discarded the whole low-variance signal
(a 5-minute surface has w ~ 1e-8, about ten raw units at 1e9), inflating
pricing error to ~0.4% at short expiry. Replace the three fixed error tiers
(8/48/1e6) with evaluation_error_for_variance, an e(w) table keyed on the
evaluation's total variance, and add a beta^2 <= 9*min_tv admission gate
(beta = b*(1+|rho|)) that holds the skew correction clear of the [0,1] clamp
so every admitted evaluation lands in an e(w) band. Expose math::isqrt for the
u128 variance square root. Real Block Scholes surfaces clear the gate ~2x
(100% of observed surfaces); 1-minute pricing error drops from ~0.4% to ~5e-5.

Tests re-pin as their own phase (unchanged this commit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…cleanups

Replace the 8-band evaluation_error_for_variance table with a single widen
(up_price_evaluation_error = 300000 raw ~ 3e-4). The admission gate bounds the
pricing error across the whole admitted domain, so one value is sound for every
evaluation with no per-band magic table; saturated evaluations sit on exact
digital limits and are returned exact (zero width). This also fixes the
soundness regression the graduated tiers introduced: the gated box admits
mid-variance surfaces whose true error (~9.5e-5 at mid-range prices 0.3-0.9)
exceeded the tightened bands.

Cleanups from independent review:
- compute_nd2_terms returns (price, saturated: bool); the unused total_var is
  gone and variance_sqrt_and_d2 returns (sqrt_var, d2).
- split the skew gate onto its own error code EBlockScholesSkewExceedsVariance.
- name the gate ratio (skew_to_variance_bound) and share normal_cdf's tail
  saturation threshold (math::normal_cdf_saturation) with the d2 cap.
- correct interval-arithmetic.md overclaims (single widen; the per-tick
  ENonPositiveVariance/ECannotBeNegative aborts remain).

Add packages/predict/predeploy/pricing_error_certificate.py: the boundary-clean
calibration harness (fixed-point mirror lo/hp vs mpmath, verified leaf constants,
the gated-box error envelope) documenting how the widen and gate were derived.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
…und (codex review)

An independent review found the deep-ITM/OTM ratio saturations (which return the
exact digital limits 0/1) are unsound for high-variance surfaces: the loose
max_svi_input=100 cap admits a total variance ~40, at which an extreme strike
has a ~0.5 true price, not 0 or 1 — the exact-saturated interval then excludes
truth. Verified over the full moneyness range: the current caps have a
100%-error case; tightening |a|, |m|, sigma <= 1 and adding b <= 0.1 bounds total
variance so the saturations are genuinely exact and the single widen covers the
domain (max ~9e-5 vs the 3e-4 widen). Real Block Scholes surfaces clear every cap
(a <= 2e-3, b <= 0.03, m <= 0.08, sigma <= 0.22). The certificate harness now
samples the tightened box over wide moneyness, exercising the saturation cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
… signatures

Adapt the 7 test files left known-red by the interval-lane phase so the suite
compiles: duplicate each drain mark (supply_mark == withdraw_mark preserves the
pre-spread behavior), destructure finish_flush's (u64, u64) return taking the
supply-side value, and prefix now-unused setup bindings. 449 tests compile and
run; 44 still assert pre-envelope / pre-high-precision values and re-pin as the
next phase (this commit is signatures only, no value expectations changed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eRQH66BjxwTdajJ4qnbem
Base automatically changed from at/dbu-605-liquidate-during-flush to main July 22, 2026 18:40
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