{
 "item": "e06-tell-port/o1-a",
 "credit": "Taylor (gtmcknight): replica2.py (config, price and order streams, the reference run) and the policies scored on it, github.com/gtmcknight/amm-sim @4812a6382311624e1506aca131ca35c378f930d9, research/solved. COMBO/TwoComp/QMRef are IdentityMD items built on Taylor's Gaussian filter and qm tables. Engine source: benedictbrady/amm-challenge @6b6921f8.",
 "summary": "Measured on a Python port of the published engine source, not on the Rust binary. On it the wads give away the arbitrageur on BOTH sides. Sell side (isBuy false): the arbitrageur's amountY is fl(fl(reserveY_new - reserveY_old)/gamma), a value on a grid about 1.8e6 wad wide, and every arb trade reproduces through execute_sell_x; a retail trade does so only by coincidence (39 of 26,448). Buy side: both paths call execute_buy_x, but the arbitrageur's amountX is fl(fl(x_virtual - reserveX_old)/gamma), a grid about 14,250 wad wide; every arb trade is on it and 44 of 26,192 retail trades are. The rule 'arb path / arb grid reproduces the wads => arb, else retail' is wrong on 32 of 54,543 first trades of a step (0.059%); COMBO's own call is wrong on 8,821 (16.17%), and the rule corrects 8,818 of them. No policy was rescored with the rule and no contract was written.",
 "hashes": {
  "amm_challenge_git_head": "6b6921f8d463314aa7c96234e1be25a25245f704",
  "amm_sim_git_head": "4812a6382311624e1506aca131ca35c378f930d9",
  "how": "git clone + git checkout <commit>; git rev-parse HEAD printed each value above",
  "combo_artifact_sha256": "d360bea6c8c982717b7b43a8069a87013169c89ee3e4da25622db4d880b936d4",
  "combo_artifact_matches_its_name": true,
  "tc_artifact_sha256": "d3c849db2ac31e567b57e52b80b86e8c24c842e5b4125b9d75c78e3cb07115b9",
  "files": {
   "combo.py": {
    "sha256": "c5b711a0b4fb4783e8879a484bf87a427171f4a11aa5eb5ec3513c24ead1a796",
    "bytes": 5929,
    "stated_by_combo_artifact": "c5b711a0b4fb4783e8879a484bf87a427171f4a11aa5eb5ec3513c24ead1a796",
    "equal": true
   },
   "twocomp.py": {
    "sha256": "9d3c1833321493fb51bbde4e1b4dabc2f8978bd6d774ee2af8dc8aed13f0f0af",
    "bytes": 11202,
    "stated_by_combo_artifact": "9d3c1833321493fb51bbde4e1b4dabc2f8978bd6d774ee2af8dc8aed13f0f0af",
    "equal": true
   },
   "qmref.py": {
    "sha256": "1dfc9b7a3c2237ff7a93dd9f0af54b9bdab16f2ce0a7eb00784cb4432598db92",
    "bytes": 7739,
    "stated_by_combo_artifact": "1dfc9b7a3c2237ff7a93dd9f0af54b9bdab16f2ce0a7eb00784cb4432598db92",
    "equal": true
   },
   "blob.bin": {
    "sha256": "3ac7cb8811ecfb6a17f499aa4e9b70dd55f7fb6432b3aec3b904e11a3dece38e",
    "bytes": 10167,
    "stated_by_combo_artifact": "3ac7cb8811ecfb6a17f499aa4e9b70dd55f7fb6432b3aec3b904e11a3dece38e",
    "equal": true
   }
  },
  "file_origin": "combo.py = first python fence after '## Code' in the COMBO artifact; twocomp.py = the same fence of the TC artifact (d3c849db...), each written with one trailing newline; qmref.py and blob.bin from the goal repository's reference/qt1/ at 31ff8ed1 (URLs in sources.json). qmref.py is hashed only: combo.py imports twocomp.py, which embeds QMRef.",
  "trade_log_sha256_by_seed": {
   "74000": "316e4daf02ab6a7ef2df59265fa4d97450f8cc0fcb05c97070fcb7862b28b440",
   "74001": "4c81cddca0c4bb8e5d51cbe27ea0731802ee77935d6420b35d15469f7dc1679f",
   "74002": "91f93130320f68f359b07b3ec98a1e06b1cc7150f10f7c06ffe9f64417072320",
   "74003": "1faa95b71b8022e6d9657c76d640db26ee9f60935d1cebf9d0e9ec7e6f2976ba",
   "74004": "88d463f11d91aa8695281221ee0ec1ca036de84d8be1db1bc124e7acb98b0483",
   "74005": "f5c2bf2b592aa5daa29e0727ab476f191111d45d34473d78ffc7d8cccd2b1251",
   "74006": "ce9f318a5fc6abb1e38b213f0913ff2b020e1ba01a2bbf2e929a1739c55258a2",
   "74007": "9b4318efc5f531241900eb0eee10516ce8e400d439dbbca44ac87d325c1f9407"
  },
  "trade_log_format": "one JSON line per own-pool trade: [step, isBuy, amountX, amountY, reserveX, reserveY, bidFeeWad_in_force, askFeeWad_in_force, true path (arb|retail), first_of_step]; sha256 over the lines. The logs lived in test/scratch and are not delivered; the bundle regenerates them."
 },
 "port_check": {
  "what": "tellport.py ports cfmm.rs (quote_buy_x, quote_sell_x, quote_x_for_y, execute_buy_x, execute_sell_x, execute_buy_x_with_y, update_fees), arbitrageur.rs (execute_arb, compute_buy_arb, compute_sell_arb), router.rs (split_buy_two_amms, split_sell_two_amms, route_to_two_amms incl. MIN_AMOUNT) and engine.rs's step loop and edge sums, operation for operation on Python floats (IEEE doubles; no fused multiply-add), with Wad::from_f64 as int(v*1e18) and Wad::to_f64 as float(w)/1e18. Pool order as in the engine: submission then normalizer. Config, price path and orders are replica2.run's (same Random streams, same draw order), seeds 74000..74007, 10,000 steps, COMBO vs fixed 30 bps.",
  "combo_inputs": "COMBO.on_trade receives only isBuy, timestamp and wad/1e18 of amountX, amountY, reserveX, reserveY (no arb flag, price or rival spot); its two fees are clamped to [0, 0.1] and truncated to wads, the engine uses float(wad)/1e18, and COMBO's stored fb/fa are set to those same values.",
  "per_seed": [
   {
    "seed": 74000,
    "port_edge": 538.3141543076088,
    "replica2_edge": 538.3141543075919,
    "diff": 1.6825651982799172e-11,
    "normalizer_edge_diff": -1.0118128557223827e-10,
    "own_trades_port": 12044,
    "callbacks_replica2": 12044
   },
   {
    "seed": 74001,
    "port_edge": 480.89299020040215,
    "replica2_edge": 480.8929902003357,
    "diff": 6.644995664828457e-11,
    "normalizer_edge_diff": -1.375042302242946e-10,
    "own_trades_port": 10020,
    "callbacks_replica2": 10020
   },
   {
    "seed": 74002,
    "port_edge": 462.7289150259419,
    "replica2_edge": 462.7289150260431,
    "diff": -1.0123812899109907e-10,
    "normalizer_edge_diff": -2.5977442419389263e-11,
    "own_trades_port": 9724,
    "callbacks_replica2": 9724
   },
   {
    "seed": 74003,
    "port_edge": 676.5968372088644,
    "replica2_edge": 676.5968372089181,
    "diff": -5.377387424232438e-11,
    "normalizer_edge_diff": -3.2741809263825417e-11,
    "own_trades_port": 12129,
    "callbacks_replica2": 12129
   },
   {
    "seed": 74004,
    "port_edge": 568.0998558524459,
    "replica2_edge": 568.0998558524628,
    "diff": -1.693933882052079e-11,
    "normalizer_edge_diff": 4.951061782776378e-11,
    "own_trades_port": 10445,
    "callbacks_replica2": 10445
   },
   {
    "seed": 74005,
    "port_edge": 487.8212127951946,
    "replica2_edge": 487.8212127951575,
    "diff": 3.7061909097246826e-11,
    "normalizer_edge_diff": 5.17843545821961e-11,
    "own_trades_port": 9697,
    "callbacks_replica2": 9697
   },
   {
    "seed": 74006,
    "port_edge": 392.559036684358,
    "replica2_edge": 392.5590366845838,
    "diff": -2.2583890313399024e-10,
    "normalizer_edge_diff": 4.5361048250924796e-11,
    "own_trades_port": 8922,
    "callbacks_replica2": 8922
   },
   {
    "seed": 74007,
    "port_edge": 474.0039622430801,
    "replica2_edge": 474.00396224320366,
    "diff": -1.2357759260339662e-10,
    "normalizer_edge_diff": 9.697487257653847e-11,
    "own_trades_port": 9807,
    "callbacks_replica2": 9807
   }
  ],
  "max_abs_edge_diff": 2.2583890313399024e-10,
  "mean_edge_port": 510.12712053973695,
  "mean_edge_replica2": 510.1271205397871,
  "callback_counts_equal_on_all_seeds": true,
  "own_trades_total": 82788,
  "verdict": "The port's COMBO edge equals replica2.run(seed, Combo('blob.bin'))['edge'] to within 2.3e-10 on each of the 8 seeds, with the same number of own-pool trades on every seed. The residue is expected: replica2 holds K at 1e6 and adds amount*gamma to reserves, where the engine recomputes k = rx*ry and adds amount - amount*fee; replica2 uses untruncated float fees and unrounded amounts.",
  "not_checked": "The port was not run against the Rust engine (the item is test only, no engine); see limitations."
 },
 "matrix": {
  "test": "Per sell-side trade (isBuy false): every double v with int(v*1e18) equal to the previous callback's reserveX wad, to its reserveY wad (afterInitialize's values before the first trade), and to the new amountX / amountY wad; askFee double = float(askFeeWad)/1e18. Path A (arbitrageur): execute_sell_x(amount_x candidate) in source order, match when its amountY, reserveX and reserveY wads equal the reported ones. Path B (retail): execute_buy_x_with_y(amount_y candidate), match when its amountX, reserveX and reserveY wads equal the reported ones.",
  "rows_true_path_columns_match": {
   "all_sell_trades": {
    "arb": {
     "arb_only": 3167,
     "retail_only": 0,
     "both": 12169,
     "neither": 0
    },
    "retail": {
     "arb_only": 0,
     "retail_only": 26409,
     "both": 39,
     "neither": 0
    }
   },
   "first_trade_of_step": {
    "arb": {
     "arb_only": 3167,
     "retail_only": 0,
     "both": 12169,
     "neither": 0
    },
    "retail": {
     "arb_only": 0,
     "retail_only": 12269,
     "both": 19,
     "neither": 0
    }
   }
  },
  "reading": "Every arb trade reproduces through path A (15,336 of 15,336) and no retail trade fails path B. 'Both' is not a tie: path B accepts any Y amount, so an arbitrageur's total_y usually also passes as a retail order of exactly that size (12,169 of 15,336), while a retail order passes path A only when its amountY wad happens to land on the arbitrageur's grid (39 of 26,448 retail sells; 19 of 12,288 first trades). So the informative column is 'path A matches' (arb_only + both).",
  "one_division_rule": {
   "rule": "amountY == int(fl(fl(ry_new - ry_old)/gamma)*1e18) for some candidate doubles of the old and new reserveY wads, gamma = fl(1 - askFee)",
   "all_sell_trades": {
    "arb": {
     "match": 15336,
     "no": 0
    },
    "retail": {
     "match": 39,
     "no": 26409
    }
   },
   "first_trade_of_step": {
    "arb": {
     "match": 15336,
     "no": 0
    },
    "retail": {
     "match": 19,
     "no": 12269
    }
   },
   "note": "Same counts as path A of the full redo."
  }
 },
 "candidates": {
  "doubles_per_wad_sell_trades": {
   "prev_reserveX": {
    "1": 30656,
    "2": 11128
   },
   "prev_reserveY": {
    "1": 30961,
    "2": 10823
   },
   "amountX": {
    "mean": 1.4872,
    "median": 1,
    "p99": 5,
    "max": 591
   },
   "amountY": {
    "mean": 1.214,
    "median": 1,
    "p99": 2,
    "max": 10
   }
  },
  "why": "A reserve of ~100 X or ~10,000 Y times 1e18 exceeds 2^53, so the wad is itself a rounded double and 1 or 2 reserve doubles share it. Amounts below ~0.009 have a product under 2^53 and truncation merges several doubles (up to 591 for the smallest arb amountX seen).",
  "path_evaluations_per_sell_trade": {
   "mean": 2.775,
   "max": 8,
   "n_trades": 41784
  },
  "collapsing": "Amount candidates that give the same intermediate values (fl(rx - a) on path A; (fl(ry + a*gamma), fl(ry + (a - a*fee))) on path B; both monotone in a) are tried once. brute.py tries every candidate double instead: seed 74000, 6,118 sell trades, 25,760 evaluations (max 601 per trade), 0 verdicts differ; seed 74005, 4,945 sell trades, 21,776 evaluations (max 1,190), 0 differ.",
  "rule": "sell side: path A reproduces the wads => arbitrageur, otherwise retail. buy side (see buy_side.closed_form_amount): amountX on the arbitrageur grid => arbitrageur, otherwise retail.",
  "rule_error_rate_first_trades": {
   "sell": {
    "n": 27624,
    "wrong": 19,
    "pct": 0.0688,
    "missed_arbs": 0,
    "retail_called_arb": 19
   },
   "buy": {
    "n": 26919,
    "wrong": 13,
    "pct": 0.0483,
    "missed_arbs": 0,
    "retail_called_arb": 13
   },
   "all": {
    "n": 54543,
    "wrong": 32,
    "pct": 0.0587
   }
  },
  "strict_rule_sell_first_trades": {
   "rule": "decide only on 'arb_only' / 'retail_only'",
   "right": 15436,
   "wrong": 0,
   "undetermined": 12188,
   "note": "Undetermined on every 'both'; of those, 12,169 are arbs and 19 retail, so reading 'both' as arb is the rule above."
  },
  "false_positives": {
   "sell_amountY_wad": {
    "n_all": 39,
    "min": 2527822385111684096,
    "median": 23806871567805091840,
    "max": 771391126790673268736
   },
   "buy_amountX_wad": {
    "n_all": 44,
    "min": 28300283275408860,
    "median": 188705850885815584,
    "max": 1813683368819527936
   },
   "mechanism": "A wad above 2^53 is a multiple of the double's ulp, so a large amount has few distinct wads per grid cell: chance of coincidence is about ulp(amount*1e18) / grid, grid = 2^-39*1e18/gamma ~ 1.82e6 wad for amountY (reserveY in [8192,16384)) and 2^-46*1e18/gamma ~ 14,250 wad for amountX (reserveX in [64,128)). By that estimate roughly 0.2% for a 20 Y sell-side order and 7% near 600 Y; about 1 to 2% for a 1 X buy-side order. The rule is weakest on the largest retail orders; rates by size were not tabulated (39 and 44 events)."
  }
 },
 "combo_errors": {
  "definition": "First own trade of a step. COMBO's call = its filter's hard classification (pi > 0.5), read as cnt == 0 after the callback; the 4 first trades at step 0 (dt = 0, no classification) count as 'retail'. Error = call differs from the true path.",
  "all": {
   "n": 54543,
   "errors": 8821,
   "pct": 16.1726
  },
  "sell_side": {
   "n": 27624,
   "errors": 4440,
   "pct": 16.073,
   "true_arb_called_retail": 1963,
   "true_retail_called_arb": 2477
  },
  "buy_side": {
   "n": 26919,
   "errors": 4381,
   "pct": 16.2748,
   "true_arb_called_retail": 2002,
   "true_retail_called_arb": 2379
  },
  "share_removed": {
   "sell_side_test_only": {
    "fixed": 4438,
    "of_sell_errors_pct": 99.955,
    "of_all_errors_pct": 50.3118
   },
   "buy_side_grid_only": {
    "fixed": 4380,
    "of_buy_errors_pct": 99.9772,
    "of_all_errors_pct": 49.6542
   },
   "both": {
    "fixed": 8818,
    "of_all_errors_pct": 99.966,
    "left": 3
   }
  },
  "note": "Counts of classification errors only. What the corrected flag is worth in edge was not measured here; Taylor's README gives +6.98 vs +3.77 over HA for the Gaussian filter with and without the true flag."
 },
 "buy_side": {
  "answer": "Yes, a tell was found: the arbitrageur's closed-form amount. The router's split gave none, and MIN_AMOUNT identifies 12 arb trades in 14,812.",
  "tests": [
   {
    "name": "path_redo",
    "what": "execute_buy_x from candidate old reserves and amountX candidates, compare amountY/reserveX/reserveY wads",
    "all": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 26192,
      "no": 0
     }
    },
    "first": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 12107,
      "no": 0
     }
    },
    "result": "No tell, as expected: both paths run the same function and every trade reproduces. It confirms the port inverts the wads on this side too."
   },
   {
    "name": "closed_form_amount",
    "what": "compute_sell_arb makes amount_x = fl(fl(x_virtual - rx)/gamma), gamma = fl(1 - bidFee). x_virtual - rx is exact and a multiple of ulp(rx) (2^-46 for rx in [64,128)), so the arbitrageur's amountX lies on a grid ~14,250 wad apart. Test: for each candidate rx, some double x_virtual within 4 ulps of rx + amountX/1e18*gamma gives int(fl(fl(x_virtual - rx)/gamma)*1e18) == amountX.",
    "all": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 44,
      "no": 26148
     }
    },
    "first": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 13,
      "no": 12094
     }
    },
    "result": "Tell: all 14,812 arb trades match; 44 of 26,192 retail trades (0.17%), 13 of 12,107 first trades (0.11%)."
   },
   {
    "name": "closed_form_amount_plus_redo",
    "what": "as above, and execute_buy_x of that exact grid double must also reproduce amountY/reserveX/reserveY",
    "all": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 44,
      "no": 26148
     }
    },
    "first": {
     "arb": {
      "match": 14812,
      "no": 0
     },
     "retail": {
      "match": 13,
      "no": 12094
     }
    },
    "result": "Removes none of the 44 coincidences."
   },
   {
    "name": "router_split",
    "what": "split_sell_two_amms gives x1 = fl(numerator/denominator) from the rival's reserve doubles and the order's total_x = size/fair_price; none of the three is in TradeInfo and the rival's reserves move on trades the strategy never sees, so the split cannot be redone from wads. Tried instead a structure statistic on first trades: trailing zero bits of the amountX wad >= 8.",
    "first": {
     "arb": {
      "ge8": 591,
      "lt8": 14221
     },
     "retail": {
      "ge8": 807,
      "lt8": 11300
     }
    },
    "result": "No tell found (4.0% of arbs vs 6.7% of retail; the statistic follows trade size, since large wads are multiples of the double ulp). The split only shows as the absence of the arbitrageur grid."
   },
   {
    "name": "MIN_AMOUNT",
    "what": "the router sends our pool x1 only if x1 > 0.0001 (y1 > 0.0001 on the sell side), the arbitrageur has no floor: amountX <= 1e14 wad on a buy (amountY <= 1e14 on a sell) can only be the arbitrageur",
    "buy_first": {
     "arb": {
      "le_min": 12,
      "gt_min": 14800
     },
     "retail": {
      "le_min": 0,
      "gt_min": 12107
     }
    },
    "sell_first": {
     "arb": {
      "le_min": 0,
      "gt_min": 15336
     },
     "retail": {
      "le_min": 0,
      "gt_min": 12288
     }
    },
    "result": "Exact but almost never fires: 12 of 14,812 buy-side arbs, 0 of 15,336 sell-side arbs, and never on retail."
   }
  ],
  "not_tried": "Whether x_virtual must also be sqrt(fl(fl(k*gamma)/p)) for some double p. The square root and the division each send many inputs to one output, so it should exclude little; not measured."
 },
 "contract_arithmetic": {
  "needed": [
   "Wad to double: for a wad W, the doubles v with trunc(RN(v * 1e18)) == W (RN = round to nearest even at 53 bits; 1e18 is exact in a double). 1 or 2 candidates for a reserve wad; in the two rules below amounts are only compared as wads, never inverted.",
   "Fee double: f = RN(RN(feeWad) / 1e18) (the i128-to-f64 cast rounds once when feeWad >= 2^53, the division rounds again); gamma = RN(1 - f). The contract knows its own returned fee wads exactly.",
   "Sell rule (isBuy false): d = ry_new - ry_old, exact; t = RN(d / gamma); compare trunc(RN(t * 1e18)) with amountY, over at most 2 x 2 reserveY candidates. One correctly rounded division and one correctly rounded multiplication per pair.",
   "Buy rule (isBuy true): u = ulp(rx_old); n near amountX * gamma / (1e18 * u); for the few neighbouring integers n: a = RN(n * u / gamma), compare trunc(RN(a * 1e18)) with amountX, over at most 2 reserveX candidates. One division and one multiplication per n.",
   "The full path redo additionally needs RN products and quotients k = RN(rx*ry), RN(k / new_rx), RN(total_y - net_y) and so on; the two rules above gave the same counts as the full redo on these 8 seeds."
  ],
  "in_solidity": "All of it is integer work: mantissa/exponent pairs, mulDiv, a 53-bit round-to-nearest-even. No ln, exp or sqrt. Not written, not gas-measured and not checked against the engine here.",
  "state_needed": "previous reserveX and reserveY wads and the fee wads last returned."
 },
 "readme_rules": {
  "source": "amm-challenge README.md at 6b6921f8, quoted with line numbers",
  "lines": [
   [
    115,
    "`afterInitialize` is called once at simulation start — return your opening `(bidFee, askFee)`. Then `afterSwap` is called after every trade that hits your AMM. You see what just happened and return updated fees for the next trade."
   ],
   [
    119,
    "| `isBuy` | `true` if AMM bought X (trader sold X to you) |"
   ],
   [
    120,
    "| `amountX` | X traded (WAD precision, 1e18 = 1 unit) |"
   ],
   [
    121,
    "| `amountY` | Y traded |"
   ],
   [
    122,
    "| `timestamp` | Step number |"
   ],
   [
    123,
    "| `reserveX`, `reserveY` | Post-trade reserves |"
   ],
   [
    125,
    "Return fees in WAD: `30 * BPS` = 30 basis points. Max fee is 10%."
   ],
   [
    127,
    "You get 32 storage slots (`slots[0..31]`) and helpers like `wmul`, `wdiv`, `sqrt`."
   ]
  ],
  "reading": "The README lists the six TradeInfo fields and 32 storage slots as what a strategy sees and keeps. Both rules use only those fields, the previous callback's reserves and the strategy's own fees. The README says nothing for or against reading rounding patterns in them; whether the organisers accept it is not stated there and was not asked."
 },
 "limitations": [
  "Port, not engine: everything is measured on tellport.py. It was checked against replica2.run (edges within 2.3e-10, equal trade counts) and against the source by reading, not against the Rust binary. The tell is a property of floating-point rounding, so one reordered operation or a fused multiply-add in the scoring build would change it; before any contract work, log real TradeInfo wads from the engine wheel and run the two rules on them.",
  "The board's scorer is assumed to run this source at 6b6921f8; if it differs in cfmm.rs, arbitrageur.rs or wad.rs the result does not transfer.",
  "Streams are replica2's (Python Random), not the engine's RNG; 8 seeds, 82,788 own trades, one policy (COMBO). The 100% arb-match rates are counts on this sample, not a proof.",
  "COMBO's fee wads here are its float fees truncated to wads; a Solidity port returns slightly different wads. The mechanism does not depend on the fee values, but the counts would move.",
  "False positives (retail read as arb) grow with order size, where the revenue is; a policy should treat a match on a very large amount as a likelihood ratio of about grid/ulp rather than a certainty. Not quantified by size.",
  "No policy was rescored with the rule, on the replica or the engine: this item measures the classification only. Gate Q and Gate F do not apply (no policy change, no contract).",
  "The trade logs (8 files, one line per trade) are not delivered; their sha256 values are in hashes and the bundle regenerates them."
 ],
 "gate_p": {
  "pass": true,
  "what": "unmodified python3 -I gates.py in research/solved at 4812a638 printed the README's '## Gates' table (seeds 10000..10002, four columns) digit for digit",
  "rows": [
   "10000  448.261189  443.455598  443.522608  443.663520",
   "10001  576.779199  571.463409  571.623551  571.977293",
   "10002  531.886497  525.168028  525.865859  526.411631"
  ]
 },
 "environment": {
  "python": "CPython 3.12.3, Linux x86_64, python3 -I, standard library only",
  "runtime": "all 8 seeds (port run, replica2 run, test) 12.4 s wall on 4 cores; no command over 13 s",
  "state": "test/scratch/ (dl/, w/, state/), never /tmp"
 },
 "code": {
  "format": "base64(zlib(JSON object {filename: source text}, sort_keys)); files tellport.py (port, logger, tests; run: python3 -I tellport.py <amm-sim>/research/solved <dir with combo.py twocomp.py blob.bin and a sibling state/ dir> out.json 74000 74008) and brute.py",
  "sha256_of_zlib_bytes": "ec6390eff50a7d5b32ce3331368c4af759542302b3dc1a549b2325dcbec30ecf",
  "file_sha256": {
   "tellport.py": "5101e0afb19641e85a37aaca2db43ff57914f9a44ac5102e77d5a90f70c6d332",
   "brute.py": "aa10e58fd197b794efc1f5320d55bb606c6de2c29f55a09d5a98f6361e104cc9"
  },
  "zlib_base64": "eNrNXAtz20aS/iuzSeUIyCRFUrajUKFvbW9Sl6p14nN8u3bJKhRIgiRiPBgApIDk8t+vv54ZYAYEJcrx3p0SS8A8evo1Pd0zPfj9i3m2K4LhtvpiKr74wP/pEjEYiMUmWHwUxcYvRBFE0TbNimEWbHPHFU6aBIKesyAPksIvwn0gtkEmlmFehMmiEGFSBFkcLEO/CMTej3aBK9bUKv+QFJtA5H5MvwjoIA+X1CDIluGiyIWfiyKrwmQtvvvHd2/ei4WfLMMlYCzT3TwKRLoSAbWuxK2/7Is0EUAkD4Ll8EPyMqPxiql461dRmglnXcSLj0m43hRuH8hG4cKfgDYCKrYpvYZB3ie0is1uPlyk8XnT49yPY8ItFn99fDme+E8vLmmAXe6vg6nYVsUmTS7E4AdRs+vtOVjhZ4vNeZ5G+2ApbsXXj0ejkWTrhySMwT+RV8QB+jXc+sVmGCZ5kBXOqI/yoZ+t99eTG/dK3NVgfOPW0LRYwLe3H5JVlsaC6JinQjV4iZe6IoqCRRGmSd5U7yCnD8kyWElanMydfkgE/bx+1xev3/fF98/74jk9P6fnN/SXpDIT2XVvW/Zu+vxQqQc//6ifdJ2v6zJdklGJHGAVBATp7fB2snK+f05Ur4nnPhetFpEfb0djZzwciQFaUjVJXLb3l1diPlnxC/2V0MqoL8oNly0yP1kHzut31Kmi4soufk/FPhX7VvFztJ5T8dwufu9K+H42B91BQb+/96M8uBIJPY4ULaRv5Zy0XshuCptHYqzZiZ+spB6EsVPO3aYUfSujr0K51Zf7V6p/NSdkPwKfUpxRsd0MAH0DoCK2AyATpmD6gJmIRzMxPmwUrqjdt0QuyQPQxTOMPSWdSmi+74LDHklw6zG99Gsg/CtZAAI+inNVi8LCQ5mqHBzQogaX7SQCd41apIUfKYjocS6V6goq5Pkx1J3qdKuBbNU5om5z/5jUmFTSUR1cMZvRXGEbg2JJPpe+edeUViQOp8GjQc+VTd9Plca9zdpjQrxzQ7xKae8R7/xE8d4rUzCX0fdJ9RR3a2HXsq2uROmlu0IrgGzRObJsdzKfubnk8juby03NAad9CIHwhSWpGSwnc8Nget9lCfiO5aLoi4RMNS0t1IiWM6e2wBcw0cFyHfRFlK7ZWmS7xINFddC+L82uY9h0wqF3Po/S+XAeJj2XZn+OsbHoOdSznClL7NBKRe+V/e6Xs+sbfqj4IaAFNacnrBRYSAFotZKKDZt0JeJS2iboSgZVIUSVchAbyQyH+YsdWeI2v/0xkU7/PKYKC7RXBHnhZLQAFbCbE6qnfzB9er244mFJsRI1buyXTlxSI7ce0ZGAmfWOBOJOJfKNRgZkVaeSFFm4zcD333tgam8qJG97EqvMXwZ5T8PgXqijN095E6qSSlEZZOSo9Ka6ISPvYY31wM2dz+si1RMtVE0keOTPyGGoFOT04Pt0dcl3sZMX1z0WS+/G/YPo/qIvvqidJtPBMgrhYwWlT97Sa/YoBK/J5OHMgyQABXMavWJPZLHxafGm2S7++nT+9JvJeHUpFqs4HmbkwJDChoToOthleP+QZDQPAjwL55GAu0U9wyRAQV4EW1KGdMsT5J/+cjqFc+Ctnj4+L1L8IY3zBdMNpVkHJHo0ffsf34m33/1MXoYDw7TPMUX8MBLsW9BMG0TkmEWCxiaXLVm7dztkoN10yRyS9SI4T7MleZF5kQV+TJTRtIKCrsK1y0iAFu240RRapDQAnMCwIOCnuXGTi/H46eRxMH4yeuov/PHFeOFfPFlcfH25+uZitPwG7LM9OXcoXv706sVPZNre3qY0tbf09J+v3pDL5GeB+GFJihUW1au/ERpBnIv5LowKYCXJ7uViRQVEFlPgkxebE29eRz5Ny8aVxASjBn62FFFIgie7lSZRNRTi0Os0dajL8STxD3/JUzJfh95nn6Znselj7VimMUbNdgtSebTvi42fb2j4vijCODjBb/yQ/PP5376nOT8OxpdX4sXrn/E8EmdnYvz4Srx6/s77/rvvmrKvqeyHH73nr376rx/fCjb5o9FY+p+w1nt3qs0wpv6eTDYGcM114EtbbafC4fhCNoUnDCXG33A8uVSgaQG8bUCvotQvqIDkyOi3QcuJMKUCsjUrcnkkUNlcvUjA7KfemrBh/Mhdj8PEUdT3xS0MPprXfu266QCXiizkWnzLjzCCgv1eLnwmxrpw7YLfBCHPxT/8JIwiX5l0gPZXJBAvTMIi9KPwt8AhSYdktcKqGeqChAAZ9eundv/81t+iZxHe3Uvj8RqTsfqZzEURrCuFjlQ6PbsHeVFR4MY8l5O3IgO3CdV0hlfPweLKXwRkebAeZbCJpIpTTOyQ2B0sJWRqfA5Ng5FE51W6y2gBJ1v1Ay11qAbVBXoEOc9O0u5kQcjRYLoe0xBt8gLmQ/nv8/OVzx0wmwo01sixcuWGGRW3xHpqRxa5oskZDPUk06z0WAyeB0YSwYQRvZIjkGPJG1IJKT79psV7qGvYxZCPKM79cOlJ/+9HCnBR9MuOHI6lDj6MwWiyY6AVTdqVb3qA6K30E3NpNdeTCet4q86v65r+jOpwBTCYP/AfVZGvinwqUkpCo/sPU8Z8yKifSZhoi+eaVe5dqtkgGebefFfR4ATdp78FVg16Zje1CE1qag6S7AeKlIK0uEAwYzjFkpPUTjZJE+kFOHooprx01UPlykHxkunSrLIZacizxgNqKEdYICghW8gGCC+0ElQ5vWMBELebIJHKLleRBTwBaDAXElAjvrQ4qzSimawvv3/1airu/flSexbdGp2wT5VjymtWmwLJh4l0SfGHdVkZB9COR5SpwJAfZTyBx3m4ZAb5OUJb20RJ0P6qlC1WlVw80E364HqewD8zX7Ngb7xC3B585MEYr/6uVJUNrabWWprG+gvNp3UKJEDW8rHC1kFfSJ3R9A4PJoGaASZBRHK/plhNyDkBVo++a9Bg9weqv+5ScmJJKb0SkpEBpFdaWK/q4jrEahaePn4Zms87MlBgxszYkunYkLHGkO3uHQDhNjheo6QiyKbFR+Yhb2uAsUZoyaWPJIgjuwmVijhZq1TMWR1MD4eb9U0kQA/IkACeGQuxpuGA6xyFPIDtvG2ii55Jcu7g1AEfTNmQuvwrZGMyelAje+rODdC0xrX3bI6Oe2TL5kBsql2/e/emEUzpUdDrVYZkqm7JnIDb/4UUJFtrHO09lkprt5wI1T1bL0qU7c0XPRFKayJUxkQoT5kIQRksdl0GCCuiyXM14aw9uHxoWq96Dlk8q6ydIYV1Y607LYq5l2ZaWhiPmbYeciWh96atWosGMzmqoZ8hbC92iaS9r1GVr9xa+wAdK4Nl7ndbnGV48E6dIsQ2BKjvNW6U9lhM9h5amjZ/66nRyWHVv5vF7W3Oo0yurH3TozwezAzDITV1plVVrtsW19tsZue2k896e/VTOS25cA+rWRzebVhsbAPSZnh5h0Jr+1MbH4vf5WkqbZmAu9nNEP8kr0ulxAbfqz+n04qJR/ht9mGXnniZWCclwcJyzBT3pLNHEWGSFlzb2vBehRnvqxbh9cWN+Mus9vgs349rWycrPB5vxxYzridXC1ukeBndIL7A0xhPXDbBaRaXPcYTlz2hJ3KbZsqto/VhxqtE/3AvW/3AWZ1JnxUcmK2SvqRhxr8pfCxn0v9jJLaVfuNDwDrQO+J6csRE4dInO5yKOibNVmPw67gYqPa6J8Oc3o2NmSy9kk10WNRupMuVdz/0t9sgWTrUh6MZc8ZSK9LYGJFOmMlp2o5m7O1RrY+52GbpiqIo8ssaPatDRx8REGJK/MV82vLWegb/RC+lUEgUf8uDT223QZ3MmS4DYNlOQ+0rHHUVgB6g32cybj25815shvmvWeHAG3AkoDMGwFG/XiSNQ5nypFjBHs6Ag32uZlliokfDb75xOxYnT7H1c61KSn5WNMGsGuj+FkzV/E6QzIF42Fp5rWUXas8q3w1BFcrB9LGGVpRnD1AUO/76XIpSevswK3Z+1FIW5WWS0rCuXNV+VdNhwAG7IXrZ5MBdP1mLlFdoq8WfdAdrnZBtB23d+LMaYaP3iQphtZPmLN9GYQHofFCGAzLt7xyYs+Zwp+7kFbcpLfKx2rEpCUQ1BlvH0oaN2YSVBLWaoHgiiyd1xLYe1zrG+jfWdmpil0+4XPZ5PrZ0qBxDifCrGlPP5xO7doJa/KomzakgGtnMr41FHRRlBIeGOqfGsiDZxZg1BMohah5JqPXh+4CGvyIfAweUhM0jbrhWXfeGD3suJnKPndvOmkgH8M9R2vSBkcO+/l5GQI1wLHnuzdB0b8oVdqQl2LIl2EO5ymPOzy5YZVcOBIty2eeFLdiqFmwJwb6wBVvVgi0Nwb44ItiyJdgXEOyLQ8GWLcGWEGx5imDLzyHY8ohgy0awLC2Ix+E94Tz8LegLLWLTFzEFqzqltVgbZ+RaejHIKnCVbypD+Oubmqs0krF27GiwHYRxaDuAjW06d2NafJqTt5a/xvEA6UZnGIRxiBS7B9bocMoHjco548FpGKlQ7Cu7teth4zK5H5fJEVwmJ+IyYd7cgQvnGrSdFN79It6pZbCp3hNt+4bXnfPZonH/cH47+wcwej9unB1F4+TGbTF6/3BGO/sHcHg/uQsJNXl4L0XNGTtJRp4FIq0FSQn5bDyiH9c6Q2zyFpCyQBEoqUGTNkDwernKDyBwSCDgUxUriUA4nCGyzPxbijT5metd69huAWskj8SHb/iPMx55hA/+kbEBxoouKIgXBz4M0SIb7pKQ4n1q/g02yCZkU8lIUjBl146GT/tC1uXhml06q5ZGubycsBUaER8u1VjbQ7QYE7Ib3TWcBabi7Cxc8UnHaPgE+5c8rPp7JeKdFyXaklOM5dRkwdTKLuPhRP6+EkEsSeLmQbl1BvSukeTj/dqu5zscc+GsyenRcxzmeZgmvX7rrNjR4ncYoz541m+Y65IxZqD8Z9RsPCZpVoOn55iPVjICr47EnWMdCRd1VHR9c8VvxtEMPN40s0qUnSCDTF1+N0mZyn1bc3gu+qPJBS2a9Dyl3ubuxlacGayUgnpUS2ibDdf+Ls/lliuUppUsSisFwDuEUh9ot9P+4LCqY7Aeousr9j7p7SBopilVHM51bm1G98yFa4DFod4NtpUGaGQEoDLt7FcoJS11UiENyLebMAqo+pnUpBbCMi0R3c+O9Ie4FEmQk6ZOpiD1bPZ4Bu/brGHrzmOQKkB+ez9DirrD8wHcnuAsb1fZhHBuxpOOLFtes3m8Ln9AC0gxuouPduqhTCpUmgqz+aUYtH7qRKyDGpViMpmbWTQyvYcszdZffHR63/7a0yk/Q1WypJK9616PblQaOJ/1HwWwPAAAkHMDgBcFfl44c1Let7Y55woxp5iLBEg+USLmOAobSbuO7UU5uIvSt8Lh3JBcxClpIvL8Q3kQLq8CuKb9xrQmvZovfTGfcuqQhKTTGmofak14SfCGZmywFM5Jf3H+PG5rLbb+W2oUpSrNkXoOBK1lo8NZtHaiFIrzdirmtBJ9PGgAIER8cxhkt2CkohRI0ayYdLotjMdDEFdAkTDZgfAmVKzpwpjH2oQ2PnIg5gLVPxNjY7yYj/MdHg2Qz891r3pAaqJHZMzovWkh00Elq3W5YtUm/JB4GbZsf/9DJWLJCX9rKxwN3uexDZ3LkTz0/O9/V2qUUyDA6sf5ZmfILuIs1VskDXNy7HqX7nI4L5bGYRUiFIbrAJlkTWptvR1g7M+OcD5I87KVd4ZlHBwyJswtrV7mK6/nxNyx7dlFQeLQ4MQ7McEiR0oEXBbUMzPNJhVe32JzNbPYpy588F0eySGKWWzO3Xe/R6bcqTSseoLG/lasRLpHS8XdKB0OSbYOJ7pGKiwNft2FBIFAc6aVvPEj7/Woez5qqhPXycsuxE9OPfIZJ12Tm2Ik4VqS0XETLfL80JDIRoFmpaufSTVcHW5JVc4Lc3pRP2pKf1YbTl8ZbtOtY4tiFUFbVhvLPY5cU42p1QYTBA3HrXZX5uvGbWm/PQNjnk6YTe3JxEtb45wTwrHCm8mMiUp4nk2LGIolqZMtWNHAl81x/72dDv6/e1Ho4JrQ0RP3+ipQ50WgzmtAnZeA2leAkOONZP3ezXUJgZaQxfhGOS+qlrC+rlBbGbVmf5Cs5eCjoc8NXQ0BnND1c9TPI8Or77iGxGc1/x/vISEHhFxIQnl6LNPsyE47uR/vCJG+eI/rbFtqsTw8QzOuOcGQSVn2tRvgT9XNo65LMQf3noiH3TdjPu3y02e+APXAS1Cf8SLUgy9DqQPsyZFsAVrxyonBk4z3LXU+y+QoAndesJoc3vmZdNyiujrih0FHaULdq6PWTlSTWkQ6Ck19d4+mzhtNlQbG1FTHvlDVFx23lu7T4/lD9PgEEcochI78o5Ozj+68+PXAy19qHWhUV/HlSmubf1zPVIbEQ3TtyCWzOzWtuU5maZpxM0ib9WCvzO6X2IEOY1oByHsaLMN9iA0G8noi8nwlJe/ZGaWhVhH+p1WRjYSrZzQFS1CvPI0D47Z0VkGHenrHKt5GQbNgVBNY9omxxL3RS9xpawBa/Wa20gA71oqlUs/f5vBj1aJxMAeXKtdM83VZkydn+7Qh4o77erKNdlf4YIy8lbzjTvOLU12Vebj8RFflRdfxLRWNxqbvIon8DH6LZskybQS9zsKl/eaZDcz8J0dmPvSxXoqTLKFDsuH7QaorifcZNrUWG3Vb4kKk9CfjWxf/3pGxB9MyGl/Zh+Dmqnlasm9nqu+x02KD7uMWpTYdygQbl3MNKzJoJwqqIZqkwIcsVMq7GyntqQX6Zxy6L8UiSvNgCSDx1Dy6l7bEPttvLErfOPX3dUDmzymsE6YlL/cjzSZ/1KwTiMqvqY7irx1yqpBEsB8d3aJ73DYYO73NnARlwYlMzk5eWhuGycqVex2tBsu+GBgtFlgEr6nX8sZMWikOUsqYu3sgs2hvSbIxp7qBaK9e0hNrGSyUWCbr3VSNaNTUM9K+1P1pjvcRP2aZTj/BVXakGOWU7Bu6f6/7EVrWQznUvH3IhuYuxwv8MbaZmZemJYqxZWparQPTj/I+N+k3DbX99xM/qvJAnTbJy5HeEiezt/Rb09PxqQ2u7v4IRw1E7/jI+5D6SAp3A9+oiXvsWxy8IxSlfK2KANk3w69EMeIMxTgY4pd5DKFvm3feNQcExPjFuKu7uv+TFA63NmWZLOZN+KjXg/rOU94XZ+SOnp195LtraCyjXb07vNviknpzSUq3VkdDfNcN4zJ+6IbTojc4umtOAYH2xEab4pStcfiNpU5dTR3mG3/y5KmmjLfuUvKqnJqZw+F5XpATdE7s8r5a8k3YqCe+0vfHb3t8O3TVcmha1+TrPSDc+Jvx9djhchfT7LmmFb/Ayo8dw+YqvXuKl9D2KeqNECiaAZPTPwnmjQuSPnxIeq3Dh+FtFhaBA+yIWRuVhcvvwyBZpCQKt962+AxfGpCgXkKaun2zQHWwrsh2fERTk0bzCSuD0/OjqEdSkBS66nMEil5110C2MSwcaS/NQLYUjoKszrbYaLDla5hm30KRdfp7B62TspbriE2+1iaX3UG6HL05eTY9NmEUXQID+P6MO5DycG+vrpbF8qSqqWk6JEEIN6kl4DiRzIMawYnRd6oPz6ByMD9fdJjnl9ec9f7fX+Xyf8wBTrcGB/ugxb05Ei6qrp5kyzEIPXb3mB7FP0VS2rsXMgU+R8FGAaoZLvFBwlwXXNYJV33wQZ93dnG+p10iuatMqOIBcpafpZIbBXyuiG3vdLlbKDcW7itcW+umpZxXWWtQ1o6ZqQM2CkYTSx+4le2Z6I2XWtk1DGgb76ittjqclBztHRiP2g7d3L2v3LmKwtEwAqgj2ln+Ke3EABjrBP1ilE7SLgAFFScAZW/sQUBPRbdh48ng/zUT4lBJDaIPjs/v1Dp0tNWO0D6mdaWtdc2HZ1SzDoUofsP6oLXq38RAPbrkGRUevn5SbBw+DFOguB1TMjrKVZq9xW8GUzVH18Elc4MGfTYTl4ohUXF5yNC78Oav1834zkvP/rKOgsgz0+7zUgEzRU1glLQ75UldYLMOevR25OniQ3u07C8ZAS15dQqpBY1voVj1JFwpZdngNkuTde+usT2pSSegoFTuGAZaI09GALdBTAXOrIsjd2uyWv31XZRpzXyPajxZrOgBOV3DB5xqxUj8ReF8wCD28w9ZQ10ZY4CQeKYfu2mUjbqtJAP3qNr7GCZs1giJwDtRdQ6AFLVL8AmKtArLVn1LjoDudQizuOiKS1QUwc4pvPOZjgmywkPIM+OEGTP36kbVIndH1RppWDf1dx5ld3q57uHJrOGuXIMnqukwRfx1qRmO2cmtbb4e6eHjC3N/8TGf4cMNFA71ySDOVluOzTwZmsw2w01QLsM1nEjq+3LG9L2UDncp35qzRO2Hm8UcTnR8fw3+eXOKqPz05thQ++vGljP5sMGCPHj+LJNTID+3QJ4iaJJFSJMtxlbRBYomKLqpL1x5v6Rzx2/ygnR0fYbdyxCfiEBOk+fxsuF5sR8mntfTQTbHzTKyZscTwV3zRcvpY4QHJHp8ByUK4XvzRoj11bXH4JRV8qRJNlUhdryLipC8N/LdcqQUUJgXb41AMd4OX6dp5CDv+7LPaRQ8LMFB2y3VgcCcP9BCAo79rQPC++Iay7FJhmu4NwChV7s6UHQyfFyUQ1MQLAPPdtCUwfOUnzmDWcN3zlQ8qKeADh4NtVZF6hNo8gVS5tDniz/+B0A/Sig="
 }
}