# bt.py, the shared harness (Harness Engineer)

## READ THIS FIRST
- **SUPERSEDED 7 Oct 12:50 Bangkok: use lab.py for every test. How-to: http://159.223.88.168/hx-c9ois/fw/lab/lab-howto.md . The rule format below is the same one lab.py takes for event rules.**
- **v1.0 (Harness Engineer, 7 Oct 12:30 Bangkok). A rule test now takes 20 s to 2 min on research-box. Acceptance PASSED: the harness reproduces the live book, A3.12 kit300k and A2.37 within 5% (table below).**
- **One example command** (from Ben's Mac: `~/kookwatch/rb.sh '...'`):
  - `cd /opt/sw/harness && python3 bt.py rules/kit300k.json --sizes --json results/kit300k.json --trades results/kit300k.csv`
- **You write a rule file, not plumbing.** Copy `rules/live_book.json` or `rules/kit300k.json`, change what you test, run. Before any test, search the registry (http://159.223.88.168/hx-c9ois/sw/sw-registry.csv).
- **Three findings from acceptance (please read):**
  1. **A3.12 kit300k was priced with no trading fee.** 69 of 71 live-book pools (and most kit pools) are the 0.01% fee tier, so "the pool's own fee" was 0.01%, not 1%. With the 1% each way the live engine pays: A **+$2,017** a day (not +$2,153), B **+$12,867** (not +$13,457). Still PASS on direction, beats random 100% / 99%.
  2. **The live book's B number depends on where the data stops.** On A3's data to 6 Oct 13:40: +$10,400 a day (tick walk). Same rule, data to 7 Oct 09:39, B = 1 to 6 Oct full days: **+$8,768** a day. Open kit holds were priced at a higher point on 6 Oct 13:40.
  3. **(H3) kit300k does NOT scale to $5k.** Same trades, tick walk, 1% each way, $ a day by ticket: half A $1k +$2,017, $2k +$3,020, **$3k +$3,238 (peak)**, $5k +$1,916; half B $1k +$12,867, $2k +$19,503, **$3k +$21,843 (peak)**, $5k +$17,780. Its ceiling is about $3k a ticket. The live book keeps rising to $5k (A +$7,906, B +$36,902 on A3's window). Every verdict now carries this sweep.
- **Half C so far (7 Oct 00:00 to 12:07, 0.5 days, too few to judge):** live book 0 trades (no coin passed the gate, checked without the army filter too); kit300k 8 trades, mean 0.50x.

## Acceptance (must match within 5%)
| test | target | harness | gap | note |
|---|---|---|---|---|
| live book, A3 data, $1k, A3's own fill (constant product, 1% each way) | A +$2,580 / B +$10,681 | A +$2,580 / B +$10,682 | 0.0% / 0.0% | same 49 + 22 trades |
| live book, tick walk fills | same | A +$2,503 / B +$10,400 | -3.0% / -2.6% | tick walk is the harness default |
| A3.12 kit300k, as A3 ran it (pool fee only) | A +$2,153 / B +$13,457 | A +$2,153 / B +$13,482 | 0.0% / +0.2% | same 91 + 107 trades, random pool 343 / 162, beats random 100% / 99.0% |
| A3.12 kit300k with 1% each way (harness default) | | A +$2,017 / B +$12,867 | -6.3% / -4.4% | finding 1 above |
| A2.37 late bloomers (WETH and USDG pools) | KILL, 20 trades, mean 0.61x | KILL, 19 trades, mean 0.62x | +1% | 18 tokens shared; 2 of A2's pools are not Uniswap v3 WETH/USDG, 1 extra here |

## Rule file (JSON), every field optional except what you change
```
{"name": "kit300k",
 "trigger": {"type": "milestone", "level": 300000, "need": 15000, "pick": "earliest", "fair": false},
 "entry":   {"delay_s": 30, "on": "swap"},
 "filters": [["kit", "in", ["A", "B", "3587"]]],
 "exits":   {"stop": 0.3, "target": 5, "pull": 0.5, "max_h": 12, "hold_kits": ["A", "B", "3587"], "trail": 0.5, "hold_max_h": 48},
 "ticket": 1000, "fill": "tickwalk", "fee_each_way": 0.01,
 "random":  {"draws": 200, "filters": [], "seed": 5},
 "window":  {"start": null, "data_end": null, "entry_end": null, "days_end": null},
 "live_rule": "live_book.json"}
```
- **trigger**: `milestone` = cumulative buys at cap >= `level` reach `need` (one event per token, its earliest pool). `pick`: `earliest` (any pool) or `earliest_new` (pools whose token was born within 72 h of the pool's first swap, the live gate's universe). `fair: true` drops crossings after a pull. `first_swap` = the pool's first trade.
- **entry**: first row (`any`) or first swap (`swap`) at least `delay_s` after the trigger.
- **filters**: `[field, op, value]`, ops `== != < <= > >= in not in`. Fields: `quote` (WETH/USDG), `fee`, `kit` (A, B, 3587, other, unknown), `creator` (pool-create tx signer), `new`, `age_h` (trigger minus pool's first swap), `top` (top receiver share of buys up to the trigger), `nbuys`, `army` (A3 army share at the $1M gate), `cap_trig`, `peak`, `pull_before`, `tok`, `pool`.
- **exits**: read on swap prices, in this order: time, target, stop, pull (in-range quote reserve <= `pull` x entry). Kits in `hold_kits` hold past the target on a `trail` from the peak, or pull, or `hold_max_h`.
- **fill**: `tickwalk` = A3's walk over every initialized tick (positions rebuilt from Mint/Burn ranges) at the end of the entry and exit blocks, pool fee inside the walk, plus `fee_each_way`. `cp` = A3's older constant product on the in-range reserve.
- **window**: Bangkok `"YYYY-MM-DD HH:MM"`. Default: all data. Halves: A to 30 Sep 23:59, B 1 to 6 Oct, C from 7 Oct; A starts 12 Sep 16:29 (block 61,000,000).

## Output (one verdict block)
- Per half: trades, mean and median x, $ a day, without top 1 / top 2, worst day (by exit day, Bangkok), beat random % (200 draws of the same count from the `random.filters` pool, same trigger and exits), live book alone, live + rule combined with combined worst day.
- Size sweep on every verdict (H3): $ a day at $10, $100, $500, $1k, $2k, $3k, $5k on the same trades, each size priced by its own tick walk. `--no-sizes` skips it.
- `--json` and `--trades` write the block and the trade list. Results folder: research-box `/opt/sw/harness/results/`.
- Flags: `--no-random`, `--no-live`, `--no-sizes` (faster).
- Full acceptance output: http://159.223.88.168/hx-c9ois/sw/sw-harness-accept.txt

## Golden dataset (H1)
- research-box `/opt/sw/harness/gold/`: `shards/` raw Swap/Mint/Burn (5.78M rows, 6,918 traded pools, every Uniswap v3 WETH/USDG pool since block 61,000,000), `p/<pool>.pkl` per-pool series + raw events, `idx.json` one row per pool (token, quote, fee, kit, creator, milestones $100k/$300k/$1M/$3M/$10M with fair flag, pull time, peak), `army.json`, `tags.json`.
- Source: Analyst 3's raw rebuild (copied, not re-pulled). Hourly append (cron :07, new pools, new rows, block times, ETH price, supply, army). Daily frozen snapshot 00:10 Bangkok in `snap/` with md5; path in `gold/SNAPSHOT` and in every verdict.
- Fair milestones (A1.25): $5k at $100k, $15k at $300k, $20k at $1M, $30k at $3M, $100k at $10M; pull = a block whose burns take the in-range quote reserve to half or less.

## Limits
- Chain launch to block 61,000,000: 426k pool creates exist (most never trade). Not in the dataset yet; backfill of the ones that traded is the next H1 step (older sample for the learning loop).
- Bundle funder per coin (A1.26) not in yet.
- v4 pools, Pons and hook pools are not in (Uniswap v3 WETH/USDG only).
- Army share: A3's values up to 6 Oct 13:40; later $1M gates computed by the harness every hour (same A3 method, own Transfer pulls).
- Not yet in: a `max_open` slot cap (A3.10). Ask if you need it.

Version: v1.0, 7 Oct 2026 12:30 Bangkok, Harness Engineer. Latest: http://159.223.88.168/hx-c9ois/sw/sw-harness.md
