{
 "delta": -5.128176,
 "code": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {AMMStrategyBase} from \"./AMMStrategyBase.sol\";\nimport {TradeInfo} from \"./IAMMStrategy.sol\";\n\ncontract Strategy is AMMStrategyBase {\n    uint256 constant EV_A = 750000000000000000;\n    uint256 constant EV_B = 15 * BPS;\n    uint256 constant EV_C = 30 * BPS;\n    uint256 constant EV_D = 500000000000000000;\n    uint256 constant ELAPSED_CAP = 8;\n    uint256 constant SIGNAL_THRESHOLD = WAD / 650;\n    uint256 constant DIR_DECAY = 750000000000000000;\n    uint256 constant ACT_DECAY = 530000000000000000;\n    uint256 constant SIZE_DECAY = 530000000000000000;\n    uint256 constant TOX_DECAY = 910000000000000000;\n    uint256 constant SIGMA_DECAY = 690000000000000000;\n    uint256 constant LAMBDA_DECAY = 990000000000000000;\n    uint256 constant SIZE_BLEND_DECAY = 828000000000000000;\n    uint256 constant TOX_BLEND_DECAY = 51000000000000000;\n    uint256 constant ACT_BLEND_DECAY = 985000000000000000;\n    uint256 constant PHAT_ALPHA = 270000000000000000;\n    uint256 constant PHAT_ALPHA_RETAIL = 60000000000000000;\n    uint256 constant PHAT_ALPHA_SAME = 120000000000000000;\n    uint256 constant REVERT_U = 0;\n    uint256 constant DIR_IMPACT_MULT = 4;\n    uint256 constant GATE_SIGMA_MULT = 7200000000000000000;\n    uint256 constant MIN_GATE = 30000000000000000;\n    uint256 constant TRADE_TOX_BOOST = 3500 * BPS;\n    uint256 constant STALE_ATTRACT_FRAC = 1050000000000000000;\n    uint256 constant RET_CAP = WAD / 35;\n    uint256 constant TOX_CAP = WAD / 5;\n    uint256 constant TRADE_RATIO_CAP = WAD / 5;\n    uint256 constant LAMBDA_CAP = 1820000000000000000;\n    uint256 constant STEP_COUNT_CAP = 64;\n    uint256 constant BASE_FEE = 4 * BPS;\n    uint256 constant SIGMA_COEF = 200000000000000000;\n    uint256 constant LAMBDA_COEF = 12 * BPS;\n    uint256 constant FLOW_SIZE_COEF = 4842 * BPS;\n    uint256 constant TOX_COEF = 300 * BPS;\n    uint256 constant TOX_QUAD_COEF = 15000 * BPS;\n    uint256 constant ACT_COEF = 91843 * BPS;\n    uint256 constant DIR_COEF = 20 * BPS;\n    uint256 constant DIR_TOX_COEF = 100 * BPS;\n    uint256 constant STALE_DIR_COEF = 6850 * BPS;\n    uint256 constant SIGMA_TOX_COEF = 500 * BPS;\n    uint256 constant TAIL_KNEE = 600 * BPS;\n    uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000;\n    uint256 constant TAIL_SLOPE_ATTRACT = 850000000000000000;\n\n    function afterInitialize(uint256 initialX, uint256 initialY) external override returns (uint256, uint256) {\n        slots[0] = BASE_FEE; slots[1] = BASE_FEE; slots[2] = 0; slots[3] = WAD; slots[4] = 0;\n        slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD;\n        slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000;\n        slots[9] = 0; slots[10] = 0; slots[11] = 0; slots[12] = 0;\n        return (BASE_FEE, BASE_FEE);\n    }\n\n    function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) {\n        uint256 prevBidFee = slots[0]; uint256 prevAskFee = slots[1]; uint256 lastTs = slots[2];\n        uint256 dirState = slots[3]; uint256 actEma = slots[4]; uint256 pHat = slots[5];\n        uint256 sigmaHat = slots[6]; uint256 lambdaHat = slots[7]; uint256 sizeHat = slots[8];\n        uint256 toxEma = slots[9]; uint256 stepTradeCount = slots[10];\n\n        bool isNewStep = trade.timestamp > lastTs;\n        if (isNewStep) {\n            uint256 elapsedRaw = trade.timestamp - lastTs;\n            uint256 elapsed = elapsedRaw > ELAPSED_CAP ? ELAPSED_CAP : elapsedRaw;\n            dirState = _decayCentered(dirState, DIR_DECAY, elapsed);\n            actEma = wmul(actEma, _powWad(ACT_DECAY, elapsed));\n            sizeHat = wmul(sizeHat, _powWad(SIZE_DECAY, elapsed));\n            toxEma = wmul(toxEma, _powWad(TOX_DECAY, elapsed));\n            if (stepTradeCount > 0 && elapsedRaw > 0) {\n                uint256 lambdaInst = (stepTradeCount * WAD) / elapsedRaw;\n                if (lambdaInst > LAMBDA_CAP) lambdaInst = LAMBDA_CAP;\n                lambdaHat = wmul(lambdaHat, LAMBDA_DECAY) + wmul(lambdaInst, WAD - LAMBDA_DECAY);\n            }\n            stepTradeCount = 0;\n        }\n\n        bool firstInStep = stepTradeCount == 0;\n        uint256 spot = trade.reserveX > 0 ? wdiv(trade.reserveY, trade.reserveX) : pHat;\n        if (pHat == 0) pHat = spot;\n\n        uint256 feeUsed = trade.isBuy ? prevBidFee : prevAskFee;\n        uint256 gamma = feeUsed < WAD ? WAD - feeUsed : 0;\n        uint256 pImplied;\n        if (gamma == 0) { pImplied = spot; }\n        else { pImplied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma); }\n\n        {\n            uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0;\n            uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL;\n            uint256 prePhat = pHat;\n            bool secondPrint = !firstInStep && stepTradeCount == 1;\n            bool sameDir = false; bool oppDir = false;\n            if (secondPrint) {\n                bool up2 = pImplied >= pHat;\n                uint256 d1 = slots[12];\n                if (d1 != 0) { sameDir = (d1 == 1) == up2; oppDir = !sameDir; }\n                if (sameDir) alpha = PHAT_ALPHA_SAME;\n            }\n            if (firstInStep) { slots[11] = pHat; slots[12] = pImplied >= pHat ? 1 : 2; }\n            uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT);\n            if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE;\n            if (ret <= adaptiveGate) { pHat = wmul(pHat, WAD - alpha) + wmul(pImplied, alpha); }\n            if (oppDir && REVERT_U > 0) {\n                uint256 pre = slots[11];\n                if (pre > pHat) pHat = pHat + wmul(pre - pHat, REVERT_U);\n                else pHat = pHat - wmul(pHat - pre, REVERT_U);\n            }\n            if (firstInStep) {\n                if (ret > RET_CAP) ret = RET_CAP;\n                sigmaHat = wmul(sigmaHat, SIGMA_DECAY) + wmul(ret, WAD - SIGMA_DECAY);\n            }\n        }\n\n        // Interior retail routing equalizes fee-adjusted marginal prices.\n        // Subsequent trades in a step cannot be the initial arbitrage trade.\n        if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) {\n            uint256 normalSpot = trade.isBuy\n                ? wdiv(wmul(spot, gamma), WAD - 30 * BPS)\n                : wdiv(wmul(spot, WAD - 30 * BPS), gamma);\n            pHat = wmul(pHat, 90 * WAD / 100) + wmul(normalSpot, 10 * WAD / 100);\n        }\n\n        uint256 tradeRatio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0;\n        if (tradeRatio > TRADE_RATIO_CAP) tradeRatio = TRADE_RATIO_CAP;\n\n        if (tradeRatio > SIGNAL_THRESHOLD) {\n            uint256 push = tradeRatio * DIR_IMPACT_MULT;\n            if (push > WAD / 4) push = WAD / 4;\n            if (trade.isBuy) {\n                dirState = dirState + push;\n                if (dirState > 2 * WAD) dirState = 2 * WAD;\n            } else {\n                dirState = dirState > push ? dirState - push : 0;\n            }\n            actEma = wmul(actEma, ACT_BLEND_DECAY) + wmul(tradeRatio, WAD - ACT_BLEND_DECAY);\n            sizeHat = wmul(sizeHat, SIZE_BLEND_DECAY) + wmul(tradeRatio, WAD - SIZE_BLEND_DECAY);\n            if (sizeHat > WAD) sizeHat = WAD;\n        }\n\n        uint256 tox = pHat > 0 ? wdiv(absDiff(spot, pHat), pHat) : 0;\n        if (tox > TOX_CAP) tox = TOX_CAP;\n        toxEma = wmul(toxEma, TOX_BLEND_DECAY) + wmul(tox, WAD - TOX_BLEND_DECAY);\n        uint256 toxSignal = toxEma;\n\n        stepTradeCount = stepTradeCount + 1;\n        if (stepTradeCount > STEP_COUNT_CAP) stepTradeCount = STEP_COUNT_CAP;\n\n        uint256 bidFee; uint256 askFee;\n        {\n            uint256 p;\n            assembly { p := calldataload(196) }\n            if (p == 0) p = spot;\n            uint256 g = wdiv(absDiff(spot, p), p);\n            uint256 expo = wmul(EV_A, g) + EV_B;\n            uint256 dg = wmul(EV_D, g);\n            uint256 other = EV_C > dg ? EV_C - dg : 0;\n            if (spot >= p) { bidFee = expo; askFee = other; }\n            else { askFee = expo; bidFee = other; }\n            bidFee = clampFee(bidFee); askFee = clampFee(askFee);\n        }\n\n        slots[0] = bidFee; slots[1] = askFee; slots[2] = trade.timestamp;\n        slots[3] = dirState; slots[4] = actEma; slots[5] = pHat;\n        slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat;\n        slots[9] = toxEma; slots[10] = stepTradeCount;\n\n        return (bidFee, askFee);\n    }\n\n    function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) {\n        if (fee <= TAIL_KNEE) return fee;\n        return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope);\n    }\n\n    function _powWad(uint256 factor, uint256 exp) internal pure returns (uint256 result) {\n        result = WAD;\n        while (exp > 0) {\n            if (exp & 1 == 1) result = wmul(result, factor);\n            factor = wmul(factor, factor);\n            exp >>= 1;\n        }\n    }\n\n    function _decayCentered(uint256 centered, uint256 decayFactor, uint256 elapsed) internal pure returns (uint256) {\n        uint256 mul = _powWad(decayFactor, elapsed);\n        if (centered >= WAD) { return WAD + wmul(centered - WAD, mul); }\n        uint256 below = wmul(WAD - centered, mul);\n        return below < WAD ? WAD - below : 0;\n    }\n\n    function getName() external pure override returns (string memory) { return \"no_cubic\"; }\n}\n",
 "simulator_diff": "diff --git a/amm_sim_rs/src/amm/cfmm.rs b/amm_sim_rs/src/amm/cfmm.rs\nindex 02e6645..ea00158 100644\n--- a/amm_sim_rs/src/amm/cfmm.rs\n+++ b/amm_sim_rs/src/amm/cfmm.rs\n@@ -54,6 +54,8 @@ pub struct CFMM {\n     accumulated_fees_x: f64,\n     /// Accumulated fees in Y (collected separately, not in reserves)\n     accumulated_fees_y: f64,\n+    /// True fair price of current step (research hint)\n+    pub fair_hint: f64,\n }\n \n impl CFMM {\n@@ -69,6 +71,7 @@ impl CFMM {\n             initialized: false,\n             accumulated_fees_x: 0.0,\n             accumulated_fees_y: 0.0,\n+            fair_hint: 0.0,\n         }\n     }\n \n@@ -291,7 +294,7 @@ impl CFMM {\n \n     /// Update fees from strategy after a trade.\n     fn update_fees(&mut self, trade_info: &TradeInfo) {\n-        if let Ok((bid_fee, ask_fee)) = self.strategy.after_swap(trade_info) {\n+        if let Ok((bid_fee, ask_fee)) = self.strategy.after_swap(trade_info, self.fair_hint) {\n             self.current_fees = FeeQuote::new(bid_fee.clamp_fee(), ask_fee.clamp_fee());\n         }\n         // On error, keep current fees\ndiff --git a/amm_sim_rs/src/evm/strategy.rs b/amm_sim_rs/src/evm/strategy.rs\nindex 1d06af1..43cea22 100644\n--- a/amm_sim_rs/src/evm/strategy.rs\n+++ b/amm_sim_rs/src/evm/strategy.rs\n@@ -55,7 +55,7 @@ pub struct EVMStrategy {\n     /// In-memory database for EVM state\n     db: InMemoryDB,\n     /// Pre-allocated calldata buffer for after_swap (196 bytes)\n-    trade_calldata: [u8; 196],\n+    trade_calldata: [u8; 228],\n }\n \n impl EVMStrategy {\n@@ -65,7 +65,7 @@ impl EVMStrategy {\n             name: default_name,\n             bytecode: bytecode.clone(),\n             db: InMemoryDB::default(),\n-            trade_calldata: [0u8; 196],\n+            trade_calldata: [0u8; 228],\n         };\n \n         strategy.deploy()?;\n@@ -176,9 +176,16 @@ impl EVMStrategy {\n     ///\n     /// Returns (bid_fee, ask_fee) in WAD.\n     #[inline]\n-    pub fn after_swap(&mut self, trade: &TradeInfo) -> Result<(Wad, Wad), EVMError> {\n+    pub fn after_swap(&mut self, trade: &TradeInfo, fair: f64) -> Result<(Wad, Wad), EVMError> {\n         // Encode trade info into pre-allocated buffer\n-        trade.encode_calldata(&mut self.trade_calldata);\n+        {\n+            let (head, tail) = self.trade_calldata.split_at_mut(196);\n+            let head: &mut [u8; 196] = head.try_into().unwrap();\n+            trade.encode_calldata(head);\n+            tail.fill(0);\n+            let v: u128 = (fair * 1e18).floor() as u128;\n+            tail[16..32].copy_from_slice(&v.to_be_bytes());\n+        }\n \n         // Copy calldata to avoid borrow conflict\n         let calldata = self.trade_calldata;\ndiff --git a/amm_sim_rs/src/simulation/engine.rs b/amm_sim_rs/src/simulation/engine.rs\nindex 6834c43..326055b 100644\n--- a/amm_sim_rs/src/simulation/engine.rs\n+++ b/amm_sim_rs/src/simulation/engine.rs\n@@ -109,6 +109,7 @@ impl SimulationEngine {\n         );\n \n         // Track edge per strategy\n+        let mut arb_edges: HashMap<String, f64> = HashMap::new();\n         let mut edges: HashMap<String, f64> = HashMap::new();\n         edges.insert(submission_name.clone(), 0.0);\n         edges.insert(baseline_name.clone(), 0.0);\n@@ -137,10 +138,12 @@ impl SimulationEngine {\n             // 1. Generate new fair price\n             let fair_price = price_process.step();\n \n+            for amm in amms.iter_mut() { amm.fair_hint = fair_price; }\n             // 2. Arbitrageur extracts profit from each AMM\n             for amm in amms.iter_mut() {\n                 if let Some(arb_result) = arbitrageur.execute_arb(amm, fair_price, t as u64) {\n                     *arb_volume_y.get_mut(&arb_result.amm_name).unwrap() += arb_result.amount_y;\n+                    *arb_edges.entry(arb_result.amm_name.clone()).or_insert(0.0) += -arb_result.profit;\n                     let entry = edges.entry(arb_result.amm_name).or_insert(0.0);\n                     // AMM edge is the negative of arbitrageur profit at true price\n                     *entry += -arb_result.profit;\n@@ -209,6 +212,7 @@ impl SimulationEngine {\n             strategies: vec![submission_name, baseline_name],\n             pnl,\n             edges,\n+            arb_edges,\n             initial_fair_price,\n             initial_reserves,\n             steps,\ndiff --git a/amm_sim_rs/src/types/result.rs b/amm_sim_rs/src/types/result.rs\nindex 0257335..aaca66f 100644\n--- a/amm_sim_rs/src/types/result.rs\n+++ b/amm_sim_rs/src/types/result.rs\n@@ -58,6 +58,10 @@ pub struct LightweightSimResult {\n     #[pyo3(get)]\n     pub edges: HashMap<String, f64>,\n \n+    /// Arb-only edge by strategy name\n+    #[pyo3(get)]\n+    pub arb_edges: HashMap<String, f64>,\n+\n     /// Initial fair price\n     #[pyo3(get)]\n     pub initial_fair_price: f64,\n",
 "sha256": "2b3b1784261dfa82e76fcd02aa627bb635b9c6fb8c6520aa20d0ad2f62e0a623",
 "tuning": {
  "rule": "Keep NP2's state updates (pHat, sigma, lambda, size, tox, dir, step count, slot writes). Replace all fee logic with: p = true fair price of the step (calldataload(196)); g = |spot-p|/p; exposed side (bid if spot>=p else ask) = a*g + b; other side = max(c - d*g, 0); clampFee.",
  "seeds": "10000..10039 (40 seeds, paired vs NP2, each run separately vs VanillaStrategy)",
  "method": "coordinate search on the brief's grid: a x b at c=25,d=0.5, then c x d at a=0.75,b=20, then a local refine. 50 of the 735 grid points were evaluated. All were negative vs NP2.",
  "frozen": {
   "a": 0.75,
   "b_bps": 15,
   "c_bps": 30,
   "d": 0.5
  },
  "grid_results": [
   {
    "a": 0.5,
    "b_bps": 10.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -71.27,
    "se": 2.214
   },
   {
    "a": 0.5,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -35.371,
    "se": 1.58
   },
   {
    "a": 0.5,
    "b_bps": 30.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -23.417,
    "se": 1.259
   },
   {
    "a": 0.5,
    "b_bps": 40.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -22.699,
    "se": 1.031
   },
   {
    "a": 0.75,
    "b_bps": 10.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -10.384,
    "se": 0.561
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -8.05,
    "se": 0.409
   },
   {
    "a": 0.75,
    "b_bps": 30.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -12.117,
    "se": 0.467
   },
   {
    "a": 0.75,
    "b_bps": 40.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -14.704,
    "se": 0.546
   },
   {
    "a": 0.9,
    "b_bps": 10.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -12.783,
    "se": 0.573
   },
   {
    "a": 0.9,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -19.351,
    "se": 0.821
   },
   {
    "a": 0.9,
    "b_bps": 30.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -21.706,
    "se": 0.859
   },
   {
    "a": 0.9,
    "b_bps": 40.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -23.08,
    "se": 0.839
   },
   {
    "a": 1.0,
    "b_bps": 10.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -29.273,
    "se": 1.077
   },
   {
    "a": 1.0,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -28.967,
    "se": 0.979
   },
   {
    "a": 1.0,
    "b_bps": 30.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -30.71,
    "se": 0.953
   },
   {
    "a": 1.0,
    "b_bps": 40.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -37.472,
    "se": 1.093
   },
   {
    "a": 1.1,
    "b_bps": 10.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -46.535,
    "se": 1.972
   },
   {
    "a": 1.1,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -52.798,
    "se": 2.579
   },
   {
    "a": 1.1,
    "b_bps": 30.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -65.083,
    "se": 2.859
   },
   {
    "a": 1.1,
    "b_bps": 40.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -81.142,
    "se": 3.054
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 10.0,
    "d": 0.0,
    "mean_diff": -17.74,
    "se": 0.542
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 10.0,
    "d": 0.5,
    "mean_diff": -14.792,
    "se": 0.505
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 10.0,
    "d": 1.0,
    "mean_diff": -15.848,
    "se": 0.526
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 15.0,
    "d": 0.0,
    "mean_diff": -19.176,
    "se": 0.558
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 15.0,
    "d": 0.5,
    "mean_diff": -12.42,
    "se": 0.478
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 15.0,
    "d": 1.0,
    "mean_diff": -14.453,
    "se": 0.506
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 20.0,
    "d": 0.0,
    "mean_diff": -21.426,
    "se": 0.582
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 20.0,
    "d": 0.5,
    "mean_diff": -9.994,
    "se": 0.437
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 20.0,
    "d": 1.0,
    "mean_diff": -12.831,
    "se": 0.482
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.0,
    "mean_diff": -24.468,
    "se": 0.625
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -8.05,
    "se": 0.409
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 25.0,
    "d": 1.0,
    "mean_diff": -11.189,
    "se": 0.456
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 30.0,
    "d": 0.0,
    "mean_diff": -28.189,
    "se": 0.682
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 30.0,
    "d": 0.5,
    "mean_diff": -7.037,
    "se": 0.398
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 30.0,
    "d": 1.0,
    "mean_diff": -9.683,
    "se": 0.432
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 35.0,
    "d": 0.0,
    "mean_diff": -32.368,
    "se": 0.745
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 35.0,
    "d": 0.5,
    "mean_diff": -7.543,
    "se": 0.397
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 35.0,
    "d": 1.0,
    "mean_diff": -8.465,
    "se": 0.416
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 40.0,
    "d": 0.0,
    "mean_diff": -36.825,
    "se": 0.817
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 40.0,
    "d": 0.5,
    "mean_diff": -9.632,
    "se": 0.405
   },
   {
    "a": 0.75,
    "b_bps": 20.0,
    "c_bps": 40.0,
    "d": 1.0,
    "mean_diff": -7.702,
    "se": 0.407
   },
   {
    "a": 0.75,
    "b_bps": 15.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -6.874,
    "se": 0.459
   },
   {
    "a": 0.75,
    "b_bps": 25.0,
    "c_bps": 25.0,
    "d": 0.5,
    "mean_diff": -10.225,
    "se": 0.416
   },
   {
    "a": 0.75,
    "b_bps": 15.0,
    "c_bps": 30.0,
    "d": 0.5,
    "mean_diff": -5.635,
    "se": 0.431
   },
   {
    "a": 0.75,
    "b_bps": 15.0,
    "c_bps": 35.0,
    "d": 0.5,
    "mean_diff": -6.483,
    "se": 0.409
   },
   {
    "a": 0.75,
    "b_bps": 10.0,
    "c_bps": 30.0,
    "d": 0.5,
    "mean_diff": -8.142,
    "se": 0.532
   },
   {
    "a": 0.75,
    "b_bps": 10.0,
    "c_bps": 35.0,
    "d": 0.5,
    "mean_diff": -8.868,
    "se": 0.519
   },
   {
    "a": 0.75,
    "b_bps": 15.0,
    "c_bps": 40.0,
    "d": 1.0,
    "mean_diff": -6.697,
    "se": 0.465
   },
   {
    "a": 0.9,
    "b_bps": 10.0,
    "c_bps": 35.0,
    "d": 0.5,
    "mean_diff": -11.59,
    "se": 0.53
   },
   {
    "a": 0.75,
    "b_bps": 15.0,
    "c_bps": 30.0,
    "d": 1.0,
    "mean_diff": -9.176,
    "se": 0.49
   }
  ]
 },
 "paired": {
  "n": 2000,
  "seeds": "2700000..2701999",
  "mean_diff": -5.128176,
  "se": 0.060038,
  "worst": -16.850597,
  "worst_seed": 2700563,
  "best": 1.020243,
  "wins": 23,
  "cand_mean_edge": 520.668104,
  "np2_mean_edge": 525.796281
 },
 "split": {
  "arb_edge_diff": -0.335041,
  "arb_edge_diff_se": 0.054984,
  "retail_edge_diff": -4.793135,
  "retail_edge_diff_se": 0.03911,
  "cand_arb_edge": -31.555634,
  "np2_arb_edge": -31.220592
 },
 "fee_stats": {
  "bid": {
   "cand_mean": 0.003359,
   "np2_mean": 0.003638
  },
  "ask": {
   "cand_mean": 0.00326,
   "np2_mean": 0.003537
  },
  "note": "mean over steps of the end-of-step fee (simulator average_fees), as a fraction (0.0033 = 33 bps), averaged over the 2000 confirmation seeds"
 },
 "blocked": null,
 "next": "A rule that knows the true price but is a simple affine function of the gap g scores 5.13 below NP2 (\u22124.79 of that is retail edge, \u22120.34 arb edge). NP2's fee level (it earns ~0.28 bps more on both sides) and its flow/size/tox terms are worth more than knowing p exactly. So this affine form is not a ceiling on what knowing p is worth; it is a weak use of p. A real ceiling test: keep NP2's full fee logic and only replace pHat with p in the tox/stale-direction terms, or add a*g on the exposed side on top of NP2's fees. Checks done: NP2 reproduces 526.1155722 on seeds 0..999 in the patched simulator (bit-exact with the brief's 526.1156). The CH = 525.525882178 check was not run because CH's code is not given in the brief."
}