id: c15acaa9da4f4369811a01fcaa459910
parent_id: 7a36a41fdb8c4746a6cae910e97f4c00
item_type: 1
item_id: de72ff3ebcbd45689c988e50038e80b0
item_updated_time: 1783024362290
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\"26-0\"],[-1,\"6-30\"],[1,\"7-02\"],[0,\". Cu\"]],\"start1\":60,\"start2\":60,\"length1\":12,\"length2\":12},{\"diffs\":[[0,\", check)\"],[1,\"\\\n4. **Bet sizing awareness** (new 2026-07-02): Overbets (>2/3 pot) tighten the range toward polarized holdings (value or bluff)\"],[0,\"\\\n\\\n## Pre\"]],\"start1\":747,\"start2\":747,\"length1\":16,\"length2\":143},{\"diffs\":[[0,\" 3 | `g4\"],[-1,\"_adaptive\"],[1,\"5_playability\"],[0,\"_preflop\"]],\"start1\":1118,\"start2\":1118,\"length1\":25,\"length2\":29},{\"diffs\":[[0,\"+ **\"],[-1,\"VPIP-based looseness** (wired\"],[1,\"flop playability-enhanced promotion** (flexible 4-6 BB call barrier\"],[0,\") |\\\n\"]],\"start1\":1171,\"start2\":1171,\"length1\":37,\"length2\":75},{\"diffs\":[[0,\"lop (`g4\"],[-1,\"_adaptive\"],[1,\"5_playability\"],[0,\"_preflop\"]],\"start1\":1264,\"start2\":1264,\"length1\":25,\"length2\":29},{\"diffs\":[[0,\"ooseness\"],[1,\" and flop-playability-enhanced fold→call promotion\"],[0,\". The lo\"]],\"start1\":1338,\"start2\":1338,\"length1\":16,\"length2\":66},{\"diffs\":[[0,\"2.0)\"],[-1,\":\\\n- Table VPIP 0.15 (tight) → looseness 0.85 (we play tighter)\\\n- Table VPIP 0.30 (normal) → looseness 1.0 (standard)\\\n- Table VPIP 0.50 (loose) → looseness 1.15 (we play slightly looser)\\\n- Table VPIP 0.70 (very loose) → looseness 1.30\\\n\\\n## Postflop Maneuver\\\n\\\n### Adaptive Postflop (`g4_adaptive_postflop`)\\\n\\\n**Decision flow:**\\\n1. **Self-observe** (simulation mode): replay this hand's actions into the observer to keep it in sync\"],[1,\". Flexible call barrier: high-playability hands can call up to 6 BB, marginal hands limited to 4 BB.\\\n\\\n## Postflop Maneuver\\\n\\\n### Adaptive Postflop (`g4_adaptive_postflop`)\\\n\\\n**Decision flow:**\\\n1. **External event feed** (live server): observer receives events via `on_hand_start` / `on_player_action` Strategy trait methods — no self-observe needed\"],[0,\"\\\n2. \"]],\"start1\":1470,\"start2\":1470,\"length1\":434,\"length2\":354},{\"diffs\":[[0,\"uencies\\\n\"],[1,\"   - `observer.effective_preflop_freqs(seat)` → PFR, 3-bet frequency\\\n\"],[0,\"   - Bui\"]],\"start1\":2107,\"start2\":2107,\"length1\":16,\"length2\":85},{\"diffs\":[[0,\" actions\"],[1,\" + bet sizing\"],[0,\"\\\n   - `r\"]],\"start1\":2250,\"start2\":2250,\"length1\":16,\"length2\":29},{\"diffs\":[[0,\"`\\\n4.\"],[-1,\" **Store prediction** for showdown accuracy tracking\\\n5.\"],[0,\" **C\"]],\"start1\":2341,\"start2\":2341,\"length1\":63,\"length2\":8},{\"diffs\":[[0,\"IP, AF)\\\n\"],[-1,\"6\"],[1,\"5\"],[0,\". **Buil\"]],\"start1\":2405,\"start2\":2405,\"length1\":17,\"length2\":17},{\"diffs\":[[0,\"esholds\\\n\"],[-1,\"7\"],[1,\"6\"],[0,\". **Dele\"]],\"start1\":2471,\"start2\":2471,\"length1\":17,\"length2\":17},{\"diffs\":[[0,\" ranges\\\n\"],[-1,\"8\"],[1,\"7\"],[0,\". **Gen \"]],\"start1\":2579,\"start2\":2579,\"length1\":17,\"length2\":17},{\"diffs\":[[0,\"### \"],[-1,\"The Observer\\\n\\\nTracks per-opponent statistics using **exponential moving averages** (EMA):\\\n\\\n```rust\\\nstruct PlayerStats {\\\n    vpip: EmaStat,       // Voluntary preflop entry rate\\\n    pfr: EmaStat,        // Preflop raise rate\\\n    af: EmaStat,         // Postflop aggression factor (bet+raise / call)\\\n    fold_to_bet: EmaStat,\\\n    fold_to_cbet: EmaStat,\\\n    cbet_freq: EmaStat,  // Continuation bet frequency\\\n    threebet: EmaStat,   // 3-bet frequency\\\n    wtsd: EmaStat,       // Went-to-showdown rate\\\n    bet_freq: EmaStat,   // First-in postflop bet rate\\\n    raise_freq: EmaStat, // Facing-bet raise rate\\\n    call_freq: EmaStat,  // Facing-bet call rate\\\n    hands_observed: usize,\\\n}\\\n```\\\n\\\n### Three-Tier Blend\\\n\\\n- **<5 hands observed**: pure table aggregate\\\n- **5-50 hands**: linear blend (gradually trust player-specific data)\\\n- **≥50 hands**: pure player stats\\\n\\\n### Range Prediction Accuracy\\\n\\\nAt showdown, the observer checks whether the opponent's actual hole cards were within the predicted range. Current accuracy: **~88% hit rate** across all streets. Accuracy is uniform across flop/turn/river.\\\n\\\n### Profile Persistence\\\n\\\nProfiles saved to `profiles/{format}_{sb}_{bb}/` (table + per-player JSON). Loaded on startup via `update_table_info()` and `on_hand_start()`. Survives server restarts.\\\n\\\n## Configs\\\n\\\n| Config | Chain | Purpose |\\\n|---|---|---\"],[1,\"Range Narrowing (updated 2026-07-02)\\\n\\\nThree layers of range narrowing:\\\n\\\n**Layer 1 — Preflop action initialization**: The S-curve center is set directly from the relevant preflop stat:\\\n- PreflopRaised → center = PFR\\\n- PreflopThreeBet → center = threebet_freq × 0.7\\\n- PreflopCalledRaise → center = VPIP × 0.60\\\n- Limp/None → center = strong_hands_fraction (VPIP-based)\\\n\\\n**Layer 2 — Postflop action narrowing**: Per-street S-curve multiplier based on action type:\\\n- Bet (donk from aggressor on flop) → center capped at 0.20\\\n- Bet (normal) → center = bet_freq\\\n- RaisedBet → center = raise_freq × 0.7\\\n- CalledBet → center = call_freq\\\n- Checked → center = 0.70 (minimal narrowing)\\\n\\\n**Layer 3 — Multiplicative widening + bet sizing** (new 2026-07-02):\\\n- `center *= narrow_center_mult` (default 1.5, scales with center)\\\n- If `bet_size_ratio > 0.67` (overbet): `center /= 1 + narrow_sizing_strength * (ratio - 0.67)`\\\n\\\nThis replaces the old static `narrow_center_offset` (additive, flat). The multiplicative factor ensures tight ranges stay tight while wide ranges get proportional slack. Bet sizing awareness prevents the bot from treating a 1.76x pot overbet the same as a standard raise.\\\n\\\n### KK Overbet Bug Fix (2026-07-02)\\\n\\\n**Root cause**: The old additive `narrow_center_offset=0.20` widened tight raise ranges excessively (center 0.07 → 0.27), and bet sizing was completely ignored. A 1.76x pot overbet got the same range treatment as a min-raise.\\\n\\\n**Fix**: \\\n1. Replaced `narrow_center_offset` (additive) with `narrow_center_mult` (multiplicative, default 1.5)\\\n2. Added `narrow_sizing_strength` (default 0.8) for overbet-aware tightening\\\n3. Fixed Bet vs RaisedBet classification (now tracks prior bets by other players)\\\n4. Fixed replay engine `actions_this_hand` (was always empty)\\\n5. Result: KK facing 1.76x pot overbet on [2-A-2] now correctly folds (hs=0.058 vs 0.596 before fix)\\\n\\\n### The Observer\\\n\\\nTracks per-opponent statistics using **exponential moving averages** (EMA):\\\n\\\n```rust\\\nstruct PlayerStats {\\\n    vpip: EmaStat,       // Voluntary preflop entry rate\\\n    pfr: EmaStat,        // Preflop raise rate\\\n    af: EmaStat,         // Postflop aggression factor (bet+raise / call)\\\n    fold_to_bet: EmaStat,\\\n    fold_to_cbet: EmaStat,\\\n    cbet_freq: EmaStat,  // Continuation bet frequency\\\n    threebet: EmaStat,   // 3-bet frequency\\\n    wtsd: EmaStat,       // Went-to-showdown rate\\\n    bet_freq: EmaStat,   // First-in postflop bet rate\\\n    raise_freq: EmaStat, // Facing-bet raise rate\\\n    call_freq: EmaStat,  // Facing-bet call rate\\\n    hands_observed: usize,\\\n}\\\n```\\\n\\\n### Three-Tier Blend\\\n\\\n- **<5 hands observed**: pure table aggregate\\\n- **5-50 hands**: linear blend (gradually trust player-specific data)\\\n- **≥50 hands**: pure player stats\\\n\\\n### Profile Persistence\\\n\\\nProfiles saved to `profiles/{format}_{sb}_{bb}/` (table + per-player JSON). Loaded on startup via `update_table_info()` and `on_hand_start()`. Survives server restarts.\\\n\\\n## Hand Replay System (new 2026-07-02)\\\n\\\nThe `hand_replay` tool now supports **opponent model annotations** for pre-seeding the observer with synthetic stats:\\\n\\\n```\\\n# Opponent model: PlayerName vpip=0.48 pfr=0.15 af=1.0 raise_freq=0.13 hands=55\\\n# Table model: vpip=0.59 pfr=0.29 af=0.82 fold_to_bet=0.64 hands=55\\\n```\\\n\\\nThe runner writes forged profile JSON to the profiles directory (with backup/restore guard), the bot loads them on init, and adaptive range narrowing activates even for a single replayed hand. This enables:\\\n- Testing bot decisions against described opponent types (Harrington hands)\\\n- Regression testing with warm observer data\\\n- Verifying fixes against specific historical hands\\\n\\\n## Configs\\\n\\\n| Config | Chain | Purpose |\\\n|---|---|---|\\\n| `cash_nl_g45.toml` | ke_hu → short_stack → g45_playability → g4_adaptive_postflop | **Live production** (G4.5) \"],[0,\"|\\\n| \"]],\"start1\":2669,\"start2\":2669,\"length1\":1357,\"length2\":3814},{\"diffs\":[[0,\"tive_postflop | \"],[-1,\"**Live\"],[1,\"Previous\"],[0,\" production** |\\\n\"]],\"start1\":6559,\"start2\":6559,\"length1\":38,\"length2\":40},{\"diffs\":[[0,\"oduction\"],[-1,\"**\"],[0,\" |\\\n| `ca\"]],\"start1\":6586,\"start2\":6586,\"length1\":18,\"length2\":16},{\"diffs\":[[0,\"resholds\"],[1,\" (narrow disabled)\"],[0,\" | Gen 4\"]],\"start1\":6641,\"start2\":6641,\"length1\":16,\"length2\":34},{\"diffs\":[[0,\"line\"],[-1,\" (non-tuned)\"],[0,\" |\\\n|\"]],\"start1\":6680,\"start2\":6680,\"length1\":20,\"length2\":8},{\"diffs\":[[0,\" looser \"],[-1,\"starting \"],[0,\"threshol\"]],\"start1\":6726,\"start2\":6726,\"length1\":25,\"length2\":16},{\"diffs\":[[0,\"ter \"],[-1,\"starting \"],[0,\"thre\"]],\"start1\":6816,\"start2\":6816,\"length1\":17,\"length2\":8},{\"diffs\":[[0,\"ent \"],[-1,\"Live Tuning (post-discount sweep, \"],[1,\"Range Narrowing Parameters (\"],[0,\"2026-0\"],[-1,\"6-29\"],[1,\"7-02\"],[0,\")\\\n\\\n|\"]],\"start1\":6859,\"start2\":6859,\"length1\":52,\"length2\":46},{\"diffs\":[[0,\"e | \"],[-1,\"Ra\"],[1,\"Descrip\"],[0,\"tion\"],[-1,\"ale\"],[0,\" |\\\n|\"]],\"start1\":6922,\"start2\":6922,\"length1\":17,\"length2\":19},{\"diffs\":[[0,\"\\\n| `\"],[-1,\"bet_turn_base` | 0.40 | +251 combined Δ (was 0.58) |\\\n| `bet_flop_base` | 0.15 | +79 combined Δ (was 0.30) |\\\n| `scurve_steepness_mult` | 0.3 | +45 combined (curve sweep R1) |\\\n| `bluff_hs_max` | 0.05 | +53 combined (curve sweep R1) |\\\n| `narrow_center_offset` | 0.2 | +46 combined (curve sweep R2) |\\\n| `strong_hands_fraction\"],[1,\"narrow_center_mult` | 1.5-1.6 | Multiplicative widening (replaces old additive offset) |\\\n| `narrow_sizing_strength\"],[0,\"` | 0.\"],[-1,\"30 | +18 combined (curve sweep R3) |\\\n| `call_w_draw` | 0.75 | +16 combined (curve sweep R3) |\\\n\\\n### 60k-Hand Validation (2026-06-29)\\\n\\\n- G4Live: **+132.9/hand** vs chump field (was +100.5 pre-fix)\\\n- G4Live: **+0.95/hand** vs gen field (was +0.52 pre-fix)\\\n\\\n### Key Sweep Findings (consolidated)\\\n\\\n- **Threshold scaling is the strongest lever** — weight map parameters have only ±2/hand impact when thresholds are fixed. The opponent model is already well-calibrated (~88%).\\\n- **Linear ranges > S-curve** — S-curve consistently underperforms linear at the same threshold scaling level.\\\n- **N\"],[1,\"8 | Overbet sensitivity (>2/3 pot → tighter) |\\\n| `scurve_steepness_mult` | 0.3 | S-curve steepness multiplier |\\\n| `n\"],[0,\"arrow\"],[-1,\"ing \"],[1,\"_\"],[0,\"strength\"],[-1,\" has zero effect** — 0.8× = 1.0× = 1.2× = 1.5× all give identical results.\\\n- **Center offset helps slightly** — +0.1 to +0.3 shifts ranges wider (less aggressive narrowing).\\\n- **Gen 4 dominates Gen 3 by ~70%** vs chumps (148 vs 86 profit/hand).\\\n- **Loose/tight config spread is small** for Gen 4 (2 pts) vs Gen 3 (17 pts) — the adaptive layer absorbs table-type differences.\"],[1,\"_mult` | 1.0 | Narrowing steepness multiplier |\\\n| `narrow_floor` | 0.02 | Minimum weight for narrowed hands |\"],[0,\"\\\n\\\n##\"]],\"start1\":6953,\"start2\":6953,\"length1\":1312,\"length2\":367},{\"diffs\":[[0,\"strategy\"],[1,\" (external event feed, bet_size_ratio)\"],[0,\" |\\\n| `ho\"]],\"start1\":7421,\"start2\":7421,\"length1\":16,\"length2\":54},{\"diffs\":[[0,\"lopGen4 \"],[-1,\"strategy \"],[0,\"(loosene\"]],\"start1\":7529,\"start2\":7529,\"length1\":25,\"length2\":16},{\"diffs\":[[0,\"ss wired) |\\\n\"],[1,\"| `holdem_bots/src/gen4/playability_preflop.rs` | PlayabilityPreflop (flop-playability promotion) |\\\n\"],[0,\"| `holdem_bo\"]],\"start1\":7545,\"start2\":7545,\"length1\":24,\"length2\":124},{\"diffs\":[[0,\"on (\"],[-1,\"S-curve +\"],[1,\"multiplicative center + bet sizing\"],[0,\" nar\"]],\"start1\":7898,\"start2\":7898,\"length1\":17,\"length2\":42},{\"diffs\":[[0,\"| `h\"],[-1,\"oldem_bots/src/gen4/accuracy.rs` | Showdown-based range accuracy tracking |\\\n| `holdem_bots/src/gen4/model_registry.rs` | Model snapshot registry |\\\n\\\n## Open Issues\\\n\\\n1. **Passive postflop play**: Bot still under-bets first-in postflop situations. The post-discount sweep (`bet_flop_base=0.15`, `bet_turn_base=0.40`) improved aggression, but the bot could still value-bet more frequently. This is the main remaining weakness — likely needs\"],[1,\"and_replay/src/parser.rs` | Hand parser with opponent model annotations |\\\n| `hand_replay/src/runner.rs` | Runner with forged profile injection |\\\n| `hand_replay/src/replay.rs` | Replay engine with actions_this_hand tracking |\\\n\\\n## Open Issues\\\n\\\n1. **Parameter sweep needed**: `narrow_center_mult` (1.5) and `narrow_sizing_strength` (0.8) are heuristic defaults — need overnight sweep validation.\\\n\\\n2. **Passive postflop play**: Bot still under-bets first-in postflop situations.\"],[0,\" Gen\"]],\"start1\":8022,\"start2\":8022,\"length1\":444,\"length2\":482},{\"diffs\":[[0,\"es) \"],[-1,\"to fu\"],[1,\"wi\"],[0,\"ll\"],[-1,\"y\"],[0,\" address\"],[1,\" this\"],[0,\".\\\n\\\n\"],[-1,\"2\"],[1,\"3\"],[0,\". **\"]],\"start1\":8533,\"start2\":8533,\"length1\":28,\"length2\":29},{\"diffs\":[[0,\"ion \"],[-1,\"misses\"],[1,\"accuracy\"],[0,\"**: \"]],\"start1\":8575,\"start2\":8575,\"length1\":14,\"length2\":16},{\"diffs\":[[0,\"rate\"],[-1,\" means 12% of shown hands fall outside the predicted range. Misses are concentrated against extreme opponents (very tight or very loose). Further improvement likely needs a learned range model (Gen 5 Phase 2).\\\n\\\n3. **No automated sweep pipeline**: The GUI sweep tool can sweep 84 parameters but requires manual winner selection. An automated sweep → apply loop would accelerate tuning\"],[1,\". Extreme opponents still cause misses. Gen 5 learned range model may improve this\"],[0,\".\\\n\\\n#\"]],\"start1\":8599,\"start2\":8599,\"length1\":391,\"length2\":90},{\"diffs\":[[0,\"om Gen 4\"],[1,\".5\"],[0,\" teacher\"]],\"start1\":8825,\"start2\":8825,\"length1\":16,\"length2\":18},{\"diffs\":[[0,\"ecisions\"],[1,\", then RL fine-tuning\"],[0,\". The ob\"]],\"start1\":8845,\"start2\":8845,\"length1\":16,\"length2\":37},{\"diffs\":[[0,\"ures\"],[-1,\", but range prediction and action selection become learned rather than hand-tuned\"],[0,\".\"]],\"start1\":8920,\"start2\":8920,\"length1\":86,\"length2\":5}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-07-02T20:37:55.562Z
created_time: 2026-07-02T20:37:55.562Z
type_: 13