{
 "credit": "Taylor (gtmcknight), github.com/gtmcknight/amm-sim@4812a6382311624e1506aca131ca35c378f930d9 research/solved: the replica, Gaussian filter, fee rule, qm tables and arb/retail tell this item runs on and patches are his. Fast replica: fastlean (artifact a88ff982eba7e078bc6ccb1555b90a211c00c9fd76ec90a62ab13a4074f2c3d0); LEANBASE reference: artifact efb8e653f8fd061cecf3e92b186470c9c96c5188523364b60ed101e9672869aa.",
 "mech": "markout: an online controller on realised markout. The fills of each side (bid = pool bought X, ask = pool sold X) in our latest trading step are valued at the filter mean after the next step's first callback; a per-side EMA of that markout (bps) raises or lowers that side's fee within the run.",
 "already_present": {
  "value": false,
  "where": "Not in the policy. Read: leanbase.py and stalerival.py (decoded from reference_zb64 of artifact efb8e653...), real.py (research/solved) and tellpol.py (research/tell) at amm-sim 66604b3426d8e97a73e2c39940b9b4dece51cc73, and their port fastlean.py. The state they keep is the Gaussian belief (m, v), the rival spot estimate s2h with synced/router_t/router_age, tlast, cnt, the previous spot and reserve wads, and the two fees in force. Fees are a table lookup at (ln s - m, ln s2h - m, phase, sd): no variable records the price or edge of a past fill, nothing compares past fills with a later mean, and no fee level is fed back from realised results. The nearest thing is the filter itself, which uses each fill to update the belief (arb pin / truncation), not to score earlier fills. So the mechanism itself was tested, not a variant of something present."
 },
 "definition": {
  "formula": "Side i: 0 bid (is_buy, pool bought X), 1 ask. Every callback, after LEANBASE's arb/retail read: if the fill's class is in `fills`, PX[i] += amountX, PY[i] += amountY (wad-quantised amounts of the callback). On a step's first callback (timestamp > previous callback's timestamp), after the filter update gives the new mean m: for each side with PX[i] > 0: mk_i = g_i * (m - ln(PY[i]/PX[i])) * 1e4 bps, g_0 = +1, g_1 = -1 (value at the later mean minus the volume-weighted execution price), clipped to +-clip_bps; E_i += beta * (mk_i - E_i); PX[i] = PY[i] = 0. After LEANBASE has chosen its two fees (same call site as fastlean's hook, before stalerival.fee rounding/clamp): dev_i = E_i - target_bps (mode 0, per side against a fixed target), E_i - Eslow_i (mode 1, not tested), E_i - E_other (mode 2, cross-side), mean(E_0, E_1) - target_bps (mode 3, common, not tested); fee_i += clip(-k * dev_i, -cap_bps, +cap_bps) * 1e-4. k > 0: a side whose recent fills marked out below the reference gets a higher fee. E starts at target_bps. k = 0 reproduces LEANBASE bit for bit (checked: 16 seeds 64000..64015 against the unpatched fastlean.py, max abs diff 0.0).",
  "parameters": {
   "k": "fee bps per bp of markout below the reference (signed)",
   "beta": "EMA rate per settled side-step",
   "mode": "0 fixed target per side, 2 cross-side (bid EMA minus ask EMA)",
   "target_bps": "fixed reference for mode 0",
   "cap_bps": "bound on the fee offset (3 in every setting)",
   "fills": "1 all fills, 0 fills not read as the arbitrageur, 2 fills read as the arbitrageur",
   "beta_slow": "unused in the tested settings",
   "clip_bps": "bound on one settled markout (50 in every setting)"
  },
  "state_kept": "6 numbers: PX[2], PY[2] (unsettled X and Y volume per side of the latest trading step) and E[2] (per-side markout EMA, bps). Inputs are only afterSwap's side, amounts, timestamp and reserves plus the policy's own filter mean.",
  "calibration": {
   "what": "fee-neutral diagnostics (k = 0, edges equal LEAN bit for bit) on choose seeds 64000..64127, used only to set target_bps and the gain scale; not counted as settings",
   "all_fills": {
    "mk_mean_bps": 18.4865,
    "bid": 18.3927,
    "ask": 18.5804,
    "sd_per_settlement_bps": 24.51,
    "settlements_per_run_per_side": 4216.7,
    "sd_of_run_means": 0.689,
    "noise_se_of_a_run_mean": 0.267,
    "corr_run_mean_with_lam": 0.801,
    "with_sigma": 0.023,
    "with_size_mean": -0.165
   },
   "not_arb_fills": {
    "mk_mean_bps": 30.3874,
    "sd_per_settlement_bps": 19.61,
    "settlements_per_run_per_side": 2901.5,
    "sd_of_run_means": 0.359,
    "noise_se_of_a_run_mean": 0.257,
    "corr_run_mean_with_lam": -0.773,
    "with_sigma": -0.181
   },
   "arb_fills": {
    "mk_mean_bps": -6.2132,
    "sd_per_settlement_bps": 10.72,
    "settlements_per_run_per_side": 1895.1,
    "sd_of_run_means": 0.368,
    "noise_se_of_a_run_mean": 0.174,
    "corr_run_mean_with_lam": -0.672,
    "with_sigma": -0.45
   },
   "reading": "The run-level markout mostly measures the run's retail arrival rate (fill mix); bid and ask means agree within noise, so a per-side level carries little that the run's rate does not (per-run rate is a spent line)."
  }
 },
 "settings_tried": [
  {
   "name": "all_b002_k+0.5",
   "parameters": {
    "k": 0.5,
    "beta": 0.002,
    "mode": 0,
    "target_bps": 18.49,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.264691,
   "se": 0.036652,
   "dropped_early": true,
   "offset_rms_bps": 0.9244,
   "offset_mean_bps": -0.0517
  },
  {
   "name": "all_b002_k-0.5",
   "parameters": {
    "k": -0.5,
    "beta": 0.002,
    "mode": 0,
    "target_bps": 18.49,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.469624,
   "se": 0.036867,
   "dropped_early": true,
   "offset_rms_bps": 1.0732,
   "offset_mean_bps": 0.0494
  },
  {
   "name": "all_b0005_k+1",
   "parameters": {
    "k": 1.0,
    "beta": 0.0005,
    "mode": 0,
    "target_bps": 18.49,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.267072,
   "se": 0.036823,
   "dropped_early": true,
   "offset_rms_bps": 0.86,
   "offset_mean_bps": -0.0415
  },
  {
   "name": "all_b0005_k-1",
   "parameters": {
    "k": -1.0,
    "beta": 0.0005,
    "mode": 0,
    "target_bps": 18.49,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.484549,
   "se": 0.041292,
   "dropped_early": true,
   "offset_rms_bps": 1.0861,
   "offset_mean_bps": 0.0564
  },
  {
   "name": "ret_b002_k+0.5",
   "parameters": {
    "k": 0.5,
    "beta": 0.002,
    "mode": 0,
    "target_bps": 30.39,
    "cap_bps": 3.0,
    "fills": 0,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.15462,
   "se": 0.02265,
   "dropped_early": true,
   "offset_rms_bps": 0.5621,
   "offset_mean_bps": -0.0086
  },
  {
   "name": "ret_b002_k-0.5",
   "parameters": {
    "k": -0.5,
    "beta": 0.002,
    "mode": 0,
    "target_bps": 30.39,
    "cap_bps": 3.0,
    "fills": 0,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.218396,
   "se": 0.025677,
   "dropped_early": true,
   "offset_rms_bps": 0.6288,
   "offset_mean_bps": -0.0032
  },
  {
   "name": "arb_b002_k+1",
   "parameters": {
    "k": 1.0,
    "beta": 0.002,
    "mode": 0,
    "target_bps": -6.21,
    "cap_bps": 3.0,
    "fills": 2,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.072061,
   "se": 0.018247,
   "dropped_early": true,
   "offset_rms_bps": 0.4179,
   "offset_mean_bps": -0.009
  },
  {
   "name": "arb_b002_k-1",
   "parameters": {
    "k": -1.0,
    "beta": 0.002,
    "mode": 0,
    "target_bps": -6.21,
    "cap_bps": 3.0,
    "fills": 2,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.18886,
   "se": 0.023532,
   "dropped_early": true,
   "offset_rms_bps": 0.4712,
   "offset_mean_bps": -0.0028
  },
  {
   "name": "cross_b005_k+0.25",
   "parameters": {
    "k": 0.25,
    "beta": 0.005,
    "mode": 2,
    "target_bps": 0.0,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.454882,
   "se": 0.039009,
   "dropped_early": true,
   "offset_rms_bps": 1.2941,
   "offset_mean_bps": 0.0
  },
  {
   "name": "cross_b005_k-0.25",
   "parameters": {
    "k": -0.25,
    "beta": 0.005,
    "mode": 2,
    "target_bps": 0.0,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.703373,
   "se": 0.041515,
   "dropped_early": true,
   "offset_rms_bps": 1.4319,
   "offset_mean_bps": 0.0
  },
  {
   "name": "all_b0005_k+0.15",
   "parameters": {
    "k": 0.15,
    "beta": 0.0005,
    "mode": 0,
    "target_bps": 18.49,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.038871,
   "se": 0.01268,
   "dropped_early": true,
   "offset_rms_bps": 0.1414,
   "offset_mean_bps": -0.0059
  },
  {
   "name": "cross_b005_k+0.03",
   "parameters": {
    "k": 0.03,
    "beta": 0.005,
    "mode": 2,
    "target_bps": 0.0,
    "cap_bps": 3.0,
    "fills": 1,
    "beta_slow": 0.0,
    "clip_bps": 50.0
   },
   "n": 128,
   "mean_diff": -0.037393,
   "se": 0.011736,
   "dropped_early": true,
   "offset_rms_bps": 0.1677,
   "offset_mean_bps": 0.0
  }
 ],
 "chosen": {
  "name": "cross_b005_k+0.03",
  "parameters": {
   "k": 0.03,
   "beta": 0.005,
   "mode": 2,
   "target_bps": 0.0,
   "cap_bps": 3.0,
   "fills": 1,
   "beta_slow": 0.0,
   "clip_bps": 50.0
  },
  "rule": "Fixed before the report runs: highest mean_diff among settings reaching n=1024 undropped; none did, so the highest mean_diff at its drop. All 12 settings met mean_diff + 3*se < 0 in the first round of 128 (seeds 64000..64127), each paired with LEAN on the same seeds.",
  "choose": {
   "n": 128,
   "mean_diff": -0.037393,
   "se": 0.011736,
   "dropped_early": true
  },
  "how_the_12_were_spent": "10 as five +k/-k pairs (all fills at beta 0.002 and 0.0005, not-arb fills, arb fills, cross-side), then 2 at the gain a quadratic fit of each pair predicted best (k/k0 = lin/(2|curv|), predicted about +0.007). Both came out negative: the loss is not quadratic in the offset. Loss against rms fee offset: 0.14 bps -> -0.039, 0.17 -> -0.037, 0.42 -> -0.072, 0.56 -> -0.155, 0.86 -> -0.267, 1.29 -> -0.455, roughly proportional to the offset size rather than to its square, so shrinking the gain does not turn the first-order term positive. In every pair the +k sign (raise the fee of a side that marked out low) lost less than -k."
 },
 "report": {
  "vs_lean": {
   "n": 2048,
   "mean_diff": -0.035103,
   "se": 0.003312,
   "seeds_positive": 812,
   "seeds_negative": 1236,
   "base_mean_edge": 536.603391,
   "mean_edge": 536.568287,
   "offset_rms_bps": 0.1698
  },
  "on_age": {
   "n": 2048,
   "mean_diff": -0.037481,
   "se": 0.003495,
   "seeds_positive": 812,
   "seeds_negative": 1236,
   "base_mean_edge": 536.6231,
   "mean_edge": 536.585619,
   "offset_rms_bps": 0.1699
  },
  "seeds": "10000..12047 (2,048), run once for the chosen setting; vs_lean pairs LEAN+markout with LEAN (a0=0.35 ainf=0.35 tau=2), on_age pairs AGE+markout with AGE (a0=0 ainf=0.7 tau=1); se = sd of paired differences (n-1) / sqrt(n); target and gain were set under LEAN and reused on AGE.",
  "aside_age_minus_lean_replica": {
   "n": 2048,
   "mean_diff": 0.019709,
   "se": 0.004066,
   "note": "AGE minus LEAN on the same replica seeds, without markout; a by-product of the baselines, replica not engine"
  },
  "conclusion": "Negative. The least bad of 12 settings loses 0.035 (se 0.003) against LEAN and 0.037 (se 0.003) on AGE on 2,048 replica seeds; 812 of 2,048 seeds positive in both (the sign differs on 632 seeds, so the equal counts are a coincidence)."
 },
 "promote": false,
 "contract_cost": {
  "measured": false,
  "storage_words": "1 to 2 new words (estimate): four pending volumes and two EMAs, packed; 6 unpacked",
  "gas": "about +7,000 to +14,000 on the peak (step-first) callback (estimate, not measured): 5,000 per new storage word read and rewritten in a callback (cold SLOAD 2,100 + SSTORE reset 2,900 under EIP-2929, assuming the engine prices storage that way and each callback starts cold: not checked against the engine), plus two fixed-point ln and two divisions at settlement, two EMA updates, clips and packing. That is about 215,000 to 222,000 of 245,000 from today's 208,000.",
  "characters": "about +900 to +1,300 source characters (estimate): 48,130 to 48,530 of 50,000 from 47,230",
  "runtime_bytes": "about +350 to +600 (estimate): 22,790 to 23,040 of 24,576 from 22,440",
  "note": "It would fit by estimate, but the mechanism is not promoted, so nothing was ported or measured."
 },
 "patch_zb64": "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",
 "patch_info": {
  "against": "fastlean/fastlean.py sha256 d9c758bb280fe24e09c039496f84ab0804173ff70cec24c332f8683f28efa582",
  "diff_sha256": "af93c28a29e9ee01041233480c395f26450c19e5eda895bf2510f21018325fcb",
  "patched_sha256": "50c480c459e9fe3a74130c757d8ae139c2e1617fa7facbd5906ce3ca24472e8f",
  "apply": "patch -p0 < markout.diff from the directory holding fastlean/ (checked: reproduces the tested file byte for byte)",
  "use": "tabs = load(amm, a0=, ainf=, tau=, mk=(k, beta, mode, target_bps, cap_bps, fills, beta_slow, clip_bps)); run_batch(tabs, seeds, diag=True) -> (edges, diagnostics). Chosen: mk=(0.03, 0.005, 2, 0.0, 3.0, 1, 0.0, 50.0).",
  "environment": "CPython 3.12.3, numpy 2.2.6, llvmlite 0.44.0, numba 0.61.2, Linux x86_64"
 },
 "not_done": [
  "Replica only: no Solidity port, no gas/size measurement, no engine run, no leaderboard submission. contract_cost is an estimate.",
  "No setting passed the first round, so no setting was measured on more than 128 choose seeds; the 1,024-seed choose block was used only up to 64127.",
  "Modes 1 (fast minus slow EMA) and 3 (common to both sides) are in the patch but were not run: the 12-setting budget was spent. Not tested either: other horizons than the next trading step, notional-weighted EMAs, a multiplicative instead of additive fee offset, gains below the two small ones tried, arb-only fills at a small gain.",
  "Where the roughly linear loss comes from was not isolated (a constant fee offset was not run, since it is not this mechanism and would have counted as a setting).",
  "The target was calibrated on choose seeds 64000..64127 under LEAN and reused on AGE; the report seeds were not used for any choice.",
  "Parity of the patched file with the unpatched fastlean.py at k = 0 was checked on 16 seeds (64000..64015) and by equality of the k = 0 diagnostic runs with the LEAN baseline on 64000..64127; the CPython LEANBASE parity is the fastlean artifact's own claim and was not re-run here."
 ]
}