id: 2758d137e3e646be91fbfc9db3347d4e
parent_id: e8f71d7d83654dc785966db298b4c1db
item_type: 1
item_id: de72ff3ebcbd45689c988e50038e80b0
item_updated_time: 1784277690882
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\"-07-\"],[-1,\"06.\"],[1,\"17.**\"],[0,\" Pro\"]],\"start1\":81,\"start2\":81,\"length1\":11,\"length2\":13},{\"diffs\":[[0,\"tegy is \"],[1,\"**\"],[0,\"Gen 4.\"],[-1,\"7\"],[1,\"8\"],[0,\"** — mat\"]],\"start1\":106,\"start2\":106,\"length1\":23,\"length2\":25},{\"diffs\":[[0,\"lop \"],[-1,\"+ Gen 4 adaptive\"],[1,\"(G47) + formula-based\"],[0,\" pos\"]],\"start1\":152,\"start2\":152,\"length1\":24,\"length2\":29},{\"diffs\":[[0,\"postflop\"],[1,\" (G48)\"],[0,\". The st\"]],\"start1\":178,\"start2\":178,\"length1\":16,\"length2\":22},{\"diffs\":[[0,\"eflop` → `g4\"],[-1,\"_adaptive\"],[1,\"8_formula\"],[0,\"_postflop`.\\\n\"]],\"start1\":259,\"start2\":259,\"length1\":33,\"length2\":33},{\"diffs\":[[0,\"n 4.\"],[-1,\"7 — Matrix-Based Equity Preflop (NEW, 2026-07-06)\\\n\\\nGen 4.7 replaces the NG ranking-table preflop with **pure equity dec\"],[1,\"8 — Formula-Based Postflop + G47 Preflop (PRODUCTION)\\\n\\\nG48 replaces the 80+ parameter Gen 3/4 categorical decision tree with a **unified score formula** + threshold compar\"],[0,\"is\"],[-1,\"i\"],[0,\"ons\"],[-1,\"** from a precomputed 169×169 PEM2 distribution matrix. The strategy chain for cash games is now:\"],[1,\" (~21 parameters). Same equity computation (MC rollouts), only the decision logic changes.\"],[0,\"\\\n\\\n| \"]],\"start1\":298,\"start2\":298,\"length1\":230,\"length2\":274},{\"diffs\":[[0,\"op |\"],[-1,\" **NEW:\"],[0,\" PEM\"]],\"start1\":734,\"start2\":734,\"length1\":15,\"length2\":8},{\"diffs\":[[0,\"resholds\"],[-1,\"**\"],[0,\" |\\\n| 3 |\"]],\"start1\":780,\"start2\":780,\"length1\":18,\"length2\":16},{\"diffs\":[[0,\" 3 | `g4\"],[-1,\"_adaptive\"],[1,\"8_formula\"],[0,\"_postflo\"]],\"start1\":792,\"start2\":792,\"length1\":25,\"length2\":25},{\"diffs\":[[0,\"p | \"],[-1,\"Gen 4 adaptive (unch\"],[1,\"**NEW: formula-based decisions with observer r\"],[0,\"ange\"],[-1,\"d)\"],[1,\"s**\"],[0,\" |\\\n\\\n\"],[-1,\"> **Note:** `g1_short_stack_preflop` was **removed** from the cash config. Its static raise/fold ranges blocked G47 from evaluating push/fold spots (e.g. folding 55 from BTN at 10 BB). Now G47 handles all preflop decisions\"],[1,\"### G48 Unified Score Formulas\\\n\\\n**value_score** (for betting/raising):\\\n```\\\nvalue = hs × (1 − npot_w × npot) + nutredraw_w × nutpot × (1 − hs) − behind_penalty_w × (1 − hs) × (1 − ppot)\\\n```\\\n\\\n**draw_score** (for semi-bluffing and calling with draws):\\\n```\\\ndraw_quality = nutpot / (nutpot + rpot + ε)\\\ndraw_score = ppot × draw_quality × ppot_weight\\\n```\\\n\\\n**combined = value_score + draw_score** — single threshold comparison replaces 7 first-in branches and 5 raised-pot branches.\\\n\\\n### G48 Key Features\\\n- **Behind-penalty** (`behind_penalty_weight=0.15`): continuous penalty for hands unlikely to improve when behind\\\n- **Board-hit boost** (`narrow_board_hit_boost=3.0`): range narrowing boosts hands matching top board card (×3 weight), penalizes without (×1/3)\\\n- **Draw-heavy board trap guard**: `board_is_drawy()` guards ALL trap paths\\\n- **Per-player looseness**: `aggressor_vpip(ctx)` keys off bettor's individual VPIP\\\n- **Observer-based range equity**: shares range computation with G45\\\n\\\n### G48 Harrington-Aligned Preflop Sizing (2026-07-16)\\\n- Standard open: **3BB** (was 2.5)\\\n- Premium: 3BB or **4BB** (35% random)\\\n- Speculative: **2BB** flat\\\n- Limpers: **+1BB** flat all types\\\n- Jitter: **0%** (was ±12%)\\\n- All raise-to amounts rounded to **whole BB** via `round_to_bb()`\\\n\\\n## Gen 4.7 — Matrix-Based Equity Preflop\\\n\\\nG47 replaces NG ranking-table preflop with **pure equity decisions** from a precomputed 169×169 PEM2 distribution matrix\"],[0,\".\\\n\\\n#\"]],\"start1\":829,\"start2\":829,\"length1\":260,\"length2\":1501},{\"diffs\":[[0,\"ized\"],[-1,\" (~12 min on 32 cores)\"],[0,\"\\\n- *\"]],\"start1\":2629,\"start2\":2629,\"length1\":30,\"length2\":8},{\"diffs\":[[0,\"tor`\"],[-1,\" (tightened calling range)\"],[0,\"\\\n- `\"]],\"start1\":2919,\"start2\":2919,\"length1\":34,\"length2\":8},{\"diffs\":[[0,\"ess`\"],[-1,\" (linear looseness OK for opening)\"],[0,\"\\\n\\\n**\"]],\"start1\":3007,\"start2\":3007,\"length1\":42,\"length2\":8},{\"diffs\":[[0,\"1))`\"],[-1,\" — bigger raises get tighter ranges\"],[0,\"\\\n- *\"]],\"start1\":3125,\"start2\":3125,\"length1\":43,\"length2\":8},{\"diffs\":[[0,\".42`\"],[-1,\" — never 3-bet with raw equity below 42%\"],[0,\"\\\n  -\"]],\"start1\":3275,\"start2\":3275,\"length1\":48,\"length2\":8},{\"diffs\":[[0,\"0.3`\"],[-1,\" — looseness^0.3 (not linear)\"],[0,\"\\\n- *\"]],\"start1\":3333,\"start2\":3333,\"length1\":37,\"length2\":8},{\"diffs\":[[0,\"**: \"],[-1,\"uses **\"],[0,\"wide\"]],\"start1\":3346,\"start2\":3346,\"length1\":15,\"length2\":8},{\"diffs\":[[0,\"er range\"],[-1,\"**\"],[0,\" (`vpip \"]],\"start1\":3353,\"start2\":3353,\"length1\":18,\"length2\":16},{\"diffs\":[[0,\"or`)\"],[-1,\" than reraise, since calling just sees a flop\\\n  - `call_equity = equity + ppot_call_bonus × ppot - npot_call_penalty × npot` vs pot odds × call_safety_margin\\\n\\\n### Tuned Parameters (2-round sweep, 2026-07-05/06)\\\n\\\n| Parameter | Value | Source |\\\n|---|---|---|\\\n| `equity_open_sb_steal` | 0.28 | R2a (+10.87 combined) |\\\n| `nutpot_reraise_bonus` | 0.5 | R2a (+9.38) |\\\n| `raise_range_factor` | 0.40 | R2a (+9.79) |\\\n| `call_safety_margin` | 1.10 | R2a (+9.43) |\\\n| `vpip_looseness_max` | 1.3 | R2a (+8.10) |\\\n| `equity_open_mid` | 0.46 | R2a (+7.30) |\\\n| `equity_reraise` | 0.75 | R2a (+7.23) |\\\n| `equity_open_late` | 0.36 | R2a (+6.70) |\\\n| `open_vpip_factor` | 0.90 | R2a (+6.26) |\\\n| `sizing_narrow_strength` | 0.3 | R2b (+0.43) |\\\n| `reraise_looseness_power` | 0.3 | R2b (+0.98) |\\\n| `min_reraise_equity` | 0.42 | R2b (confirmed optimal) |\\\n| `ppot_call_bonus` | 0.15 | Default |\\\n| `default_pfr` | 0.15 | Default |\\\n\\\n### Performance (2026-07-06 benchmark)\\\n\\\n| Field | G47 BB/hand | G45 opponents avg |\\\n|---|---|---|\\\n| G45-heavy (3×G45 + 2×Flock) | **+10.63** | -0.78 |\\\n| Flock-heavy (1×G45 + 4×Flock) | **+10.63** | +1.30 |\\\n| Mixed (2×Chump + 2×G45 + 1×Flock) | **+248** | chumps crushed |\\\n\\\n### Live Play Fixes (2026-07-05)\\\n\\\nFive regression tests in `hand_replay/tests/data/` — all pass:\\\n\\\n| Test | Bug (G45/G47 old) | Fix | G47 Decision |\\\n|---|---|---|---|\\\n| JJ facing 4-bet shove | Folded (G45) | G47 equity logic | **Call** |\\\n| 55 BTN 10 BB | Folded (short-stack blocked) | `consider_fold_as_not_applicable=true` | **Raise 143/214** |\\\n| AJo 10 BB facing 3-bet | Folded (G45) | G47 equity logic | **AllIn** |\\\n| 62s BTN facing raise | 3-bet (G47 loose table) | min_reraise_equity + PFR range | **Call** (not raise) |\\\n| K4o facing 170 BB 3-bet | AllIn (G47) | sizing_narrow_strength + PFR range | **Fold** |\\\n\\\n### Observer Lifecycle Fix (2026-07-06)\\\n\\\n**Bug**: `on_hand_end()` was called from `showdown_event()`, which only fires on showdown hands (minority) and multi-counts per revealed player. \"],[1,\", pot-odds-gated\\\n- **AJ shove fold**: call range now narrows by bet sizing (AJs eq dropped 0.606→0.391, correctly folds all-in)\\\n\\\n## Observer Lifecycle\\\n\\\nObserver tracks per-opponent stats (\"],[0,\"VPIP\"],[-1,\"/PFR adaptation was effectively disabled.\\\n\\\n**Fix**: Moved to proper `on_hand_end` trait override. Now fires on every hand, once.\\\n\\\n## Postflop Maneuver\\\n\\\n### Adaptive Postflop (`g4_adaptive_postflop`) — Unchanged from G4.5\\\n\\\n**Decision flow:**\\\n1. **External event feed** (live server): observer receives events via Strategy trait methods\\\n2. **Check observer warmth**: if `table.hands_observed < 5`, fall back to Gen 3 defaults\\\n3. **For each opponent seat**: build weighted `HandRange` from\"],[1,\", PFR, AF, bet frequencies) via EMA. `on_hand_end()` fires on every hand (fixed from showdown-only). Profile persistence via disk loading. Three-tier blend:\"],[0,\" obs\"]],\"start1\":3387,\"start2\":3387,\"length1\":2478,\"length2\":356},{\"diffs\":[[0,\"ats \"],[-1,\"+ this hand's actions + bet sizing\\\n4. **Build overridden Gen3Config** with table-adaptive thresholds\\\n5. **Delegate to Gen 3**: equity against predicted ranges → final action\"],[1,\"→ table-level → defaults.\"],[0,\"\\\n\\\n##\"],[-1,\"#\"],[0,\" R\"],[-1,\"ange Narrowing (from G4.5)\\\n\\\nThree layers: preflop action initialization → postflop action narrowing → multiplicative widening + bet sizing.\\\n\\\n| Parameter | Value | Description |\\\n|---|---|---|\\\n| `narrow_center_mult` | 1.5 | Multiplicative widening |\\\n| `narrow_sizing_strength` | 0.8 | Overbet sensitivity (>2/3 pot → tighter) |\\\n| `scurve_steepness_mult` | 0.3 | S-curve steepness multiplier |\\\n\\\n## Engine Crash Fix (rusty-marvin, 2026-07-05)\\\n\\\n**Bug**: `complete_hand()` dropped the HandRunner (with all seats) on `run_to_completion()` error. The next `start_hand()` saw 0 active players → `NotEnoughPlayers` → **silent simulation termination**.\\\n\\\n**Fix**: \\\n1. Error path now restores seats from runner via `into_seats()` \\\n2. Wagered chips refunded before `reset_for_new_hand()` (prevents chip destruction)\\\n3. `NotEnoughPlayers` logs a warning with hand count\\\n\\\nRoot cause of the crash: a bot returning `RaiseBelowMinimum(0, 60)` (chump_bot raising to 0). Occurs ~2 per 5000 hands.\"],[1,\"ecent Fixes (2026-07-16/17)\\\n- Call-path sizing narrowing, per-opponent PFR\\\n- Board-hit boost (KK on Ace boards)\\\n- Behind-penalty, drawy trap guard\\\n- RaiseBelowMinimum fix (BB rounding clamp), deep-stack overbet allin fix\\\n- Per-player looseness (`aggressor_vpip`)\\\n- Sanity checks passed all 11 gates\"],[0,\"\\\n\\\n##\"]],\"start1\":3751,\"start2\":3751,\"length1\":1163,\"length2\":337},{\"diffs\":[[0,\"sh_nl_g4\"],[-1,\"7\"],[1,\"8_live\"],[0,\".toml` |\"]],\"start1\":4146,\"start2\":4146,\"length1\":17,\"length2\":22},{\"diffs\":[[0,\"lop** → \"],[-1,\"g4_adaptive\"],[1,\"**g48_formula\"],[0,\"_postflo\"]],\"start1\":4194,\"start2\":4194,\"length1\":27,\"length2\":29},{\"diffs\":[[0,\"ula_postflop\"],[1,\"**\"],[0,\" | **Live pr\"]],\"start1\":4212,\"start2\":4212,\"length1\":24,\"length2\":26},{\"diffs\":[[0,\"on**\"],[-1,\" (G4.7)\"],[0,\" |\\\n|\"]],\"start1\":4244,\"start2\":4244,\"length1\":15,\"length2\":8},{\"diffs\":[[0,\"sh_nl_g4\"],[-1,\"5\"],[1,\"8\"],[0,\".toml` |\"]],\"start1\":4256,\"start2\":4256,\"length1\":17,\"length2\":17},{\"diffs\":[[0,\"` | \"],[-1,\"ke_hu → short_stack → g45_playability → g4_adaptive_postflop | Previous production (G4.5, \"],[1,\"same, sim settings | Sim/test |\\\n| `cash_nl_g47.toml` | ke_hu → **g47_equity_preflop** → g4_adaptive_postflop | G47 with old postflop (\"],[0,\"fall\"]],\"start1\":4270,\"start2\":4270,\"length1\":98,\"length2\":142},{\"diffs\":[[0,\"sh_nl_g4\"],[-1,\"_live\"],[1,\"5\"],[0,\".toml` |\"]],\"start1\":4425,\"start2\":4425,\"length1\":21,\"length2\":17},{\"diffs\":[[0,\"→ g4\"],[-1,\"_adaptive_preflop\"],[1,\"5_playability\"],[0,\" → g\"]],\"start1\":4463,\"start2\":4463,\"length1\":25,\"length2\":21},{\"diffs\":[[0,\"ion \"],[-1,\"|\\\n| `cash_nl_g4.toml` | same chain, default thresholds (narrow disabled) | Gen 4 baseline\"],[1,\"(G4.5)\"],[0,\" |\\\n\\\n\"]],\"start1\":4522,\"start2\":4522,\"length1\":97,\"length2\":14},{\"diffs\":[[0,\"sh_nl_g4\"],[-1,\"7\"],[1,\"8_live\"],[0,\"` (in `c\"]],\"start1\":4560,\"start2\":4560,\"length1\":17,\"length2\":22},{\"diffs\":[[0,\"--|---|\\\n\"],[1,\"| `holdem_bots/src/gen4/formula_postflop.rs` | **G48 strategy** — unified score formula, value_score with behind-penalty, draw guards |\\\n\"],[0,\"| `holde\"]],\"start1\":4643,\"start2\":4643,\"length1\":16,\"length2\":152},{\"diffs\":[[0,\"ns, \"],[-1,\"PFR ranges, sizing narrow\"],[1,\"per-opponent PFR, call-path narrowing, Harrington siz\"],[0,\"ing \"]],\"start1\":4870,\"start2\":4870,\"length1\":33,\"length2\":61},{\"diffs\":[[0,\"uity\"],[-1,\"/ppot/npot\"],[0,\" loo\"]],\"start1\":5017,\"start2\":5017,\"length1\":18,\"length2\":8},{\"diffs\":[[0,\"src/\"],[-1,\"bin/gen_preflop_equity.rs` | Standalone matrix generation binary |\\\n| `data/preflop_equity_matrix.bin` | PEM2 binary data (~8.7 MB, gitignored)\"],[1,\"gen4/range_builder.rs` | Range construction with board-hit boost\"],[0,\" |\\\n|\"]],\"start1\":5047,\"start2\":5047,\"length1\":150,\"length2\":72},{\"diffs\":[[0,\"en4 \"],[1,\"(G45 \"],[0,\"strategy\"],[-1,\" (unchanged from G4.5\"],[0,\") |\\\n\"]],\"start1\":5174,\"start2\":5174,\"length1\":37,\"length2\":21},{\"diffs\":[[0,\"ng, \"],[-1,\"event callback\"],[1,\"per-opponent stat\"],[0,\"s) |\"]],\"start1\":5254,\"start2\":5254,\"length1\":22,\"length2\":25},{\"diffs\":[[0,\"src/\"],[-1,\"gen4/range_builder.rs` | Range construction (multiplicative center + bet sizing) |\\\n| `hand_replay/tests/data/*.txt` | 5 live-play regression test hands |\\\n| `scripts/sweep_g47_round2.sh` | Multi-field parameter sweep script |\\\n| `scripts/sweep_g47_round2b.sh` | Structural parameter sweep script |\\\n\\\n## Open Issues\\\n\\\n1. **Observer data in live play**: PreflopObserver uses table-level VPIP/PFR (needs 30+ hands). Per-opponent tracking exists but isn't wired into G47's equity lookup yet.\\\n\\\n2. **Chump field simulation crashes**: chump_bot returns `RaiseBelowMinimum(0, ...)` causing hand errors. Fixed by crash recovery, but root cause (chump_bot action generation) should be addressed.\\\n\\\n3. **Gen5 teacher update**: Overnight collection used Gen4 teacher. Need to update `gen5_collect_full` to use G47 as teacher for future data.\\\n\\\n4. **Postflop unchanged**: G47 only changes preflop. Postflop still uses Gen 4 adaptive (Gen 3 equity). Gen 5 will eventually replace postflop.\\\n\\\n## Where This Goes Next\\\n\\\n- **Gen5 training**: 3.79M transitions collected overnight. Train with G47 preflop teacher + G4 postflop teacher.\\\n- **Live monitoring**: G47 debug logging (`epf_debug`) available for per-decision equity analysis. Currently disabled in production (set in sweep configs only).\\\n- **Postflop equity matrix**: Extend PEM2 approach to postflop — precompute equity distributions for common board textures.\"],[1,\"cash/rollout_postflop_base.rs` | Shared postflop base (raise min clamps, deep-stack allin fix) |\\\n| `hand_replay/tests/data/{harrington,regression,synthetic}/` | 40 hand replay test hands |\\\n\\\n## Where This Goes Next\\\n\\\n- **Gen5 training**: G48 teacher data collection running (24.1M short-handed transitions done, full-ring in progress)\\\n- **Postflop equity matrix**: PEM3 extension to postflop deferred by user — MC rollouts fine for live play\"],[0,\"\\\n\"]],\"start1\":5380,\"start2\":5380,\"length1\":1399,\"length2\":444}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-07-17T08:46:48.023Z
created_time: 2026-07-17T08:46:48.023Z
type_: 13