Session History & Archive

# Session History & Archive (from AGENTS.md, moved 2026-08-16)

> Historical session logs, post-mortems, model history, and tuning notes. Current state lives in Pipeline State (`ec1518e71453490f8fe5ab75cff7180c`); forward-looking work in Roadmap (`47031623e2c6451fb36730ffe93380ea`).

## Key Fixes (2026-07-18 to 2026-07-31)
- **stack_depth_factor sign error** (critical): inverted sigmoid caused deep-stack shove willingness at ALL depths → AJs 93 BB shove. Fixed: `(stack_bb - mid) / width`.
- **npot saturation**: `npot/(1+npot)` prevents equity matrix's unbounded npot from destroying scores for dominated hands (AQo, KQs)
- **Config alignment**: sim config had sizing_base=0.65 (vs live=0.33), ppot_weight=0.90 (vs live=0.75)
- **Postflop investment formula**: `expected_postflop = min(effective_pot × 0.5, stack × 0.5)` in limped-pot complete threshold
- **Second barrel penalty**: +0.15 bet threshold on turn/river when preflop aggressor
- **Multiway draw tightening**: hs >= 0.25 for multiway bets (was 0.10)
- **Pot-odds override**: call tiny bets (< 15% pot) when draw equity exceeds pot odds
- **Short-stack shove guard**: >33% commit + ≤25 BB → shove (uses additional commit, not raise-to)
- **Reraise recalibration**: equity_reraise 0.62→0.53, equity_reraise_huge 0.70→0.60
- **Range feature expansion**: 57→81→85 dims (8→32 action history dims with rich per-street encoding, then base 49→53)
- **Min raise bug**: fully fixed (raise-by vs raise-to semantics)
- **Combo-count bug** (critical): `probs_to_hand_range()` was assigning full type probability to each combo, inflating offsuit 3× vs suited. Fixed with 2-pass: count remaining combos per type, then assign `type_prob / count` per combo. This turned G49 blend from -16.4 → +15.1 BB/100.
- **Alpha configurable from TOML**: `range_alpha_min`, `range_alpha_max` in Gen48Config. Currently 1.0/1.0 (pure NN).
- **Personality VPIP calibration** (critical, 2026-08-01): G48 personality configs (fish/station/lag/maniac) had equity thresholds so low that fish played 90%+ of hands instead of 35%. Root cause: equity preflop uses table VPIP feedback loop (`effective_vpip()` returns observed table VPIP after 5 hands), causing all bots to converge to same VPIP. Fix: (1) raised thresholds to realistic levels, (2) set `epf_min_observed_hands = 999999` for ALL personality configs so they always use `default_vpip` instead of table VPIP — breaks feedback loop, each personality maintains distinct VPIP. Verified: median VPIP 0.25, range 0.08-0.40 (was 0.92 median, 75% >0.50).

## Key Fixes (2026-08-05 session)
- **Multiway formula overhaul**: replaced linear `per_opp * n` with saturating `k*n/(n+m)` curves. Six configurable params: `multiway_bet_k/m`, `multiway_npot_k/m`, `multiway_ppot_k/m`. Default `bet_k=0.0` (no penalty), `ppot_k=0.15` (mild penalty). Sweep showed bet_k=0.0 best vs Fish.
- **Min-raise war fix** (critical): `compute_threebet_size` used `to_call * 3.0` as sizing base — in raise wars, to_call is 1 BB, producing 3 BB re-raises. Fixed: pot-based minimum (45% pot). Combined with `first_in` bug fix (was true during raise wars because `to_call <= bb` when stack nearly committed).
- **Preflop opponent-awareness**: `situation_vpip()` uses limper-weighted VPIP for limped pots, `callers_behind_bonus()` estimates implied odds for players yet to act. Adaptive_preflop now situation-aware (raiser VPIP vs table VPIP vs limper VPIP).
- **Performance optimizations**: batched NN inference (`predict_ranges_batched`), OnceLock memoization for `canonical_type_lookup`, `[bool;52]` bitset in `probs_to_hand_range`, in-place softmax.
- **Sanity check parallelized**: 5 seeds run in parallel per opponent (5× faster).

## Key Fixes (2026-08-09 session)
- **Live config updated**: `cash_nl_g50_live.toml` now uses `range_v17.safetensors` (was range_v14_b1).
- **Parallel eval**: `MAX_PARALLEL=15`. 10 seeds × 5K hands in ~11 min (was 83 min sequential). Per-seed TOML generated dynamically.

## Sanity Check snapshot (range_v17, 2026-08-09)
- All gates pass — 53 Harrington, self-play audit, performance vs field
- Gen2: +0.7, Gen3: +1.0, G48_nn: +1.8, TAG_nn: +1.8, Nit_nn: +0.1 BB/100
- Mixed: +0.3, Fish: +4.5, Whale: +4.3
- G48_nn extended eval: +18.7 BB/100 avg (5 seeds × 5K hands, +1.9 to +6.4 range)

## Key Fixes (2026-08-15 session) — G51: action-likelihood range corrector
- **Implemented idea #7**: `holdem_bots/src/gen4/range_corrector.rs` — Bayesian range refinement after RangeNet prior: `P(hand|actions,board) ∝ P(actions|hand) × P(hand)`. XpotTable per street (exact hs percentile enumeration + 128 shared-runout ppot/npot/nutpot/rpot, cached per spot, 4ms warm). Hand-fit likelihood curves per StreetAction with bet-size, aggression (af), bet-frequency, barrel-compounding, and VPIP-floor-lift conditioning. Range-width invariant. Knobs: `corr_*` in TOML (off by default).
- **KK overplay defect FIXED**: NN path turn hs 0.730→0.535 (AllIn→Raise), river 0.611→0.290 (Raise→Check). Replay: `replay_kk_overplay_variants` (#[ignore], real profiles).
- **Configs**: `cash_nl_g51.toml` (sim) / `cash_nl_g51_live.toml` (live, DEFAULT in live_bots.toml).
- **Sanity g51: 10/10 PASSED** (5 runs). h2h g51 vs g50: −0.29 BB/100 (dead heat, 200K hands). Small deficit (~1-5) vs specialist 9-max fields — expected on-distribution cost; corrector targets off-distribution human lines.
- **eval_9max.sh parallelized** (MAX_PARALLEL=8 × RAYON 4). A/B harness: `/tmp/kilo/run_ab_parallel.sh <cand> <opp> <tag> <hands> <seeds...>`.
- **Harrington board parser bug FIXED (critical, pre-existing)**: turn/river parsing took the FIRST bracket on `*** TURN *** [board] [card]`, duplicating the flop's last card as the turn card — ALL multi-street turn/river validations ran on corrupted boards (phantom paired board, inflated hero equity). Now takes the LAST bracket.
- **Sanity Gate 1 gap CLOSED**: now runs `--features holdem_bots/gen5_nn` — the production NN path was never sanity-tested before. Two unmasked strategy gaps #[ignore]-tracked: `replay_harrington_4_5_99` (later FIXED by eq_cc gate), `replay_harrington_7_6` (KK river value-bet vs capped line, still open). g50 fails a2o_river/99_twopair on the fixed suite; g51 passes both.
- **Code review before commit**: fixed chips/BB unit bug in street_bet_ratios (ratios were clamp-saturated), NN-blend+corrector hoisted out of narrow_enabled gate, removed inert corr_max_boost, +2 tests.
- **Cleanup**: Gen6/PPO code+configs removed, models archived to `models/abandoned_gen6/`, 17G `data/gen5_transitions` deleted, sweep artifacts removed.
- Commits: 0609ebb, 35b4fc6, 042876b, 0b18e88.

## Key Fixes (2026-08-15 evening) — eq_cc value-bet gate + NN fallback
- **NN-returns-None fallback** (58e3456): with alpha=1.0 the heuristic build is skipped; NN inference failure (CUDA OOM, tensor error, NaN logits) left an EMPTY range → coin-flip hs=0.5. Now falls back to heuristic range; success path unchanged (pure NN).
- **eq_vs_continue value-bet gate** (56b99f0): a bet's value term is `(2·eq_cc−1)·bet` vs the range that CONTINUES. New `gen4/decision_math.rs`: `continuing_range()` filters by P(continue|hand,size,freqs) via corrector likelihood curves; `equity_vs_continue()` = hero equity vs filtered range (HU enumeration). Knob `eq_cc_min` (g51: 0.52, default 0.0 = opt-in), bluff path exempt. **4_5_99 PASSES**: turn bet vetoed (hs 0.40, eq_cc 0.25). Designated FutureActionNet swap point (`ContinueFilter::{Call, CallOrRaise, None}`).
- **7_6 stays ignored** (agreed): KK river thin-value vs capped line = range-accuracy defect needing sequence-aware modeling; not a leak.
- eq_cc_min swept 0.48/0.56 vs TAG+Fish: flat (seed noise) → 0.52 kept.
- rust-reviewer pass: 1 medium fixed (default 0.52→0.0 opt-in), 2 low fixed.
- **live_server now persistent lifetime** (survives session/config reloads).

## Key Fixes (2026-08-15/16 overnight) — EquityNet (idea #1) phases 1-5
- **Data collection**: `gen5/equity_recorder.rs` — taps decision context (post-corrector ranges) in `build_ranges_and_equity`; labels via exact enumeration vs actual holdings at `cards_revealed_event`. Env `EQUITY_RECORDER_PATH` activates; zero overhead otherwise. Records compacted to 9.5KB.
- **Model**: `gen5/equity_net.rs` — permutation-invariant (shared 169→128→64 encoder, mean‖max pool, trunk →5 sigmoid heads); any n_opp 1-9. `bin/train_gen5_equity.rs` (convert + train, GPU).
- **Shadow mode**: `equity_net_path` + `equity_nn_enabled` TOML knobs (false=shadow log via EQUITY_SHADOW_LOG, true=replace MC). `cash_nl_g52.toml` = g51 + EquityNet. Tooling: `scripts/equity_shadow_run.sh` + `equity_shadow_analyze.py` (gates: hs MAE ≤0.03 HU / ≤0.045 MW, slope 0.9-1.1).
- **Collection corpus**: `/home/jan/gen5_data/equity_v6` — 8 tables × g51-pipeline all seats. ~10M samples.
- **IMPORTANT**: equity_v5_2m4 corpus is RangeNet classification data (features+hand_type) — NOT equity labels.
- rustfmt applied to gen4/gen5 trees; ~1000-line pre-existing fmt debt in untouched files.
- Commits: 1190941, 9b95def, 55a01ad, 785986f, adc3d15.

## Dropped Approaches (lessons)
- **Direct-action Gen5** (imitation/Q-reg on 290-dim features): 71.5% accuracy, catastrophic mistakes (All-In with weak draws). Action selection without opponent range info is fundamentally blind.
- **Equity NN** (`model_infer_equity`): Pure value betting works in 6-max but fails in 9-max (+121 vs -148 BB/100). Redundant with G48's MC computation. (Superseded 2026-08-16 by EquityNet idea #1 — range-conditioned, different design.)
- **Combined inference** (`model_infer_combined`): Single-street EV formula too aggressive. -157 to -2140 BB/100.
- **FoldEquityNet**: Overfit, insufficient data.
- **Heuristic range blending** (alpha 0.3-0.7): pure NN (+138 BB/100 seed 42) beats blend (+80.5) beats heuristic (-0.5).
- **PreflopNet (Gen6)**: 99.38% eval accuracy but **-644 BB/100 deployed**. 15 features can't capture G47's preflop logic. PPO on broken base hopeless (G62 ≈ G60 ≈ -644). Would need 50+ features, continuous sizing, much more data.

## Gen 6 Post-Mortem (PreflopNet / PPO)
Eval (10 seeds × 5K hands, 9-max vs 8 NN opponents):

| Bot | Avg chips/hand | BB/100 |
|-----|---------------|--------|
| G48_nn (production) | +3.73 | +18.7 |
| G60 (PreflopNet imitation) | -128.75 | -643.8 |
| G63 (PPO v3 on-policy) | -129.45 | -647.3 |

- PPO iterations made zero meaningful difference — policy weight changes < 0.001/iter
- Value head correlation 0.10 with outcomes (gate > 0.03) but too weak
- Conclusion: abandoned. G47 formula remains preflop strategy.

## Sim Speed Notes
- **Bottleneck is multiway postflop computation**, not NN inference
- 9 Tag_nn: 1300 h/s. 9 Fish_nn: 4.8 h/s (25×). Loose = 5-7 way flops, G48 formula per decision per street
- RangeNet forward ~0.1ms. MC budget changes (1K vs 10K): zero speed effect
- `nice -n 19 ionice -c 3` causes 5-6× slowdown — background work only

## Range Model History
- range_v10–v13: 57-dim, ~3% top-1, ~19% top-10 (ceiling with coarse features)
- range_v14_b1: 81-dim, 1M samples, 2.86% top-1, 19.0% top-10
- range_v14_b2–b4: 81-dim bug-fix iterations (combo-count, alpha config)
- range_v15: 81-dim interim
- range_v16: 81-dim, 19.2M samples, 3.61% top-1, 22.3% top-10
- range_v17: 85-dim, 19.2M samples, 4.35% top-1, 24.2% top-10 ← production

## Gen 5 Tuning notes
- Training eval is raw softmax (no card exclusion); effective inference accuracy higher due to hero+board masking
- Diminishing returns: 19M→84M samples <1% projected. Better levers: feature quality, live opponent data
- Improvement levers: (1) feature quality — showdown history, positional stat breakdown, pot-odds context, board interaction; (2) live data — real opponents have exploitable patterns; (3) per-street specialization

## Data & Models
- `equity_v5_2m4/` (at /home/jan/gen5_data): RangeNet collection, 19.2M samples — classification data, NOT equity labels
- `equity_v6/`: EquityNet collection (2026-08-16), g51 pipeline, exact labels
- `models/range_v17.safetensors`: production range model
- `models/abandoned_gen6/`: preflop_v1, ppo_v1/v1b/v1c/v2/v3 (archived)

id: 283e98fe73984f5e90635ddaf664a6e8
parent_id: 2c8da247905946c3aa19eb4936e16323
created_time: 2026-08-16T04:54:44.668Z
updated_time: 2026-08-16T04:54:44.668Z
is_conflict: 0
latitude: 0.00000000
longitude: 0.00000000
altitude: 0.0000
author: 
source_url: 
is_todo: 0
todo_due: 0
todo_completed: 0
source: joplin-desktop
source_application: net.cozic.joplin-desktop
application_data: 
order: 1786856084668
user_created_time: 2026-08-16T04:54:44.668Z
user_updated_time: 2026-08-16T04:54:44.668Z
encryption_cipher_text: 
encryption_applied: 0
markup_language: 1
is_shared: 0
share_id: 
conflict_original_id: 
master_key_id: 
user_data: 
deleted_time: 0
is_locked: 0
extracted_resource_ids: 
type_: 1