Structural Review — Decision Code (2026-08-22)

# Struktur-Review Decision-Code (2026-08-22)

> Zwei Subagent-Reviews (Postflop-Kern + Infrastruktur), Kernbefunde am Code verifiziert. Kohärente Erklärung für die Station-Lücke (+18 BB/100): **die gesamte Exploit-Maschinerie saturiert oder schaltet sich genau im Station-Regime ab.**

## Die Station-Kette (verifiziert, höchste Priorität)

**S1. NN wird gegen loose Gegner ABGESCHALTET** — `gen4/mod.rs:326-336`: bei eff. VPIP ≥ 0.55 → `station_factor=0` → alpha=0 → RangeNet komplett umgangen, heuristische Range genutzt. Und deren Anker enden bei VPIP 0.70 (`profile.rs:335`, clamp 0.05-0.90): ein 0.9-Station kriegt dieselbe Range wie ein 0.70er. **Konsequenz: Gegner-Ranges im Station-Regime systematisch zu eng → Hero-Equity unterschätzt → zu wenig Value.** Genau die Phantomsättigungs-Familie wie beim Preflop-Fix.

**S2. opp_looseness-Sättigung** — `formula_postflop.rs:811-815`: `looseness.clamp(0.7, 1.3)` erreicht das Cap bei VPIP≈0.567. ALLE postflop-Thresholds (bet/raise/call) und der Station-Sizing-Boost behandeln jeden Gegner ab VPIP 0.57 identisch.

**S3. Statisches Fold-Equity für Bluffs** — `formula_postflop.rs:1358` → `player_model.rs:100`: hardcoded Java-Portierung (flop 0.756, turn 0.766, river 0.774) hoch ^num_opponents. Der Observer trackt fold_to_bet pro Spieler — **wird nie gelesen**. Hero blufftknown Stations auf einer 83%-Fold-Fiktion.

**S4. Table-VPIP enthält Hero selbst** — `observer.rs:286,533`: `on_hand_start` baut HandStates für ALLE Seats inkl. Hero; das Table-Aggregat wird strukturell deflatiert (2 tighte CANDs an Station-Tisch: 0.85→0.63). Speist effective_vpip, aggressor_vpip, alle Blends.

## Value-Pfad (Postflop-Kern)

- **V1. eq_cc-Gate nur Heads-Up** — `gen4/mod.rs:701`: `ranges.len()==1`. Multiway (das loose 9-max-Feld!) hat KEIN Value-Gate. Kombiniert mit bet_base=0.08 → dünn betten in 3+ Caller ohne Continuing-Range-Check.
- **V2. River Thin-Value-Band entkommt dem Gate** — Gate nur bei `value>=0.30` (`:1081`); River-Threshold ~0.20 → Value [0.15,0.30) bettet ungeprüft — die dünnsten Bets sind ungegatet.
- **V3. Sizing-Sättigung** — `sizing_fraction`: Ceiling ~0.58 (excess clamp 0.5); station_boost max +0.09 (looseness-cap!); aggressor_vpip fällt first-in auf TABLE-VPIP zurück (ein Station unter 8 wird weggemittelt).
- **V4. second_barrel_penalty blind** — flat +0.15 auf Turn/River-Threshold, ungeachtet caller VPIP/WTSD. Mit V1: "flop dünn betten, Turn aufgeben" = Stations-Futter.
- **V5. eq_cc bei Anker-Size 0.5** nicht bei echter Bet-Size berechnet.
- **V6. Trap auf Table-Durchschnitts-AF** — ein Maniac am Tisch lässt Hero den Near-Nuts gegen den Station checken.

## Double-Counting-Familie (Phantom-Signatur)

- **D1. npot ×2, ppot ×3**: value_score diskontiert npot, multiway_value_adj erneut; draw_score ppot + multiway_draw_bonus + dieselbe Kurve nochmal als call_threshold-Senkung — dieselbe Implied-Odds-Wirkung auf BEIDEN Seiten des Vergleichs (`:1022-1027`, `:969-971`, `:1316`).
- **D2. value als hs über API-Grenze** an AllIn-Gate (0.60) — latent bei npot_weight 0.5.
- **D3. frac-Einheiten**: bet = frac·pot, raise = frac·pot als INKREMENT über current_bet.
- **D4. Limp-Complete: Phantom-50%-Postflop-Kosten** ohne Win-Gegenstück (`equity_preflop.rs:1214-1222`) — Spiegelbild des Preflop-Bugs.

## Observer/Stat-Defizite

- BB-Raise über Limper zählt nicht als VPIP/PFR (`observer.rs:359`)
- 3bet-Denominator enthält den Original-Raiser (driftet Richtung 0)
- pfr_looseness/reraise_looseness_power/equity_pos_bonus: **Dead Code** — geparst, nie gelesen (`equity_preflop.rs:1314` flat 0.58/0.60)
- All-In-Call-Gate flat 0.50 ohne Pot-Odds (`:1551`)
- Half-Life 100 / Prior 0.30: Station-Erkennung braucht ~56 Hände auf 0.6; AF nie beobachtet für pure Aggressoren; WTSD auf alle Hände (nicht saw-flop)
- Barrel-Compounding +0.10/Street opponent-blind — überschärft Station-Reads (`range_corrector.rs:960`)

## Guardrails/Predictor (klein)
- Guardrail 1 ignoriert ppot (faltet Nut-Combo-Draws); Guardrail 3 tot (is_preflop immer false); kein Guard gegen zu kleines Sizing (Richtung verpasster Value ungeschützt)
- Predictor: Empty-Range-Guard asymmetrisch; range_temp nur im Batch-Pfad

## Fix-Priorisierung (Vorschlag)
1. **S1+S2+S3+S4** (Station-Kette): alpha-Switch ersetzen durch NN-mit-Breite (kein Abschalten), looseness-Cap heben oder Kurve ersetzen, fold_equity aus Observer-Stats, Hero aus Table-Aggregat
2. **V1+V2+V4**: eq_cc multiway (stärkster Range), Gate-Band auf [thresh,0.30) schließen, second_barrel nach Caller-Stats konditionieren
3. **D1**: Double-Counts entfernen (unit-test-bar)
4. Rest (Dead Code, Observer-Fixes, All-In-Odds) als Folge-Commits

Baselines laufen: g48+g51 volle Gates 1-6 auf aktuellem Binary (Vergleichs-Referenz für die Fixes).

id: 27c500f5a6fd4cd491a169af4cd218ec
parent_id: 111595e632f1437d8c451eb73811d9c2
created_time: 2026-08-22T08:41:19.386Z
updated_time: 2026-08-22T08:41:19.386Z
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: 1787388079386
user_created_time: 2026-08-22T08:41:19.386Z
user_updated_time: 2026-08-22T08:41:19.386Z
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