# delta Insert after tail compression, before slots[0]/slots[1] are written. These are the only three changed lines; all NP2 constants and state updates remain intact: ```solidity uint256 leanShift = bidFee < 16000000000000 ? bidFee : 16000000000000; bidFee -= leanShift; askFee = clampFee(askFee + leanShift); ``` A fixed transfer targets the mean bias while retaining directional, stale/attract and aligned-trade signal formulas. The actual transfer is limited by available bid fee; the existing ask clamp still applies. # code ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; contract Strategy is AMMStrategyBase { uint256 constant ELAPSED_CAP = 8; uint256 constant SIGNAL_THRESHOLD = WAD / 650; uint256 constant DIR_DECAY = 750000000000000000; uint256 constant ACT_DECAY = 530000000000000000; uint256 constant SIZE_DECAY = 530000000000000000; uint256 constant TOX_DECAY = 910000000000000000; uint256 constant SIGMA_DECAY = 690000000000000000; uint256 constant LAMBDA_DECAY = 990000000000000000; uint256 constant SIZE_BLEND_DECAY = 828000000000000000; uint256 constant TOX_BLEND_DECAY = 51000000000000000; uint256 constant ACT_BLEND_DECAY = 985000000000000000; uint256 constant PHAT_ALPHA = 270000000000000000; uint256 constant PHAT_ALPHA_RETAIL = 60000000000000000; uint256 constant PHAT_ALPHA_SAME = 120000000000000000; uint256 constant REVERT_U = 0; uint256 constant DIR_IMPACT_MULT = 4; uint256 constant GATE_SIGMA_MULT = 7200000000000000000; uint256 constant MIN_GATE = 30000000000000000; uint256 constant TRADE_TOX_BOOST = 3500 * BPS; uint256 constant STALE_ATTRACT_FRAC = 1050000000000000000; uint256 constant RET_CAP = WAD / 35; uint256 constant TOX_CAP = WAD / 5; uint256 constant TRADE_RATIO_CAP = WAD / 5; uint256 constant LAMBDA_CAP = 1820000000000000000; uint256 constant STEP_COUNT_CAP = 64; uint256 constant BASE_FEE = 4 * BPS; uint256 constant SIGMA_COEF = 200000000000000000; uint256 constant LAMBDA_COEF = 12 * BPS; uint256 constant FLOW_SIZE_COEF = 4842 * BPS; uint256 constant TOX_COEF = 300 * BPS; uint256 constant TOX_QUAD_COEF = 15000 * BPS; uint256 constant ACT_COEF = 91843 * BPS; uint256 constant DIR_COEF = 20 * BPS; uint256 constant DIR_TOX_COEF = 100 * BPS; uint256 constant STALE_DIR_COEF = 6850 * BPS; uint256 constant SIGMA_TOX_COEF = 500 * BPS; uint256 constant TAIL_KNEE = 600 * BPS; uint256 constant TAIL_SLOPE_PROTECT = 930000000000000000; uint256 constant TAIL_SLOPE_ATTRACT = 850000000000000000; function afterInitialize(uint256 initialX, uint256 initialY) external override returns (uint256, uint256) { slots[0] = BASE_FEE; slots[1] = BASE_FEE; slots[2] = 0; slots[3] = WAD; slots[4] = 0; slots[5] = initialX > 0 ? wdiv(initialY, initialX) : 100 * WAD; slots[6] = 950000000000000; slots[7] = 800000000000000000; slots[8] = 2000000000000000; slots[9] = 0; slots[10] = 0; slots[11] = 0; slots[12] = 0; return (BASE_FEE, BASE_FEE); } function afterSwap(TradeInfo calldata trade) external override returns (uint256, uint256) { uint256 prevBidFee = slots[0]; uint256 prevAskFee = slots[1]; uint256 lastTs = slots[2]; uint256 dirState = slots[3]; uint256 actEma = slots[4]; uint256 pHat = slots[5]; uint256 sigmaHat = slots[6]; uint256 lambdaHat = slots[7]; uint256 sizeHat = slots[8]; uint256 toxEma = slots[9]; uint256 stepTradeCount = slots[10]; bool isNewStep = trade.timestamp > lastTs; if (isNewStep) { uint256 elapsedRaw = trade.timestamp - lastTs; uint256 elapsed = elapsedRaw > ELAPSED_CAP ? ELAPSED_CAP : elapsedRaw; dirState = _decayCentered(dirState, DIR_DECAY, elapsed); actEma = wmul(actEma, _powWad(ACT_DECAY, elapsed)); sizeHat = wmul(sizeHat, _powWad(SIZE_DECAY, elapsed)); toxEma = wmul(toxEma, _powWad(TOX_DECAY, elapsed)); if (stepTradeCount > 0 && elapsedRaw > 0) { uint256 lambdaInst = (stepTradeCount * WAD) / elapsedRaw; if (lambdaInst > LAMBDA_CAP) lambdaInst = LAMBDA_CAP; lambdaHat = wmul(lambdaHat, LAMBDA_DECAY) + wmul(lambdaInst, WAD - LAMBDA_DECAY); } stepTradeCount = 0; } bool firstInStep = stepTradeCount == 0; uint256 spot = trade.reserveX > 0 ? wdiv(trade.reserveY, trade.reserveX) : pHat; if (pHat == 0) pHat = spot; uint256 feeUsed = trade.isBuy ? prevBidFee : prevAskFee; uint256 gamma = feeUsed < WAD ? WAD - feeUsed : 0; uint256 pImplied; if (gamma == 0) { pImplied = spot; } else { pImplied = trade.isBuy ? wmul(spot, gamma) : wdiv(spot, gamma); } { uint256 ret = pHat > 0 ? wdiv(absDiff(pImplied, pHat), pHat) : 0; uint256 alpha = firstInStep ? PHAT_ALPHA : PHAT_ALPHA_RETAIL; uint256 prePhat = pHat; bool secondPrint = !firstInStep && stepTradeCount == 1; bool sameDir = false; bool oppDir = false; if (secondPrint) { bool up2 = pImplied >= pHat; uint256 d1 = slots[12]; if (d1 != 0) { sameDir = (d1 == 1) == up2; oppDir = !sameDir; } if (sameDir) alpha = PHAT_ALPHA_SAME; } if (firstInStep) { slots[11] = pHat; slots[12] = pImplied >= pHat ? 1 : 2; } uint256 adaptiveGate = wmul(sigmaHat, GATE_SIGMA_MULT); if (adaptiveGate < MIN_GATE) adaptiveGate = MIN_GATE; if (ret <= adaptiveGate) { pHat = wmul(pHat, WAD - alpha) + wmul(pImplied, alpha); } if (oppDir && REVERT_U > 0) { uint256 pre = slots[11]; if (pre > pHat) pHat = pHat + wmul(pre - pHat, REVERT_U); else pHat = pHat - wmul(pHat - pre, REVERT_U); } if (firstInStep) { if (ret > RET_CAP) ret = RET_CAP; sigmaHat = wmul(sigmaHat, SIGMA_DECAY) + wmul(ret, WAD - SIGMA_DECAY); } } // Interior retail routing equalizes fee-adjusted marginal prices. // Subsequent trades in a step cannot be the initial arbitrage trade. if (!firstInStep && feeUsed > 30 * BPS && gamma > 0) { uint256 normalSpot = trade.isBuy ? wdiv(wmul(spot, gamma), WAD - 30 * BPS) : wdiv(wmul(spot, WAD - 30 * BPS), gamma); pHat = wmul(pHat, 90 * WAD / 100) + wmul(normalSpot, 10 * WAD / 100); } uint256 tradeRatio = trade.reserveY > 0 ? wdiv(trade.amountY, trade.reserveY) : 0; if (tradeRatio > TRADE_RATIO_CAP) tradeRatio = TRADE_RATIO_CAP; if (tradeRatio > SIGNAL_THRESHOLD) { uint256 push = tradeRatio * DIR_IMPACT_MULT; if (push > WAD / 4) push = WAD / 4; if (trade.isBuy) { dirState = dirState + push; if (dirState > 2 * WAD) dirState = 2 * WAD; } else { dirState = dirState > push ? dirState - push : 0; } actEma = wmul(actEma, ACT_BLEND_DECAY) + wmul(tradeRatio, WAD - ACT_BLEND_DECAY); sizeHat = wmul(sizeHat, SIZE_BLEND_DECAY) + wmul(tradeRatio, WAD - SIZE_BLEND_DECAY); if (sizeHat > WAD) sizeHat = WAD; } uint256 tox = pHat > 0 ? wdiv(absDiff(spot, pHat), pHat) : 0; if (tox > TOX_CAP) tox = TOX_CAP; toxEma = wmul(toxEma, TOX_BLEND_DECAY) + wmul(tox, WAD - TOX_BLEND_DECAY); uint256 toxSignal = toxEma; stepTradeCount = stepTradeCount + 1; if (stepTradeCount > STEP_COUNT_CAP) stepTradeCount = STEP_COUNT_CAP; uint256 flowSize = wmul(lambdaHat, sizeHat); uint256 fBase = BASE_FEE + wmul(SIGMA_COEF, sigmaHat) + wmul(LAMBDA_COEF, lambdaHat) + wmul(FLOW_SIZE_COEF, flowSize); uint256 fMid = fBase + wmul(TOX_COEF, toxSignal) + wmul(TOX_QUAD_COEF, wmul(toxSignal, toxSignal)) + wmul(ACT_COEF, actEma); fMid = fMid + wmul(SIGMA_TOX_COEF, wmul(sigmaHat, toxSignal)); uint256 dirDev; bool sellPressure; if (dirState >= WAD) { dirDev = dirState - WAD; sellPressure = true; } else { dirDev = WAD - dirState; sellPressure = false; } uint256 skew = wmul(DIR_COEF, dirDev) + wmul(DIR_TOX_COEF, wmul(dirDev, toxSignal)); uint256 bidFee; uint256 askFee; if (sellPressure) { bidFee = fMid + skew; askFee = fMid > skew ? fMid - skew : 0; } else { askFee = fMid + skew; bidFee = fMid > skew ? fMid - skew : 0; } { uint256 staleShift = wmul(STALE_DIR_COEF, toxSignal); uint256 attractShift = wmul(staleShift, STALE_ATTRACT_FRAC); if (spot >= pHat) { bidFee = bidFee + staleShift; askFee = askFee > attractShift ? askFee - attractShift : 0; } else { askFee = askFee + staleShift; bidFee = bidFee > attractShift ? bidFee - attractShift : 0; } } { bool tradeAligned = (trade.isBuy && spot >= pHat) || (!trade.isBuy && spot < pHat); if (tradeAligned) { uint256 tradeBoost = wmul(TRADE_TOX_BOOST, tradeRatio); if (trade.isBuy) { bidFee = bidFee + tradeBoost; } else { askFee = askFee + tradeBoost; } } } if (sellPressure) { bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_PROTECT)); askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_ATTRACT)); } else { askFee = clampFee(_compressTailWithSlope(askFee, TAIL_SLOPE_PROTECT)); bidFee = clampFee(_compressTailWithSlope(bidFee, TAIL_SLOPE_ATTRACT)); } uint256 leanShift = bidFee < 16000000000000 ? bidFee : 16000000000000; bidFee -= leanShift; askFee = clampFee(askFee + leanShift); slots[0] = bidFee; slots[1] = askFee; slots[2] = trade.timestamp; slots[3] = dirState; slots[4] = actEma; slots[5] = pHat; slots[6] = sigmaHat; slots[7] = lambdaHat; slots[8] = sizeHat; slots[9] = toxEma; slots[10] = stepTradeCount; return (bidFee, askFee); } function _compressTailWithSlope(uint256 fee, uint256 slope) internal pure returns (uint256) { if (fee <= TAIL_KNEE) return fee; return TAIL_KNEE + wmul(fee - TAIL_KNEE, slope); } function _powWad(uint256 factor, uint256 exp) internal pure returns (uint256 result) { result = WAD; while (exp > 0) { if (exp & 1 == 1) result = wmul(result, factor); factor = wmul(factor, factor); exp >>= 1; } } function _decayCentered(uint256 centered, uint256 decayFactor, uint256 elapsed) internal pure returns (uint256) { uint256 mul = _powWad(decayFactor, elapsed); if (centered >= WAD) { return WAD + wmul(centered - WAD, mul); } uint256 below = wmul(WAD - centered, mul); return below < WAD ? WAD - below : 0; } function getName() external pure override returns (string memory) { return "no_cubic"; } } ``` # sha256 `952b5634215c1cd04245ed66ce413d3e9a9f74327f7d018aef646250db891404` (UTF-8 Solidity above, including its final newline). # tuning Simulator pinned to `6b6921f8d463314aa7c96234e1be25a25245f704`. Setup and StarterStrategy validation passed. Final candidate passed `amm-match validate scratch/center-016.sol`. NP2 reconstruction SHA-256: `51f1c1a9d4999ee460eb8bbc66880da8074b173399a4f5d71f96671482e18ac0`. Inputs: [TWO](https://api.imd.fun/artifacts/528a6da78583c6142644a552c86670f9d25c20e39e92f4de44deae05ddc8cecd), [NP insertion](https://api.imd.fun/artifacts/da313379a2e69e9286668865e06b18dfcae25732c82b934b0fd9c2ef0d8c2ff5). The source uses the pinned [AMMStrategyBase](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/AMMStrategyBase.sol) helpers and [IAMMStrategy](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/IAMMStrategy.sol) interface; 1 bps is 1e14 WAD units. All numbers below are local measurements, not claims of a leaderboard submission. Calibration and standalone diagnostics use the pinned [30 bps normalizer](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol). CH is the [pinned Strategy.sol](https://raw.githubusercontent.com/ChengHua926/amm-challenge/d34a5199c59a4c44d5336a25f1436b4ae1f21104/contracts/src/Strategy.sol). Calibration on seeds 0..999 (submission mean edge): | Strategy | measured | requested check | |---|---:|---:| | CH | 525.525882178083 | 525.525882178 | | NP2 | 526.115572245986 | 526.1156 | Source-isolation diagnostics, seeds 0..199, one term zeroed at a time. This is diagnosis only; none of these ablations is the delivered candidate. zero-dir sets skew=0 while retaining dirState updates and tail-side choice; zero-stale sets staleShift=0 (thus attractShift=0); zero-boost sets tradeBoost=0. Values are step-end mean bid-minus-ask in bps; standalone edge differences subtract NP2 against the same normalizer on the same seeds. | variant | standalone lean | standalone paired edge diff | SE | direct-vs-NP2 lean | direct edge diff | SE | |---|---:|---:|---:|---:|---:|---:| | NP2 | 0.890445 | 0 | — | — | — | — | | zero-dir | 0.902679 | 0.061225 | 0.012403 | 0.584601 | -2.305771 | 0.103957 | | zero-stale | -0.035281 | -122.521314 | 1.648450 | -0.016565 | -92.444986 | 1.262198 | | zero-boost | 0.762273 | -0.809412 | 0.044062 | 0.592481 | 16.404532 | 0.320798 | Stale/attract shifts are the dominant source: removing them changes standalone lean from 0.890445 to -0.035281 bps and costs 122.521314 edge per seed. Removing directional skew leaves +0.902679 bps. The direct-market stale ablation also removes the lean but loses 92.444986 edge. These are causal interventions with changed trading paths, not additive attribution percentages. The final strategy retains all three transient signals and removes only a constant mean imbalance. The boost ablation retains +0.762273 bps lean. It gains +16.404532 in direct matches but changes standalone paired edge by -0.809412 (SE 0.044062), an observed sign reversal. Direct-match gains therefore cannot be labeled standalone leaderboard gains. Tuning uses only seeds 10000..10299 for direct matches and 10000..10199 for standalone checks. For direct matches, exactly the requested `amm_sim_rs.run_batch(candidate, np2, configs, 8)` is used; the difference is submission edge minus normalizer-slot NP2 edge in the same market. Standalone paired differences subtract separate candidate-versus-Vanilla and NP2-versus-Vanilla submission edges on identical seeds. These are distinct estimands. Fixed-shift pilot (stopped in favor of EMA after observing overcorrection; partial points include only completed seeds): | shift each side (bps) | direct n | direct paired mean_diff | SE | standalone n | standalone paired mean_diff | SE | standalone lean | |---|---:|---:|---:|---:|---:|---:|---:| | .25 | 240 | 0.411277 | 0.051292 | 200 | -0.051158 | 0.011424 | -0.461147 | | .375 | — | — | — | 40 | -0.098375 | 0.021496 | -1.351578 | EMA pilot (decays 0.995 and 0.999, approximately 200 and 1000 steps; the planned 5000-step point was not run). These use previous step-end raw pre-centering bid-minus-ask, a mean held fixed within each step, and elapsed-time decay. Partial points were stopped after the completed 200-step point lost standalone edge. No EMA is in the delivered code. | EMA steps | direct n | direct mean_diff | SE | standalone n | standalone paired mean_diff | SE | standalone lean | |---|---:|---:|---:|---:|---:|---:|---:| | 200 | 300 | 6.704602 | 0.240106 | 200 | -2.575406 | 0.066534 | 0.091751 | | 1000 | 60 | 2.590089 | 0.283216 | 120 | -0.684745 | 0.047058 | 0.154933 | Refined fixed-shift grid. Selection minimizes absolute standalone tuning bid-minus-ask among the completed fixed-shift points and the completed EMA point. Edge changes are reported separately. Each refined point uses exactly the same 200 seeds. No initial, directional, stale, boost, or tail constant is retuned. | shift: bid down / ask up (bps) | direct n | direct mean_diff | SE | standalone n | standalone paired mean_diff | SE | standalone lean (bps) | |---|---:|---:|---:|---:|---:|---:|---:| | .125 | 200 | 0.150039 | 0.046661 | 200 | -0.032412 | 0.008810 | 0.182142 | | .16 (chosen) | 200 | 0.217723 | 0.055549 | 200 | -0.041040 | 0.009038 | 0.002943 | | .20 | 200 | 0.283198 | 0.056704 | 200 | -0.048963 | 0.010425 | -0.204115 | Chosen: a fixed 0.16 bps transfer from bid to ask. This minimizes absolute standalone tuning lean among the completed fixed-shift points and completed EMA point: +0.002943 bps versus NP2 +0.811751. Partial pilots were excluded from selection. The standalone tuning gain is negative, so this is a mean-centering result, not a tuning improvement claim. All selection and code validation finished before opening the holdout. The same frozen candidate is used once in each prespecified market configuration of the single confirmation cohort; there is no holdout retuning. Configuration: per-seed `numpy.random.default_rng(seed)`, draw size U(19,21), rate U(0.6,1.0), sigma U(0.000882,0.001008), in that order; n_steps=10000, initial_price=100, initial_x=100, initial_y=10000, mu=0, dt=1, retail_size_sigma=1.2, retail_buy_prob=0.5, cfg.seed=seed. This reproduces [MatchRunner draws](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py) and [baseline settings](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py); the [engine](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/simulation/engine.rs) seeds retail at seed+1. All 12 config fields were checked exactly against MatchRunner._build_configs on seeds 0..199. Unmodified simulator, batches of 20, 8 workers. Vanilla is renamed Strategy solely for compiler lookup; its fee logic remains the pinned constant 30 bps. SE is sample SD / sqrt(n). Worst lists the five smallest per-seed differences. # paired One frozen confirmation cohort on fresh seeds **2500000..2501999**, never used during tuning. Each specified market configuration is evaluated once; no candidate changes or follow-up selection use these seeds. Primary result is the direct candidate-vs-NP2 market, as requested. NP2 is the normalizer-slot strategy here, not Vanilla. This direct-match edge difference is not a measured standalone leaderboard improvement. ```json { "n": 2000, "mean_diff": 0.26896243824752986, "se": 0.020664102379059298, "worst": [ { "seed": 2501078, "diff": -24.86038361094245 }, { "seed": 2500846, "diff": -9.400637116598432 }, { "seed": 2500647, "diff": -8.509041439006978 }, { "seed": 2500479, "diff": -6.550209787939593 }, { "seed": 2501820, "diff": -6.289628011408013 } ] } ``` Standalone confirmation in the same frozen holdout cohort, with candidate and NP2 each evaluated once against Vanilla on exactly these seeds (no reselection or subsequent tuning): ```json { "n": 2000, "candidate_mean_edge": 524.7818547805484, "np2_mean_edge": 524.8165271472873, "mean_diff": -0.03467236673875178, "se": 0.0031935884477932775, "worst": [ { "seed": 2501332, "diff": -1.0724055809355377 }, { "seed": 2501505, "diff": -0.9094366084431158 }, { "seed": 2500724, "diff": -0.7889904734463471 }, { "seed": 2500918, "diff": -0.7373119461954047 }, { "seed": 2500699, "diff": -0.6769344833622881 } ] } ``` Standalone confirmation: **mean edge change -0.034672367, SE 0.003193588**. Mean bid-minus-ask falls from **+0.837111 to +0.038584 bps**. This achieves near-level fees but does not improve the standard challenge-market edge; retain NP2 for performance. # fee_stats Confirm seeds, same direct matches. Fees are in bps. Each run averages all 10000 step-end fees (including steps with no trade). “Mid slope” is OLS slope of the run mean (bid+ask)/2 against that strategy’s total retail Y / 10000, with intercept, across runs. “Any bid >40” counts runs having at least one step-end bid above 40 bps; the last column also gives the count using run mean bid instead. [Result fields](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_sim_rs/src/types/result.rs). | strategy | mean bid | mean ask | bid-ask | mid slope / 10k retail Y | runs: any bid >40 | runs: mean bid >40 | |---|---:|---:|---:|---:|---:|---:| | NP2 | 36.139296 | 35.618097 | 0.521199 | 1.708045 | 2000 | 178 | | candidate | 35.744803 | 35.977072 | -0.232270 | 1.708036 | 2000 | 139 | Standalone confirmation fees, same frozen holdout cohort, each strategy against the 30 bps normalizer. Definitions and units are identical to the direct-match table above: | strategy | mean bid | mean ask | bid-ask | mid slope / 10k retail Y | runs: any bid >40 | runs: mean bid >40 | |---|---:|---:|---:|---:|---:|---:| | NP2 | 36.278382 | 35.441271 | 0.837111 | 1.702907 | 2000 | 168 | | candidate | 35.851925 | 35.813341 | 0.038584 | 1.703576 | 2000 | 112 | Standalone holdout retail thirds: equal-count bins sorted by NP2 total retail Y, with the same seed membership for candidate and reference. Fees are step-end means in bps; these are descriptive bins, not a second selection step. | NP2 retail-Y third | strategy | n | mean bid | mean ask | bid-ask | |---|---|---:|---:|---:|---:| | low | NP2 | 667 | 34.262402 | 33.359190 | 0.903211 | | low | candidate | 667 | 33.840015 | 33.724270 | 0.115745 | | middle | NP2 | 667 | 36.408376 | 35.596247 | 0.812130 | | middle | candidate | 667 | 35.981303 | 35.970727 | 0.010576 | | high | NP2 | 666 | 38.167199 | 37.371269 | 0.795930 | | high | candidate | 666 | 37.737283 | 37.747925 | -0.010642 | Standalone tuning-market fees (200 seeds; candidate and NP2 each against Vanilla), to show centering in the calibration market: | strategy | mean bid | mean ask | bid-ask | mid slope / 10k retail Y | runs: any bid >40 | runs: mean bid >40 | |---|---:|---:|---:|---:|---:|---:| | NP2 | 36.267390 | 35.455639 | 0.811751 | 1.779513 | 200 | 20 | | candidate | 35.837136 | 35.834193 | 0.002943 | 1.777624 | 200 | 15 | # blocked `null` — setup, calibration, final validation, and requested confirm completed. # next Keep NP2: zeroing the lean reduced standalone edge. Use separate paired candidate/NP2 runs against the 30 bps normalizer for promotion decisions; direct head-to-head gains are not transferable here.