{"verdict": "NEGATIVE: the H=8 table rule loses to V2. paired mean_diff -0.506 (se 0.0093, n=2000). It does not move toward top 10. Do not submit.", "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 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 TABLE = 173139225821558651789222541593188674096595598542984;\n    uint256 constant TSTEP = 1;\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[3] = WAD; \n        slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD;\n        slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000;\n        slots[13] = 902500000000; slots[14] = slots[5]; \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 = uint64(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        uint256 sigmaForFast = sigmaHat;\n        uint256 fastHat = slots[14];\n        uint256 uncertainty = slots[13];\n        uint256 silent = trade.timestamp > lastTs ? trade.timestamp - lastTs : 0;\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            uncertainty += wmul(sigmaForFast, sigmaForFast) * elapsedRaw;\n            if (uncertainty > 100000000000000) uncertainty = 100000000000000;\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        // S: infer a no-trade interval center from the last post-trade spot.\n        uint256 silenceScale = WAD;\n        if (firstInStep && silent > 1) {\n            uint256 g = silent - 1;\n            if (g > 1) g = 1;\n            uint256 w = WAD - _powWad(800000000000000000, g);\n            uint256 s = slots[2] >> 64;\n            if (s == 0) s = pHat;\n            uint256 c = (wmul(s, WAD - prevBidFee) + wdiv(s, WAD - prevAskFee)) / 2;\n            if (c >= pHat) pHat += wmul(w, c - pHat);\n            else pHat -= wmul(w, pHat - c);\n            silenceScale = WAD - wmul(300000000000000000, w);\n        }\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[12] = pImplied >= pHat ? 1 : 2; }\n            uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT);\n            if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE;\n            alpha = wmul(alpha, silenceScale);\n            adaptiveGate = wmul(adaptiveGate, silenceScale);\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        {\n            uint256 ret = fastHat > 0 ? wdiv(absDiff(pImplied, fastHat), fastHat) : 0;\n            uint256 alpha;\n            if (firstInStep) {\n                uint256 processSigma = sigmaForFast;\n                uint256 obsVar = uncertainty + wmul(processSigma, processSigma);\n                uint256 probArb;\n                uint256 z2 = wdiv(wmul(ret, ret), obsVar);\n                uint256 density = _powWad(wdiv(WAD, WAD + z2 / 16), 8);\n                uint256 sigmaObs = _isqrt(obsVar * WAD);\n                uint256 odds = wmul(density, wdiv(6700000000000000, sigmaObs));\n                bool arbFlag = ret <= wmul(sigmaForFast, 1220000000000000000);\n                uint256 prior = arbFlag ? 650000000000000000 : 400000000000000000;\n                uint256 tr = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0;\n                if (tr > 3000000000000000) prior = wmul(prior, 6 * WAD / 10);\n                if (silent > 1) prior = wmul(prior, 8 * WAD / 10);\n                odds = wmul(odds, wdiv(prior, WAD - prior));\n                probArb = wdiv(odds, WAD + odds);\n                alpha = wmul(probArb, 600000000000000000) + wmul(WAD - probArb, 80000000000000000);\n                slots[15] = pImplied >= fastHat ? 1 : 2;\n                uncertainty = wmul(uncertainty, WAD - alpha);\n            } else {\n                if ((slots[15] == 1) == (pImplied >= fastHat)) alpha = PHAT_ALPHA_RETAIL;\n            }\n            uint256 gate = wmul(sigmaHat, GATE_SIGMA_MULT);\n            if (gate < MIN_GATE) gate = MIN_GATE;\n            if (ret <= gate) fastHat = wmul(fastHat, WAD - alpha) + wmul(pImplied, alpha);\n            slots[13] = uncertainty;\n        }\n\n        if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) {\n            uint256 normalObs = trade.isBuy\n                ? wdiv(wmul(spot, gamma), WAD - 30 * BPS)\n                : wdiv(wmul(spot, WAD - 30 * BPS), gamma);\n            if ((slots[15] == 1) == (normalObs >= fastHat)) {\n                fastHat = wmul(fastHat, 9 * WAD / 10) + wmul(normalObs, WAD / 10);\n            }\n        }\n        slots[14] = fastHat;\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 flowSize = wmul(lambdaHat, sizeHat);\n        uint256 fBase = BASE_FEE + wmul(SIGMA_COEF, sigmaHat) + wmul(LAMBDA_COEF, lambdaHat) + wmul(FLOW_SIZE_COEF, flowSize);\n        uint256 fMid = fBase + wmul(TOX_COEF, toxSignal) + wmul(TOX_QUAD_COEF, wmul(toxSignal, toxSignal)) + wmul(ACT_COEF, actEma);\n        fMid = fMid + wmul(SIGMA_TOX_COEF, wmul(sigmaHat, toxSignal));\n\n        uint256 dirDev; bool sellPressure;\n        if (dirState >= WAD) { dirDev = dirState - WAD; sellPressure = true; }\n        else { dirDev = WAD - dirState; sellPressure = false; }\n\n        uint256 skew = wmul(DIR_COEF, dirDev) + wmul(DIR_TOX_COEF, wmul(dirDev, toxSignal));\n        uint256 bidFee; uint256 askFee;\n        if (sellPressure) {\n            bidFee = fMid + skew;\n            askFee = fMid > skew ? fMid - skew : 0;\n        } else {\n            askFee = fMid + skew;\n            bidFee = fMid > skew ? fMid - skew : 0;\n        }\n\n        {\n            uint256 staleHat = wmul(pHat, 700000000000000000) + wmul(fastHat, 300000000000000000);\n            uint256 staleTox = wdiv(absDiff(spot, staleHat), staleHat);\n            if (staleTox > TOX_CAP) staleTox = TOX_CAP;\n            uint256 staleShift = wmul(STALE_DIR_COEF, staleTox);\n            uint256 attractShift = wmul(staleShift, STALE_ATTRACT_FRAC);\n            if (spot >= staleHat) {\n                bidFee = bidFee + staleShift;\n                askFee = askFee > attractShift ? askFee - attractShift : 0;\n            } else {\n                askFee = askFee + staleShift;\n                bidFee = bidFee > attractShift ? bidFee - attractShift : 0;\n            }\n        }\n\n        {\n            bool tradeAligned = (trade.isBuy && spot >= pHat) || (!trade.isBuy && spot < pHat);\n            if (tradeAligned) {\n                uint256 tradeBoost = wmul(TRADE_TOX_BOOST, tradeRatio);\n                if (trade.isBuy) { bidFee = bidFee + tradeBoost; }\n                else { askFee = askFee + tradeBoost; }\n            }\n        }\n\n        if (sellPressure) {\n            bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_PROTECT));\n            askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_ATTRACT));\n        } else {\n            askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_PROTECT));\n            bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_ATTRACT));\n        }\n\n\n        {\n            // finite-horizon table (H=8): gap x flow x count -> joint (protect, attract) fee offset\n            uint256 gb = tox < 3 * BPS ? 0 : tox < 8 * BPS ? 1 : tox < 15 * BPS ? 2 : tox < 25 * BPS ? 3 : tox < 40 * BPS ? 4 : tox < 65 * BPS ? 5 : 6;\n            uint256 fb = lambdaHat < 750000000000000000 ? 0 : lambdaHat < 900000000000000000 ? 1 : 2;\n            uint256 act = (TABLE >> (4 * ((gb * 3 + fb) * 2 + (stepTradeCount > 1 ? 1 : 0)))) & 15;\n            uint256 pd = act / 3; uint256 ad = act % 3;\n            uint256 pFee = spot >= pHat ? bidFee : askFee;\n            uint256 aFee = spot >= pHat ? askFee : bidFee;\n            if (pd == 2) pFee += TSTEP * BPS; else if (pd == 0) pFee = pFee > TSTEP * BPS ? pFee - TSTEP * BPS : 0;\n            if (ad == 2) aFee += TSTEP * BPS; else if (ad == 0) aFee = aFee > TSTEP * BPS ? aFee - TSTEP * BPS : 0;\n            pFee = clampFee(pFee); aFee = clampFee(aFee);\n            if (spot >= pHat) { bidFee = pFee; askFee = aFee; } else { askFee = pFee; bidFee = aFee; }\n        }\n        slots[0] = bidFee; slots[1] = askFee; slots[2] = (spot << 64) | 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    // Floor square root: bit-length seed and seven Newton steps (all uint256).\n    function _isqrt(uint256 x) internal pure returns (uint256 r) {\n        if (x == 0) return 0;\n        unchecked {\n            uint256 y = x;\n            r = 1;\n            if (y >> 128 != 0) { y >>= 128; r <<= 64; }\n            if (y >> 64 != 0) { y >>= 64; r <<= 32; }\n            if (y >> 32 != 0) { y >>= 32; r <<= 16; }\n            if (y >> 16 != 0) { y >>= 16; r <<= 8; }\n            if (y >> 8 != 0) { y >>= 8; r <<= 4; }\n            if (y >> 4 != 0) { y >>= 4; r <<= 2; }\n            if (y >> 2 != 0) { r <<= 1; }\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            r = (r + x / r) >> 1;\n            uint256 t = x / r;\n            return r < t ? r : t;\n        }\n    }\n\n    function getName() external pure override returns (string memory) { return \"no_cubic\"; }\n}\n", "sha256": "e5e17ccc7bf5483ddf31d0587ae11076b84f04bf43ec37f8297890701b6af294", "base": "G (V2 with gas trims; recovered from Gsrc.code_GN, sha 610c1905... verified) plus one table block inserted before the final fee write; no Mix block. V2 sha 28417e11... verified. G and V2 gave identical edges on 8 smoke seeds (30000..30007).", "table_generator": {"model": "Offline Monte Carlo, 8-step horizon, common random numbers across actions. Exact CFMM (fees excluded from reserves), exact router split vs a 30bps normalizer, arb to the band edge on both pools, lognormal retail sizes (mean 20, sigma 1.2), Poisson remaining prints, one arb attempt next step, GBM sigma 0.00095. Latent fair price integrated: observed gap = true gap + N(0,3bps) noise. Opponent pool is re-arbed each step. 6000 paths per cell and action.", "bins": "7 gap bins (|spot-pHat| in bps: 0-3,3-8,8-15,15-25,25-40,40-65,65+) x 3 flow bins (lambdaHat <0.75, <0.9, else; model lambda 0.667/0.8/0.933, baseline fee 34/38/42bps) x 2 count bins (stepTradeCount==1 vs >1; remaining-print rate x1.0 / x0.5). 42 cells.", "actions": "9 joint (protect-side, attract-side) fee offsets in {-s,0,+s}^2 bps, protect side = bid when spot>=pHat. Offset is added after V2's direction skew and tail compression (V2 skew kept), then clampFee. In the MC the action applies for the first 2 steps; V2-like baseline fees (F0 + 0.685|g| protect, F0 - 0.72|g| attract) afterwards. Later recentering enters only through the 8-step reward; there is no terminal value.", "packed_table_f": {"0,0,0": 8, "0,0,1": 8, "0,1,0": 8, "0,1,1": 8, "0,2,0": 3, "0,2,1": 0, "1,0,0": 8, "1,0,1": 8, "1,1,0": 3, "1,1,1": 5, "1,2,0": 0, "1,2,1": 0, "2,0,0": 5, "2,0,1": 8, "2,1,0": 3, "2,1,1": 7, "2,2,0": 0, "2,2,1": 3, "3,0,0": 8, "3,0,1": 8, "3,1,0": 7, "3,1,1": 7, "3,2,0": 0, "3,2,1": 0, "4,0,0": 7, "4,0,1": 7, "4,1,0": 7, "4,1,1": 6, "4,2,0": 0, "4,2,1": 6, "5,0,0": 7, "5,0,1": 7, "5,1,0": 7, "5,1,1": 7, "5,2,0": 6, "5,2,1": 6, "6,0,0": 7, "6,0,1": 7, "6,1,0": 7, "6,1,1": 7, "6,2,0": 6, "6,2,1": 7}, "action_index": "idx=3*dp+da with dp,da in {0:-s,1:0,2:+s}; baseline=4", "step_bps_f": 1.0, "generator_source_dp_py": "import numpy as np, json, sys\nBPS=1e-4\nGAPE=[0,3,8,15,25,40,65,120]   # obs gap bins (bps)\nFLOW_F0=[34,38,42]; FLOW_LAM=[0.667,0.8,0.933]; COUNT_LAM=[1.0,0.5]\nSIG=0.00095; M=20.0; SZ=1.2\ndef fees(g,f0):\n    # V2-like baseline: protect side = bid when spot above fair (g>0)\n    prot=f0*BPS+0.685*np.abs(g); att=np.maximum(f0*BPS-0.72*np.abs(g),0)\n    bid=np.where(g>=0,prot,att); ask=np.where(g>=0,att,prot)\n    return bid,ask\ndef sim(g_obs,noise,f0,lam,act,H,dur,seed,P):\n    \"\"\"returns per-path edge sum over horizon for action (dp,da) bps applied for `dur` steps.\"\"\"\n    rng=np.random.default_rng(seed)\n    p=np.full(P,100.0); gt=g_obs+noise*rng.standard_normal(P)\n    kA=1e6; xA=np.sqrt(kA/(p*np.exp(gt))); yA=kA/xA\n    kB=1e6; xB=np.sqrt(kB/p); yB=kB/xB\n    edge=np.zeros(P); fb=0.003\n    dp,da=act\n    def curfees(t):\n        g=np.log(yA/xA/p); b,a=fees(g,f0)\n        if t<dur:\n            prot_bid=g>=0\n            b=b+np.where(prot_bid,dp,da)*BPS; a=a+np.where(prot_bid,da,dp)*BPS\n        return np.clip(b,0,0.1),np.clip(a,0,0.1)\n    def retail(n,t):\n        nonlocal xA,yA,xB,yB,edge\n        nmax=int(n.max()) if len(n) else 0\n        for i in range(nmax):\n            m=i<n\n            S=np.exp(np.log(M)-SZ*SZ/2+SZ*rng.standard_normal(P))\n            buy=rng.random(P)<0.5\n            bidA,askA=curfees(t)\n            fA=np.where(buy,askA,bidA); gA=1-fA; gB=1-fb\n            xin=np.where(buy,yA,xA); xinB=np.where(buy,yB,xB)\n            # r = sqrt(xA gA yA)/sqrt(xB gB yB)\n            r=np.sqrt(xA*gA*yA)/np.sqrt(xB*gB*yB)\n            T=np.where(buy,S,S/p)\n            inA=np.where(buy,yA,xA); inB=np.where(buy,yB,xB)\n            T1=np.clip((r*(inB+gB*T)-inA)/(gA+r*gB),0,T)\n            T1=np.where(m,T1,0)\n            # execute A (and B for remainder)\n            # A buy (AMM sells X): in Y\n            dyA=gA*T1; xo=xA-kA/(yA+dyA)\n            eb=T1-p*xo\n            dxA=gA*T1; yo=yA-kA/(xA+dxA)\n            es=p*T1-yo\n            edge+=np.where(buy,eb,es)\n            nxA=np.where(buy,kA/(yA+dyA),xA+dxA); nyA=np.where(buy,yA+dyA,kA/(xA+dxA))\n            xA,yA=nxA,nyA\n            T2=T-T1; \n            dyB=gB*T2; nxB=np.where(buy,kB/(yB+dyB),xB+dyB); nyB=np.where(buy,yB+dyB,kB/(xB+dyB))\n            xB,yB=nxB,nyB\n    def arb():\n        nonlocal xA,yA,xB,yB,edge\n        bidA,askA=curfees(0 if False else tcur[0])\n        ga=1-askA; gb=1-bidA; k=kA\n        s=yA/xA\n        buyX=s<ga*p\n        q=np.minimum(xA-np.sqrt(k/(ga*p)),0.99*xA)\n        yin=(k/(xA-q)-yA)/ga; prof=p*q-yin\n        okb=buyX&(q>0)&(prof>0)\n        sellX=s>p/gb\n        q2=(np.sqrt(k*gb/p)-xA)/gb\n        yout=yA-k/(xA+gb*q2); prof2=yout-p*q2\n        oks=sellX&(q2>0)&(prof2>0)\n        edge+=np.where(okb,-prof,0)+np.where(oks,-prof2,0)\n        nx=np.where(okb,xA-q,np.where(oks,xA+gb*q2,xA)); ny=np.where(okb,yA+ga*yin,np.where(oks,yA-yout,yA))\n        xA,yA=nx,ny\n        # B arb, fee 30bps\n        g=1-fb; kk=kB; s=yB/xB\n        bX=s<g*p; q=np.minimum(xB-np.sqrt(kk/(g*p)),0.99*xB); yi=(kk/(xB-q)-yB)/g\n        sX=s>p/g; q2=(np.sqrt(kk*g/p)-xB)/g\n        nxB=np.where(bX&(q>0),xB-q,np.where(sX&(q2>0),xB+g*q2,xB))\n        nyB=np.where(bX&(q>0),yB+g*yi,np.where(sX&(q2>0),kk/(xB+g*q2),yB))\n        xB,yB=nxB,nyB\n    tcur=[0]\n    # remaining retail in current step\n    retail(rng.poisson(lam,P),0)\n    for t in range(1,H):\n        tcur[0]=t\n        z=rng.standard_normal(P); p=p*np.exp(SIG*z-SIG*SIG/2)\n        arb()\n        retail(rng.poisson(lam_all,P) if False else rng.poisson(lam_global[0],P),t)\n    return edge\nlam_global=[0.8]\ndef table(step,H,dur,noise,P=6000,seed=7):\n    acts=[(a,b) for a in (-step,0,step) for b in (-step,0,step)]\n    tab={}; gains={}\n    rngs=np.random.default_rng(seed)\n    for gi in range(7):\n        for fi in range(3):\n            for ci in range(2):\n                lam=FLOW_LAM[fi]*COUNT_LAM[ci]\n                lam_global[0]=FLOW_LAM[fi]\n                gobs=rngs.uniform(GAPE[gi],GAPE[gi+1],P)*BPS\n                vals=[]\n                cs=int(rngs.integers(1<<30))\n                for a in acts:\n                    e=sim(gobs,noise,FLOW_F0[fi],lam,(a[0]*1.0,a[1]*1.0),H,dur,cs,P)\n                    vals.append(e.mean())\n                vals=np.array(vals); base=vals[4]\n                # require improvement beyond 2se to leave baseline\n                best=int(vals.argmax())\n                tab[(gi,fi,ci)]=best; gains[(gi,fi,ci)]=float(vals[best]-base)\n    return acts,tab,gains\nif __name__==\"__main__\":\n    step=float(sys.argv[1]); H=int(sys.argv[2]); dur=int(sys.argv[3]); noise=float(sys.argv[4])*BPS\n    acts,tab,gains=table(step,H,dur,noise)\n    out={\"step\":step,\"H\":H,\"dur\":dur,\"noise_bps\":noise/BPS,\"acts\":acts,\"tab\":{f\"{k[0]},{k[1]},{k[2]}\":v for k,v in tab.items()},\"gains\":{f\"{k[0]},{k[1]},{k[2]}\":v for k,v in gains.items()}}\n    json.dump(out,open(sys.argv[5],\"w\"))\n    for gi in range(7): print(gi,[ [tab[(gi,f,c)] for c in range(2)] for f in range(3)], round(np.mean([gains[(gi,f,c)] for f in range(3) for c in range(2)]),4))\n"}, "training": {"seeds": "30000..30063 (64)", "runs_vs_V2": {"a_step6_dur2_noise3": {"mean_diff": -4.0196, "se": 0.1509}, "b_step3_dur2_noise3": {"mean_diff": -1.9417, "se": 0.0961}, "c_step10_dur2_noise3": {"mean_diff": -3.5579, "se": 0.1708}, "d_step6_dur8_noise3": {"mean_diff": -2.8356, "se": 0.1911}, "e_step6_dur2_noise8": {"mean_diff": -4.0209, "se": 0.1502}, "f_step1_dur2_noise3": {"mean_diff": -0.524, "se": 0.0498}}, "ablation_H1_step6": {"mean_diff": -6.6812, "se": 0.1748, "note": "H=1 table is worse than the H=8 table with the same step (a, -4.02)."}, "trend": "Every table lost to V2. Loss shrinks as the step shrinks, so any offset away from V2's own fees hurts in the real simulator. The offline model's fee structure does not match V2's real one.", "all_valid_oog": "candidate OOG 0 and V2 OOG 0 in every training run (64 seeds)."}, "screen": {"seeds": "32000..32255 (256)", "top2": {"f": {"mean_diff": -0.5394, "se": 0.0248}, "b": {"mean_diff": -1.8722, "se": 0.045}}, "frozen": "f", "oog": "candidate 0, V2 0"}, "seed_ranges": {"train": "30000..30063", "screen": "32000..32255", "confirm": "4280000..4281999, run once, as four disjoint 500-seed chunks (single call exceeds 10 min tool limit). The chunks were merged; no seed was reused."}, "paired": {"n": 2000, "mean_diff": -0.5056861537601934, "se": 0.009258267234976539, "worst": [{"seed": 4281702, "diff": -2.360873538644114}, {"seed": 4280605, "diff": -2.1420066028895235}, {"seed": 4280982, "diff": -1.9717977551897548}, {"seed": 4280203, "diff": -1.8683438170003228}, {"seed": 4280726, "diff": -1.85163142457219}], "fraction_seeds_positive": 0.098, "candidate_mean_edge": 526.0265100196527, "v2_mean_edge": 526.532196173413}, "gas": {"max_ok": 220938, "oog": 0, "other_errors": 0}, "v2_gas": {"max_ok": 243901, "oog": 34, "other_errors": 0}, "oog_rule": "valid: candidate OOG 0 <= V2 OOG 34 on the same 2000 seeds. Part of the gap is that V2 loses fees when its afterSwap halts; the gas trims in G remove those halts. G and V2 gave identical edges on the smoke seeds.", "checks": "other errors=0 for both. Per-seed counters equal global counters in all 8 runs. max |retail+arb-total| = 8.58e-12 (<1e-8).", "retail_arb_deltas_candidate_minus_V2": {"definition": "Edge per seed. Terciles are by V2's retail volume (retail_volume_y, submission) on the same seeds.", "overall": {"n": 2000, "total": {"mean": -0.5056861537601934, "se": 0.009258267234976539}, "retail": {"mean": -1.1810782900349117, "se": 0.00953912002868886}, "arb": {"mean": 0.6753921362747957, "se": 0.004454830045702064}}, "tercile_low": {"n": 666, "total": {"mean": -0.5603760426369409, "se": 0.01397132901141986}, "retail": {"mean": -1.1102862673026064, "se": 0.014336709891081451}, "arb": {"mean": 0.549910224665755, "se": 0.0058629010990799675}}, "tercile_mid": {"n": 667, "total": {"mean": -0.5154414277805955, "se": 0.015142032940225356}, "retail": {"mean": -1.198446588402075, "se": 0.015561167514723188}, "arb": {"mean": 0.6830051606215485, "se": 0.006199786904156328}}, "tercile_high": {"n": 667, "total": {"mean": -0.44132298469944076, "se": 0.01834935502987944}, "retail": {"mean": -1.2343958794334386, "se": 0.018964281521644012}, "arb": {"mean": 0.7930728947340716, "se": 0.007836712764031833}}, "retail_volume_y_delta": {"mean": 75.82590362730366, "se": 1.9553400944305095}, "arb_volume_y_delta": {"mean": -318.993483998607, "se": 2.237173581558496}}, "interpretation": "The step-1 offsets (a table that is nearly V2) still lose about 0.5. Retail edge falls 1.18 and arb loss improves 0.68 on average, and the retail loss outweighs it. The model said these offsets would help: it overstates the arb saving or the flow elasticity, or the proxy lambdaHat thresholds (0.75/0.9, guessed, not measured) put cells in the wrong bins. I did not test which. The leaders' gap (+5 to +8.7) is not reachable with a gap x flow x count offset table on top of V2's fees.", "limits": ["lambdaHat bin thresholds were not calibrated against real lambdaHat values.", "MC baseline fee levels are rough approximations of V2's real fees (average real fee about 38bps taken from a 16-seed run).", "Only 6 variants, no re-tuning after the first results, as the brief limits.", "Not tested: the table replacing V2's fMid/skew terms rather than adding offsets."], "blocked": null}