Skip to content

feat(blueprint): postflop subgame wiring + range expansion (Phase 4, #68)#177

Merged
amaster97 merged 2 commits into
mainfrom
feat-premium-a-phase-4-postflop-wiring
May 28, 2026
Merged

feat(blueprint): postflop subgame wiring + range expansion (Phase 4, #68)#177
amaster97 merged 2 commits into
mainfrom
feat-premium-a-phase-4-postflop-wiring

Conversation

@amaster97

Copy link
Copy Markdown
Owner

Summary

Premium-A Phase 4 (issue #68) — thin Python glue layer that bridges the 169-class preflop blueprint (Phase 1, PR #167 / PR #171) to the postflop range-vs-range Nash solver. The existing chained orchestrator does NOT consume a pre-existing Blueprint asset (it runs its own Stage 1 preflop solve), so this PR adds a separate entry point operating directly on blueprint data — Phase 4 scope is independent of Phases 2 (loader) and 3 (interpolation).

New surface in poker_solver.blueprint_subgame (also re-exported from the top-level package):

  • derive_continuation_ranges_from_blueprint: walks a preflop action sequence through the blueprint's history-keyed infosets, multiplying per-class action probabilities to produce per-class reach.
  • expand_classes_to_range: 169-class -> 1326-combo expansion (uniform within class), with board-blocker filtering and per-combo weights threaded into a Range.
  • solve_postflop_from_blueprint: full pipeline (lookup -> expand -> postflop solve) returning a BlueprintPostflopResult with per-stage wall times.

Scope hygiene

  • No engine code modified. No Rust changes.
  • No 169-class engine code modified.
  • No chained orchestrator (chained.py) modified. Wider refactor (Phase 4 subplan §4 suggests replacing chained.py's Stage 1 with a blueprint lookup) is deferred — out of this phase's scope.
  • Phase 4 scope is "verify postflop subgame solver consumes the blueprint as range prior; add wiring if missing". This adds the wiring as a separate entry point so chained.py's behavior stays intact for the Phase A test suite.

Test plan

  • tests/test_blueprint_subgame_wiring.py — 15 cases, all passing locally:
    • Range expansion: uniform within class, weight-scaling across classes, board-blocker filtering, error paths.
    • Reach derivation: root reach == 1.0; polarized AA shove (10/90) propagates correct reach; missing-infoset raises clean error; class filtering; bad hero_player rejected.
    • End-to-end on Qs 7h 2d flop: blueprint -> 1326 expansion -> Rust vector-form CFR returns a simplex-valid strategy.
  • ruff check clean on new files + __init__.py.
  • Existing tests still collect (tests/test_blueprint_pipeline.py 24/24 pass; tests/test_chained_orchestrator.py collects 9 tests, no broken imports).

Wall-time sample

End-to-end blueprint lookup -> 1326 expansion -> postflop subgame solve on a 2-class fixture (AA + KK) on Qs 7h 2d, 30 iterations:

[Phase 4 wall-time] total=0.914s, lookup=0.000s, expand=0.000s, solve=0.914s

Lookup + expansion are pure Python, microsecond-scale. Solve cost dominates (Rust vector-form CFR, dominated by the 30-iter setting). Production iter counts (500-2000) would scale roughly linearly here.

What this unblocks

Phase 5 (top-level routing layer Solver.solve(spot)) can now route postflop spots through solve_postflop_from_blueprint once Phases 2 + 3 land the loader / interpolation. Phase 5 will likely also wrap or replace chained.py's Stage 1 to share the blueprint cache.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

🤖 Generated with Claude Code

amaster97 and others added 2 commits May 28, 2026 03:34
)

Add a thin Python glue layer that bridges the Premium-A 169-class preflop
blueprint (Phase 1) to the postflop range-vs-range Nash solver. The
existing chained orchestrator does NOT consume a pre-existing Blueprint
asset (it runs its own Stage 1 preflop solve via Route A aggregation),
so this PR ships a separate entry point operating from blueprint data.

New surface in poker_solver.blueprint_subgame:
- derive_continuation_ranges_from_blueprint: walks a preflop action
  sequence through the blueprint's history-keyed infosets, multiplying
  per-class action probabilities to produce per-class reach into a
  given terminal.
- expand_classes_to_range: 169-class -> 1326-combo expansion (uniform
  within class), with board-blocker filtering and per-combo weights
  threaded into a Range.
- solve_postflop_from_blueprint: end-to-end pipeline (lookup -> expand
  -> postflop solve) returning a BlueprintPostflopResult that carries
  per-stage wall times for verification.

Integration test (tests/test_blueprint_subgame_wiring.py, 15 cases):
- Range expansion: uniform within class, weight-scaling across classes,
  board-blocker filtering, error paths.
- Reach derivation: root reach == 1.0; polarized AA shove (10/90)
  propagates 0.1 reach for AA at continuation; missing-infoset raises;
  class filtering; bad hero_player rejected.
- End-to-end on Qs 7h 2d flop: blueprint -> 1326 expansion -> Rust
  vector-form CFR returns a simplex-valid strategy; wall time on a
  2-class fixture is ~0.9 s (30 iters).

No engine code modified. No 169-class engine code modified. Chained
orchestrator (chained.py) untouched per Phase 4 scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@amaster97 amaster97 merged commit 18b9bcf into main May 28, 2026
5 of 8 checks passed
amaster97 added a commit that referenced this pull request May 28, 2026
Preemptive draft for v1.9.0 — ready for ship-trigger after audit
clears. Covers the Premium-A blueprint shipping milestone:

- 27 precomputed preflop blueprint shards (PR #171 + asset commit
  1783bef): 169-class engine 178x/406x/448x speedup; ~21 MB bundle
  shipped under assets/blueprints/.
- Blueprint loader API (PR #174), stack-depth interpolation (PR #173),
  postflop subgame wiring (PR #177), top-level SolverRouter (PR #181),
  UI integration (PR #178).
- Vector-form BR walk (PR #170): W2.3 strict-PASS, persona table
  17/0/0/0 (recorded in PR #184).
- CS-bug fix (PR #165): preflop State::initial honors
  config.initial_contributions.
- B10 per-combo frequency train (PRs #149/#154/#158/#160): W2.2 Sarah
  Range.diff -> PASS.
- DCFR optimization ledger (docs/rust_optimization_ledger.md):
  empirical speedups for PRs #114/#139/#150/#157/#162/#170/#171.

Known limitations disclosed honestly:
- Flop live-solve OOMs in v1.9.0; flop = blueprint-only. v1.10
  task #70 addresses (docs/v1_10_postflop_optimization_plan.md).
- top_k_per_side is a speed knob, not a correctness flag.
- "Realtime postflop" claim scoped precisely: turn + river only.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
amaster97 added a commit that referenced this pull request May 28, 2026
#196)

Audits #69 (v1.9.0) and #71 (v1.10.0) both flagged that the persona-
table claimed Wendy (Premium-A consumer) coverage existed but the W5.x
workflows had never been authored. This PR ships the five W5.x persona
tests via tests/test_w5_premium_a_personas.py, restores the persona
acceptance spec at docs/pr13_prep/persona_acceptance_spec.md (lost when
the docs/pr13_prep/ directory was historically purged), and bumps the
snapshot count 17 → 22 in docs/persona_status_2026-05-28-w5x.md.

The five workflows:
  W5.1 — Blueprint Casual Lookup (100 BB / no-ante / AKs, <100 ms
         warm-cache, 10 cells populated) — PR #174 (BlueprintLoader)
  W5.2 — Interpolated Depth Lookup (67 BB = 0.65 * v60 + 0.35 * v80
         convex blend) — PR #173 (interp) + PR #181 (router)
  W5.3 — Blueprint → Postflop Chained on Qs7h2d, synthetic 2-class
         smoke fixture (production-scale OOM-blocked per the v1.10
         perf roadmap; documented as a deferred follow-up) — PR #177
         + PR #182 + PR #181
  W5.4 — Custom Range Fallback (B10 override forces custom_live_solve,
         not blueprint_lookup) — PR #181 + B10 PRs #149/#154/#158
  W5.5 — Ante Selection (40 BB / 72o shifts L1>0.05 across no/half/
         full ante) — 27-shard bundle (chore `1783bef`) + PR #174

13/13 tests PASS in 1.13 s on M-series arm64. No engine code touched;
docs + tests only.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
amaster97 added a commit that referenced this pull request May 28, 2026
Updates README + USAGE to reflect v1.10.0 ship state (combined v1.9.0
Premium-A + v1.10 postflop optimization MINOR bump) per the v1.9.0
audit (task #69) findings. v1.9.0 was drafted but never tagged; both
docs were stuck at v1.8.x prose.

README.md (+150/-80 net):
- Status: bump v1.8.0 -> v1.10.0; strike v1.6.0 fork-bomb warning
  (resolved in v1.8.0 PR #42 727206e; left a historical mention of
  what was fixed)
- Preflop blueprint mode: expand from 3 sentences to a full section
  covering the four-API surface (BlueprintLoader/interp/subgame/
  SolverRouter), Phase 6 UI wiring (PR #178 chart widget source
  badges + chained tab + live-solve confirmation modal), B10
  per-combo editor (PRs #149/#154/#158/#160), Phase 7+8 docs
  (PRs #175/#176), and v1.10 flop unblock (task #70)
- "What's new in v1.10.0" replaces "Recent changes (since v1.8.0)";
  cites per-PR for Premium-A train + v1.10 postflop optimization
- UI section: chart widget + chained tab now consume real solver
  (PR #178); standalone ad-hoc tab still mock (PR 10b pending)
- Known issues: strike v1.6.0 fork-bomb (resolved), replace with
  ad-hoc-signing + arm64-only framing

USAGE.md (+185/-100 net):
- Header: v1.8.x -> v1.10.0; rewrite document baseline + v1.10.0
  section pointer paragraph
- Path A (.dmg): remove "DO NOT LAUNCH" warning, document Gatekeeper
  override flow for ad-hoc-signed bundle
- New §5.10 "CLI BB-normalization (v1.9.0; canonical in v1.10.0)"
  covering --pot N --stack M canonical flags + --pot-bb/--stack-bb
  deprecation warning (PR #152)
- §5.9 Preflop blueprint: extend with chained postflop subgame
  example (solve_postflop_from_blueprint, PR #177) + top-level
  SolverRouter example (PR #181) + honest perf framing (flop
  unblocked but benchmark numbers TBD)
- §7b Known perf cliffs: bump from v1.7.x to v1.10.0; document flop
  unblock from v1.9.0 OOM-killed; preserve aggregator-recommended
  framing for production-scale chart generation
- §7 Known limitations: bump from v1.0.0 to v1.10.0; UI partial-real
  framing (chart widget + chained tab real; standalone tab still mock)
- §8 What's coming: drop completed items; flag v1.10 perf benchmark
  publication as next-up + PR 10b standalone-tab swap
- --version output: bump 1.8.0 -> 1.10.0

Ship date: 2026-MM-DD placeholder; honest framing throughout that
flop top_k=169 wall numbers are TBD by combined-stack benchmark
(task #70 PRs #186-#190 + PR-1 arena + PR-3 vector flop).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant