Skip to content

Wave 11e — v12.20.6 enqueue_adl B-residual algorithm - #103

Merged
dcccrypto merged 1 commit into
mainfrom
feat/eng-enqueue-adl-b-residual-wave11e
May 11, 2026
Merged

Wave 11e — v12.20.6 enqueue_adl B-residual algorithm#103
dcccrypto merged 1 commit into
mainfrom
feat/eng-enqueue-adl-b-residual-wave11e

Conversation

@dcccrypto

@dcccrypto dcccrypto commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replaces fork's K-adjust ADL with toly's v12.20.6 certified/potential/B-residual algorithm in enqueue_adl Step 7/8/10/11. K is no longer modified for bankruptcy residual.
  • 3 Kani proofs rewritten with strictly stronger v12.20.6 post-state invariants; 3 new harnesses pin the three observable D_rem routes. Engine Kani 360 → 363 (+3).
  • KL-FORK-ENGINE-BANKRUPT-CLOSE-1 fully REVOKED — the entire bankrupt-close subsystem (gate + state machine + recovery branches + lock wiring + residual booking) is now at byte-for-byte algorithmic parity with toly v12.20.6.

Algorithmic change

Fork (pre-Wave-11e, K-adjust ADL) Toly v12.20.6 (this PR)
Step 7 effect K_opp -= ceil(D_rem * A_old * POS_SCALE / OI) with headroom check D_rem splits into d_phantom (→ uninsured) + d_social (→ B-residual booking OR uninsured)
Haircut mechanism Implicit via lazy K-snap diff on opp-side accounts Explicit forced close at oracle in chunks, OR explicit non-claim loss bucket
Phantom-dust handling K-adjust applies to phantom dust too (potential double-count) Certified-phantom-dust share routes to uninsured loss explicitly
State carrier adl_coeff_<opp> active_close_present + active_close_residual_* + explicit_unallocated_loss_<side>

Both algorithms preserve global conservation.

Kani harnesses

3 rewritten (old K-adjust assertions replaced with B-residual equivalents):

  • t11_54_worked_example_regression — replaces adl_coeff_long != 0i128 with bankruptcy_hmax_lock_active + explicit_unallocated_loss_long == 500.
  • t11_49_pure_pnl_bankruptcy_path — replaces adl_coeff_long != k_before with bankruptcy_hmax_lock_active + explicit_unallocated_loss_long == 1000.
  • proof_adl_pipeline_trade_liquidate_reopen — replaces adl_coeff_short < k_short_before with bankruptcy_hmax_lock_active + explicit_unallocated_loss_short == 1000.

3 new:

  • proof_d_phantom_routes_to_uninsured_protocol_lossold_certified >= oi → full D_rem to record_uninsured_protocol_loss.
  • proof_d_social_routes_to_uninsured_when_uncertified_gap_nonzerouncertified_potential != 0 → both shares to uninsured.
  • proof_d_social_books_residual_when_uncertified_gap_zerouncertified_potential == 0 → social share to book_or_start_active_close_residual_to_side.

Drive-by fixes (pre-existing Kani-build breakages)

Kani-on-main has been silently broken since Wave 11d Phase 1. Necessary to fix to verify Wave 11e's harnesses:

  • tests/common/mod.rs:110,210 — typo max_max_max_trading_fee_bpsmax_trading_fee_bps.
  • tests/proofs_audit.rs:756validate_execute_trade_entry 9-arg → 10-arg call (missing admit_h_min = 0).
  • assert_public_postconditions, settle_losses_with_context, resolve_flat_negative_with_context wrapped in test_visible! macro (Wave 11d Phase 1 added Kani tests calling these but never wrapped them).

Test plan

  • cargo build --release --tests --features test — clean.
  • cargo test --release --features test --tests — 335 passed, 0 failed.
  • verify-engine-preservation.sh, verify-engine-deferred-absent.sh, verify-eng-port-preservation.sh, verify-wrapper-preservation.sh — all silent.
  • 3 rewritten Kani harnesses — VERIFICATION SUCCESSFUL.
  • 3 new Kani harnesses — VERIFICATION SUCCESSFUL.
  • 5 adjacent Kani harnesses spot-checked for regression — all SUCCESSFUL.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Enhanced bankruptcy and asset depletion liquidation (ADL) logic with improved phantom-dust accounting and deficit routing mechanisms.
    • Updated liquidation deficit handling to provide more precise loss allocation across positions.
    • Refined algorithm for bankrupt position closure and residual loss management.

Review Change Stack

Replaces fork's K-adjust ADL (`delta_K_abs = ceil(D_rem * A_old * POS_SCALE / OI)`
written to `adl_coeff_<opp>`) with toly's v12.20.6 certified/potential/B-residual
routing. K is no longer modified for bankruptcy residual on any path.

Changes
-------

* `enqueue_adl` Step 7: `D_rem` now splits into `d_phantom` (proportional to
  `phantom_dust_certified_<opp> / oi`, routed to
  `record_uninsured_protocol_loss`) and `d_social = D_rem - d_phantom`.
  `d_social` routes to `book_or_start_active_close_residual_to_side` when
  `uncertified_potential == 0`, else to `record_uninsured_protocol_loss`.
  Mirrors toly:5034-5069.

* `enqueue_adl` Step 8/10/11: `phantom_dust_certified_<side>` +
  `phantom_dust_potential_<side>` maintained via `represented_after` /
  `aggregate_gap` arithmetic. Full-drain / terminal-drain / Step 5 paths
  zero both accumulators. Mirrors toly:5074-5135.

* Helper `ceil_mul_div_u128_or_wide` ported (toly:3398-3424). Kani-visible
  Result-returning ceil(a*b/d) with U256 fallback (cfg(not(kani))) and Err
  shortcut (cfg(kani)) on u128 overflow.

* Removed fork-only `inc_phantom_dust_potential_by` (its only call site
  was the pre-v12.20.6 Step 10 dust write; toly inlines `aggregate_gap +
  account_floor_bound` instead). `wide_mul_div_ceil_u128_or_over_i128max`
  + `OverI128Magnitude` imports dropped (only enqueue_adl used them).

Kani harnesses
--------------

* 3 rewritten — old K-adjust post-state assertions replaced with strictly
  stronger v12.20.6 invariants:
    - `t11_54_worked_example_regression` — replaces `adl_coeff_long != 0i128`
      with `bankruptcy_hmax_lock_active` + `explicit_unallocated_loss_long == 500`.
    - `t11_49_pure_pnl_bankruptcy_path` — replaces `adl_coeff_long != k_before`
      with `bankruptcy_hmax_lock_active` + `explicit_unallocated_loss_long == 1000`.
    - `proof_adl_pipeline_trade_liquidate_reopen` — replaces
      `adl_coeff_short < k_short_before` with `bankruptcy_hmax_lock_active` +
      `explicit_unallocated_loss_short == 1000`.

* 3 new harnesses pin the three observable D_rem routes:
    - `proof_d_phantom_routes_to_uninsured_protocol_loss`
      (`old_certified >= oi` shortcut).
    - `proof_d_social_routes_to_uninsured_when_uncertified_gap_nonzero`
      (`uncertified_potential != 0`).
    - `proof_d_social_books_residual_when_uncertified_gap_zero`
      (`uncertified_potential == 0` → residual booking; with
      `loss_weight_sum_<opp> == 0` records explicit).

* Adjacent harnesses verified non-regressing:
  `proof_enqueue_adl_arms_bankruptcy_lock_when_d_positive`,
  `proof_enqueue_adl_leaves_bankruptcy_lock_when_d_zero`,
  `t11_48_bankruptcy_liquidation_routes_q_when_D_zero`,
  `t11_46_enqueue_adl_k_add_overflow_still_routes_quantity`,
  `t4_17_enqueue_adl_preserves_oi_balance_qty_only`.

Engine Kani 360 → 363 (+3). All 335 host tests pass.
KL-FORK-ENGINE-BANKRUPT-CLOSE-1 fully REVOKED (was: PARTIALLY REVOKED
since Wave 11d Phase 1).

Drive-by fixes (pre-existing Kani-build breakages from prior waves)
-------------------------------------------------------------------

These prevented `cargo kani` from running on main; necessary to verify
Wave 11e's harnesses.

* `tests/common/mod.rs` — typo `max_max_max_trading_fee_bps` →
  `max_trading_fee_bps` (introduced by an earlier auto-rename, never tested
  under Kani at lines 110, 210).

* `tests/proofs_audit.rs:756` — `validate_execute_trade_entry` updated from
  9-arg to 10-arg call (signature added separate `admit_h_max` in Wave
  11a-ii; test was never updated). Inserted `admit_h_min = 0`.

* `test_visible!`-wrapped three fns broken by Wave 11d Phase 1 (commit
  d0fae02): `assert_public_postconditions`, `settle_losses_with_context`,
  `resolve_flat_negative_with_context`. The Wave 11d Phase 1 commit added
  Kani tests that call these methods but never wrapped the methods
  themselves. Kani-on-main has been silently broken since Wave 11d Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements Wave 11e B-residual routing in the ADL engine, introducing phantom-dust certified/potential split logic, a new overflow-safe ceil-mul-div helper, and replacing coefficient-based deficit accounting with explicit loss and bankruptcy-close state machine routing. All proof harnesses are updated to validate the new behavior.

Changes

Wave 11e ADL B-Residual Routing Implementation

Layer / File(s) Summary
Wide-Math Helpers & Imports
src/percolator.rs
Narrow wide_math imports to required helpers and add new u128 ceil-mul-div variants. Implement new ceil_mul_div_u128_or_wide(a, b, d) helper with U256 fallback and explicit overflow handling for ADL deficit split computation.
Deficit Remainder Split & Routing (Wave 11e)
src/percolator.rs
In enqueue_adl, snapshot opposing phantom-dust state (certified/potential), compute uncertified potential, split d_rem into phantom-share (routed to uninsured loss) and social-share (routed by uncertified pinning: either uninsured loss or bankrupt-close state machine). Use new ceil-mul-div helper for phantom-share proportional computation.
Phantom-Dust State Updates
src/percolator.rs
After opposing-side A shrink, compute new phantom_dust_certified and phantom_dust_potential using represented-after/aggregate-gap logic with U256 intermediates and close-pin effects, replacing prior "OI decreased → increment by bound" rule.
Terminal Drain State Cleanup
src/percolator.rs
On full opposing-side drain, zero phantom-dust certified/potential for that side. On terminal drain of both sides, additionally zero phantom-dust for the liquidated side. Remove obsolete inc_phantom_dust_potential_by helper.
Test Configuration Updates
tests/common/mod.rs
Update RiskParams fixtures in zero_fee_params() and default_params() from max_max_max_trading_fee_bps to max_trading_fee_bps field (values: 0 and 10 respectively).
Proof & Assertion Updates
tests/proofs_audit.rs, tests/proofs_instructions.rs, tests/proofs_liveness.rs
Update t11_54_worked_example_regression to assert bankruptcy lock arming, ADL multiplier shrink, and explicit loss routing via d_social. Add three new Wave 11e routing harnesses validating phantom/social split outcomes. Update pure-PnL bankruptcy and ADL pipeline proofs to assert h_max lock activation and explicit loss recording instead of coefficient changes. Add extra parameter to validate_execute_trade_entry call in audit proof.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • dcccrypto/percolator#97: Introduces B-tracking schema and fields that this PR's phantom-dust routing logic depends on and operates against.
  • dcccrypto/percolator#88: Earlier ADL logic modifications and wide_math helpers that this PR refactors and builds upon.
  • dcccrypto/percolator#64: Foundational wide_math types and U256 utilities that the new ceil-mul-div helper leverages.

Poem

🐰 A phantom dust split, now carefully planned,
Social and certified, hand-in-hand,
Deficits routed with overflow care,
Wave 11e blooms—proofs prove it's fair! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Wave 11e — v12.20.6 enqueue_adl B-residual algorithm' is highly specific and directly reflects the main change: implementing the Wave 11e B-residual routing algorithm inside the enqueue_adl function.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/eng-enqueue-adl-b-residual-wave11e

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/proofs_instructions.rs (1)

823-861: ⚡ Quick win

Also pin active_close_present on the other two routing harnesses.

Lines 824-827 and Lines 910-916 describe "no state-machine startup", but only the uncertified-gap proof actually asserts that. As written, these two proofs would still pass if enqueue_adl spuriously started bankrupt-close state while preserving the loss buckets. Since this PR is explicitly restoring bankrupt-close parity, I'd snapshot active_close_present here too.

Suggested diff
 fn proof_d_phantom_routes_to_uninsured_protocol_loss() {
@@
     let protocol_loss_before = engine.explicit_unallocated_protocol_loss.get();
     let explicit_long_before = engine.explicit_unallocated_loss_long.get();
     let k_before = engine.adl_coeff_long;
+    let active_close_before = engine.active_close_present;
@@
     assert!(
         engine.adl_coeff_long == k_before,
         "K must not be modified on the certified-saturated path"
     );
+    assert!(
+        engine.active_close_present == active_close_before,
+        "phantom-only routing must not start bankrupt-close state"
+    );
 }
@@
 fn proof_d_social_books_residual_when_uncertified_gap_zero() {
@@
     let protocol_loss_before = engine.explicit_unallocated_protocol_loss.get();
     let explicit_long_before = engine.explicit_unallocated_loss_long.get();
+    let active_close_before = engine.active_close_present;
@@
     assert!(
         engine.bankruptcy_hmax_lock_active,
         "Step 2 must arm the bankruptcy h_max lock when d > 0"
     );
+    assert!(
+        engine.active_close_present == active_close_before,
+        "fully absorbed residual must not start bankrupt-close state"
+    );
 }

Also applies to: 909-955

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/proofs_instructions.rs` around lines 823 - 861, Snapshot the
InstructionContext.active_close_present flag before calling enqueue_adl and
assert it is unchanged after in the
proof_d_phantom_routes_to_uninsured_protocol_loss test (and the other two
routing-harness tests mentioned) so a spurious bankrupt-close start is detected;
specifically, capture ctx.active_close_present into a local (e.g., let
active_close_before = ctx.active_close_present) prior to calling
RiskEngine::enqueue_adl, then add an assertion after the call that
ctx.active_close_present == active_close_before; apply the same change to the
other two routing harness functions that exercise enqueue_adl so all three pin
active_close_present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/percolator.rs`:
- Around line 4096-4109: The branch handling d_social must ensure B-side loss
weights are populated before deciding between record_uninsured_protocol_loss and
book_or_start_active_close_residual_to_side: populate loss_weight_sum_<side> and
each account's loss_weight / b_* on the live attach/trade/liquidation paths so
loss_weight_sum_* > 0 when appropriate; specifically, wire/update those
per-account and aggregate B-loss weight fields prior to the d_social routing
here (so book_or_start_active_close_residual_to_side sees correct weights)
rather than only relying on test pre-seeding — if there is an existing helper
that computes loss weights, call it before this branch, otherwise implement the
wiring logic and ensure record_uninsured_protocol_loss remains the fallback when
weights are truly zero.

---

Nitpick comments:
In `@tests/proofs_instructions.rs`:
- Around line 823-861: Snapshot the InstructionContext.active_close_present flag
before calling enqueue_adl and assert it is unchanged after in the
proof_d_phantom_routes_to_uninsured_protocol_loss test (and the other two
routing-harness tests mentioned) so a spurious bankrupt-close start is detected;
specifically, capture ctx.active_close_present into a local (e.g., let
active_close_before = ctx.active_close_present) prior to calling
RiskEngine::enqueue_adl, then add an assertion after the call that
ctx.active_close_present == active_close_before; apply the same change to the
other two routing harness functions that exercise enqueue_adl so all three pin
active_close_present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2b460abf-5258-43d9-9e8c-5eb4d71f8753

📥 Commits

Reviewing files that changed from the base of the PR and between f65ea0a and e53116e.

📒 Files selected for processing (5)
  • src/percolator.rs
  • tests/common/mod.rs
  • tests/proofs_audit.rs
  • tests/proofs_instructions.rs
  • tests/proofs_liveness.rs

Comment thread src/percolator.rs
Comment on lines +4096 to +4109
if d_social != 0 {
if uncertified_potential != 0 {
self.record_uninsured_protocol_loss(d_social);
} else {
let (_booked, _recorded) = self.book_or_start_active_close_residual_to_side(
ctx,
u16::MAX,
opp,
self.last_oracle_price,
self.current_slot,
q_close_q,
d_social,
PUBLIC_B_CHUNK_ATOMS,
)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Wire the B-loss weights before routing d_social here.

This branch only reaches real B-booking when loss_weight_sum_<side> > 0, but this file still never populates non-zero loss_weight_sum_* or per-account loss_weight/b_* on the live attach/trade/liquidation paths. In normal engine state, book_or_start_active_close_residual_to_side() will therefore collapse to explicit loss recording instead of socializing or opening the active-close residual flow, so the advertised Wave 11e behavior is only reachable in tests that pre-seed those fields.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/percolator.rs` around lines 4096 - 4109, The branch handling d_social
must ensure B-side loss weights are populated before deciding between
record_uninsured_protocol_loss and book_or_start_active_close_residual_to_side:
populate loss_weight_sum_<side> and each account's loss_weight / b_* on the live
attach/trade/liquidation paths so loss_weight_sum_* > 0 when appropriate;
specifically, wire/update those per-account and aggregate B-loss weight fields
prior to the d_social routing here (so
book_or_start_active_close_residual_to_side sees correct weights) rather than
only relying on test pre-seeding — if there is an existing helper that computes
loss weights, call it before this branch, otherwise implement the wiring logic
and ensure record_uninsured_protocol_loss remains the fallback when weights are
truly zero.

@dcccrypto
dcccrypto merged commit 86f7d7a into main May 11, 2026
1 check passed
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