Engine Audit — rusty-marvin holdem_core (2026-08-23)

# Sim-Engine-Audit rusty-marvin/holdem_core (2026-08-23)

> Subagent-Audit, H1-H3 am Code verifiziert. Kontext: Engine treibt alle Benchmarks.

## HIGH (Mess-Bias / Regelverletzungen)

**H1. Legaler Kurz-AllIn-Raise wird zu Call konvertiert** — `hand_runner.rs:575-593`: `validate_action` lehnt jeden Raise-Inkrement < min_raise ab, OHNE Ausnahme für `total == wagered + stack`. Ein Bot, der AllIn via `Raise{total: stack}` sized (statt `Action::AllIn`), bekommt einen *partiellen Call* — bleibt aktiv mit Chips dahinter, Side-Pot-Geometrie falsch. Messbias für jeden Adapter-Bot mit Raise-to-Stack-Sizing. VERIFIZIERT.

**H2. Sub-Minimum-AllIn reopen't Betting + korrumpiert MinRaise-Tracking** — `hand_runner.rs:706-719`, `betting.rs:226-234`: `apply_bet` setzt `last_raise_size = raise_increment` bedingungslos. Kurz-Shove (+15 über 100 bei Min-Re-Raise 40): (a) reset't `has_acted_this_round` für alle → bereits Callende bekommen volle Raise-Rechte zurück (Regeln: unvollständiger Raise reopen't nicht), (b) nächster Min-Re-Raise wird aus dem KURZEN Inkrement berechnet. Extra Action + unterpreiste Re-Raises nach Kurz-Shoves.

**H3. `cards_revealed_event` leak't ALLE Karten (inkl. gefoldeter) — Default-Finalize-Pfad** (`hand_runner.rs:1163-1175`): Feuert für jede Hand an jeden Bot. Konvention "training only" wird nicht enforced. ENTLASTUNG (verifiziert): Unsere Produktions-Bots konsumieren es NUR für Recording/Training nach Handende (range_rec/equity resolve; modular-Default no-op) — kein aktiver Bias in unseren Benchmarks, aber opt-in-Pflicht für Dritt-Bots. Flock/Chump/Gen2 nutzen es nicht.

## MED
- **M1**: `GameInfo.num_raises` zählt AllIn-Raises NICHT (`Action::AllIn` unsichtbar) → 100BB-Shove liest sich als "unraised pot". FlockBot branch't genau darauf falsch (shove → min-Raise statt Call/Fold).
- **M2**: Postflop Minimum-Bet nicht enforced (`min_raise = br.last_raise_size` = 0 fresh round; BetLimit-Config ignoriert) — 1-Chip-Bets legal, RandomBot kann `Raise{total:0}`.
- **M3**: Button/Blinds brechen bei SittingOut-Spielern (button landet auf Bust-Spieler, dealer `.unwrap_or(0)`) — nicht unter reset_bankroll=true, aber SNG/Tournament-Korruption.
- **M4**: RandomBot nutzt `rand::rng()` statt Seed → nicht reproduzierbar (nur relevant wenn RandomBot im Pool).
- **M5**: **FlockBot ist postflop KEIN TAG**: middle pair/any draw call't jede Bet-Size (Station-Verhalten), board-only Flush/Straight → Raise in garantierte Chops, "pot_sized_raise" ist Overbet-Formel. Preflop genuinely tight. Benchmark-Schlussfolgerungen gegen "TAG-Referenz" Flock überzeichnen Value/Bluff-Profitabilität.
- **M6**: Odd-Chip-Split nondeterministisch (HashMap-Ordnung) — bricht bit-exakte Reproduzierbarkeit (Chips konserviert, Regel "odd chip links vom Button" fehlt).

## LOW (bestätigt korrekt)
- Zero-Sum exakt verifiziert (pot.rs tests; stats: Σ=0, kein Drift über 500K; keine Rake in Benchmarks)
- Deck-Seed `seed + hand_number` pro Hand; Seat-Shuffle eigener Stream; keine globale RNG; parallel Sims ok
- `randomize_seats` mischt JEDE Hand (undokumentiert, aber fair)
- Side-Pot-Layering korrekt, BB-Option korrekt, Preflop current_bet bei Short-BB korrekt

## Architektur-Bemerkungen
- Meerkat-Hacks (Blinds-as-Raise, BB-counts-as-raise) leaken in jeden Consumer und erzwingen Kompenstations-Wrapper (`voluntary_actions`) — leaky abstraction, Wurzel der Gen1/2-Bugs
- **Doku-Bug**: `GameInfo.active_players`-Doku sagt "non-folded, non-all-in", Runner füllt mit `count_active_players()` (inkl. all-in) — dieselbe active_players-vs-num_active-Falle wie beim Gen2 is_short_handed-Bug
- Duplizierte Helper über 4 Trivial-Bots; Pot-Limit-Enforcement doppelt (step vs validator); totes `BettingRules.min_raise_amount`, `first_to_act` write-only, `_find_next_active_seat` dead, `apply_call()` leer

## Top-Fixes nach Mess-Impact
1. H1+H2 (Kurz-AllIn-Handling — ändert Pot-Geometrie und Action-Rechte)
2. M1+M5 (FlockBot vs Shoves + kein echtes TAG — "Referenz" ist keine)
3. H3 opt-in machen; M6 Odd-Chip-Regel; Doku-Fix active_players

id: fa4fb21a70a849e49efa376a4c312faf
parent_id: 111595e632f1437d8c451eb73811d9c2
created_time: 2026-08-23T14:02:58.368Z
updated_time: 2026-08-23T14:02:58.368Z
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: 1787493778368
user_created_time: 2026-08-23T14:02:58.368Z
user_updated_time: 2026-08-23T14:02:58.368Z
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