pokertools-arena 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,171 @@
1
+ # Release notes
2
+
3
+ ## 0.4.0 — Methodology, reproducibility and repository organization
4
+
5
+ This release does not redesign the 0.3.0 decision foundations. It makes the
6
+ benchmark more rigorous, separates the questions being answered, and reorganizes
7
+ the repository so there is one source of truth for code, tools, tests and
8
+ documentation.
9
+
10
+ ### Repository
11
+
12
+ - Browser application source now lives under `src/` (`src/app.js`,
13
+ `src/index.html`, `src/styles.css`, `src/lib/decision-core.js`,
14
+ `src/benchmark/scenarios.js`, `src/env/arena-env.js`, `src/shims/crypto.cjs`,
15
+ `src/assets/`). There are no duplicate root copies.
16
+ - Developer-only implementation lives under `tools/diagnostics/` and
17
+ `tools/release/`; tests are grouped into `tests/unit`, `tests/integration`,
18
+ `tests/real` and `tests/analysis`; documentation lives under `docs/`.
19
+ - `build.mjs`, `bin/pokertools-arena.mjs`, every import, npm script, GitHub
20
+ workflow and documentation link were updated for the new layout.
21
+
22
+ ### Methodology
23
+
24
+ - **Paired fixed-state corpus** (`tools/diagnostics/corpus.js`): immutable,
25
+ production-shaped decision states covering strict legality/dominance, value
26
+ betting, bluffing, preflop, hand recognition and representation sensitivity.
27
+ Gold answers exist only where strict dominance or an explicit synthetic
28
+ opponent policy makes them deterministic.
29
+ - **Paired flat-vs-hierarchical test** (`tools/diagnostics/paired.js`): the same
30
+ model, state, context, mode and representation under both architectures, with
31
+ deterministic interleaving and a recorded `experimentSeed`. This is the
32
+ primary architecture comparison; real tournaments are end-to-end validation.
33
+ - **Family vs sizing correctness** are reported separately, with sizing accuracy
34
+ conditional on a correct family, plus final-action accuracy.
35
+ - **`fragmentation_flip_rate`**: the share of paired runs whose broad family
36
+ changes when only the number of same-family sizing choices changes, across
37
+ menus A/B/C/D and multiple states.
38
+ - **Exact entropy validation and domain labelling**: `familyEntropyBits`,
39
+ `sizingEntropyBits` and `flatActionEntropyBits`; a generic “entropy” is never
40
+ reported.
41
+ - **Standardized counters** (`tools/diagnostics/counters.js`): `pokerDecisions`,
42
+ `familyModelCalls`, `sizingModelCalls`, `spectatorModelCalls`,
43
+ `totalModelCalls`, `httpRequests`, `httpRetries`, `rateLimitResponses`,
44
+ `decisionErrors`, `fallbackActions`, `protocolFallbacks`, with asserted
45
+ relationships.
46
+ - **Wilson 95% confidence intervals and sample sizes** for behavioral
47
+ proportions, so 2/2 and 100/100 are not presented with equal strength.
48
+ - **One generated summary** (`tools/diagnostics/report.js`) drives every
49
+ human-readable report; a release test fails if committed documentation drifts
50
+ from the machine-readable totals.
51
+ - **Spectator explanations default off** in rigorous runs; when enabled they are
52
+ isolated and counted separately.
53
+ - **Size-bucket boundary audit** for tiny/huge stacks, min-bet/min-raise edges,
54
+ all-in below min raise, all-in near LARGE, pot smaller than the big blind,
55
+ heads-up, multiway and post-elimination states.
56
+
57
+ ### Testing and CI
58
+
59
+ - `npm run test:unit`, `test:integration`, `test:real`, `test:tournament-ab`,
60
+ `report:diagnostics` and `release:archive` replace the ad-hoc script names.
61
+ - CI runs install → build → release checks → unit/fairness → integration and
62
+ never requires real API credentials. Real diagnostics run from a manual,
63
+ secret-gated workflow.
64
+ - The release archive is built from the new layout, excludes secrets/logs/dist,
65
+ and is verified by an archive-content regression test.
66
+
67
+ ### Compatibility
68
+
69
+ - The browser build, GitHub Pages deployment, `npx pokertools-arena` launcher and
70
+ automatic `.env` bootstrap are preserved.
71
+ - `@pokertools/engine@1.0.20` and `@pokertools/evaluator@1.0.20` are unchanged.
72
+ - The `.env` file is never moved, printed or archived.
73
+
74
+ ## 0.3.0 — Fair hierarchical decisions, Strategy/Raw modes, deterministic hand evaluation
75
+
76
+ This release is a fairness and correctness release. It changes how the benchmark
77
+ turns a poker state into a decision so that CHECK, CALL, FOLD, BET and RAISE are
78
+ represented fairly for **every** model, regardless of how many bet sizes an
79
+ arena happens to generate.
80
+
81
+ ### The problem
82
+
83
+ A single passive strategy was represented by one class (e.g. `CHECK`) while a
84
+ single aggressive strategy could be represented by many classes (`BET 1 BB`,
85
+ `BET 2 BB`, `BET 3 BB`, …, `BET ALL-IN`). Under a flat argmax this fragmenting
86
+ of the aggressive probability mass made passive actions look dominant even when
87
+ the model's total aggressive probability was larger.
88
+
89
+ ### What changed
90
+
91
+ - **Hierarchical decision architecture (`hierarchical-v1`).** Every model is now
92
+ asked two questions:
93
+ 1. **Action family** — `CHECK`/`BET` when nothing is owed, or
94
+ `FOLD`/`CALL`/`RAISE` when facing a bet. Only legal families are exposed.
95
+ 2. **Size** — only when the family is `BET` or `RAISE`, from a deterministic,
96
+ engine-validated size set (`SMALL`, `MEDIUM`, `LARGE`, `ALL_IN`).
97
+ A single passive strategy is one family; a single aggressive strategy is one
98
+ family. The model cannot change the family during the sizing step.
99
+ - **One canonical decision contract.** `src/lib/decision-core.js` is the single
100
+ source of truth for decision state, action families, sizing choices, Jev
101
+ questions, chat schemas and the final engine action. Production, diagnostics
102
+ and tests all use the same functions.
103
+ - **Deterministic sizing.** `legalAggressiveSizes(engine, seat, family)` clamps
104
+ to the available stack, respects the minimum bet/raise, deduplicates and drops
105
+ near-duplicate amounts, always includes all-in when materially distinct, and
106
+ works for short stacks (a single `ALL_IN` or `SMALL`/`ALL_IN` is valid).
107
+ - **No prose in the primary decision.** Chat models no longer return
108
+ `publicReason` inside the action call. The primary contract contains only
109
+ typed decision fields. Spectator explanations are a separate, isolated,
110
+ off-the-clock concern (disabled by default; Jev never gets fabricated prose).
111
+ - **Strategy / Raw benchmark modes.** A tournament-wide setting:
112
+ * **Strategy** — every model receives a deterministic `heroHand`
113
+ (`{ category, description }`) generated by `@pokertools/evaluator`.
114
+ * **Raw cognition** — no `heroHand`; models infer strength from raw cards.
115
+ The mode applies to all seats and is recorded in tournament state, logs,
116
+ reports and replays. Opponent hand evaluations are never exposed.
117
+ - **Representation modes.** `canonical_json` (default), `compact_json` and
118
+ `markdown`, applied to every seat.
119
+ - **Shared action clock.** The family and size calls share one abort signal and
120
+ one action clock. A model does not receive a fresh timer for the sizing stage.
121
+ - **Decision event schema.** `decisionMeta` now carries
122
+ `decisionArchitecture`, `family` and `sizing` (choice, probabilities,
123
+ confidence, latency) plus `finalAction`. Events record `primaryDecisionLatencyMs`
124
+ (family latency + sizing latency, excluding spectator explanations).
125
+ - **Legacy aggregation.** `aggregateActionProbabilitiesByFamily` folds old flat
126
+ probability vectors into family mass for replay and log analysis, labelled
127
+ “Aggregated from legacy flat action probabilities”. Historical selected actions
128
+ are never changed.
129
+ - **Jev telemetry.** Internal identifiers (`A0`, `A1`, …) are translated through
130
+ the actual choice map. Spectators see family probabilities, sizing
131
+ probabilities, confidence bands, aggression tendency and bluff-opportunity
132
+ telemetry rather than invented text rationales.
133
+ - **Diagnostics.** New `action_fragmentation`, `flat vs hierarchical`, `probe`
134
+ matrix and family-entropy/telemetry sections in
135
+ `tests/real/real-decision-diagnostics.mjs`; new offline fairness suite
136
+ `tests/unit/hierarchical-decision-tests.mjs`; real tournament A/B harness
137
+ `tests/real/real-tournament-ab.mjs`; concise summary builder
138
+ `tests/analysis/diagnostics-summary.mjs`.
139
+
140
+ ### Compatibility
141
+
142
+ - Flat legacy mode is retained **only** as a diagnostics baseline
143
+ (`decisionArchitecture: "flat"`). Hierarchical is the production default.
144
+ - `@pokertools/engine@1.0.20` and `@pokertools/evaluator@1.0.20` are unchanged.
145
+ - Existing `.env` bootstrap, GitHub Pages and `npx pokertools-arena` workflows
146
+ are unchanged.
147
+
148
+ ### Measured effect (real API, 2026-09-19)
149
+
150
+ 369 decisions across Gemma, Qwen and Jev, 0 request errors, 415 HTTP requests.
151
+
152
+ Action-fragmentation experiment on identical river states:
153
+
154
+ | Menu | Gemma | Qwen | Jev |
155
+ | --- | --- | --- | --- |
156
+ | A · CHECK / BET ALL-IN | 0% | 89% | 100% |
157
+ | B · CHECK / BET SMALL / ALL-IN | 0% | 56% | 56% |
158
+ | C · CHECK / BET SMALL / MEDIUM / LARGE / ALL-IN | 0% | 56% | 33% |
159
+ | D · hierarchical | 0% | 44% | 100% |
160
+
161
+ Jev's aggressive-selection rate collapsed from 100% to 33% purely by adding
162
+ almost-identical bet-size classes, and the hierarchical architecture restored
163
+ it to 100%. This is the option-count asymmetry the release removes. Jev's mean
164
+ family aggressive probability mass rose from 45% (fragmented flat) to 56%
165
+ (hierarchical), and its selected-family probability from 37% to 73%.
166
+
167
+ Strict diagnostics were preserved: Layer A (action-id mapping) 100%, Layer D
168
+ (strictly dominated) 100% flat / 94% hierarchical, Layer B (raw hand
169
+ recognition) 62% — the same cross-model weakness as before, and the reason
170
+ Strategy mode exists.
171
+
@@ -0,0 +1,250 @@
1
+ # pokertools-arena 0.3.x — technical verification record
2
+
3
+ Fairness/correctness release: hierarchical decisions for every model, Strategy/Raw
4
+ benchmark modes, deterministic hand evaluation, and a prose-free primary decision
5
+ contract.
6
+
7
+ ## 1. Implementation summary
8
+
9
+ ### Canonical decision core (`src/lib/decision-core.js`)
10
+
11
+ - `legalActionFamilies(legalActions, { toCall })` — the one canonical family set.
12
+ Free check exposes `check` + (`bet`|`raise`); facing a bet exposes
13
+ `fold`/`call`/(`raise`). Never exposes `fold` when `check` is free; never
14
+ exposes `bet` and `raise` together; throws on any arena invariant violation.
15
+ - `planAggressiveSizes` / `aggressiveSizesForState` / `legalAggressiveSizes` —
16
+ deterministic, engine-validated sizing. At most four buckets
17
+ (`small` ≈33% pot, `medium` ≈67%, `large` ≈100%, `all_in`), clamped to the
18
+ stack, respecting the minimum bet/raise, deduplicated, near-duplicates removed,
19
+ all-in only when materially distinct, correct for short stacks.
20
+ - `buildHierarchicalDecision`, `familyCriteria`, `sizeCriteria`,
21
+ `chatFamilySchema`, `chatSizeSchema`, `buildJevFamilyQuestions`,
22
+ `buildJevSizeQuestions` — one representation of the hierarchy for every adapter.
23
+ - `resolveHierarchicalAction` — resolves `(family, size)` to one validated
24
+ engine action; the deterministic size amount is authoritative.
25
+ - `decideHierarchical` — the two-stage executor: one shared `combineAbort`
26
+ signal (one action clock), family call then optional size call, no prose,
27
+ flat menus stripped from hierarchical prompts, request/usage accounting.
28
+ - `applyBenchmarkMode` / `stripHeroHand` — Strategy adds a deterministic,
29
+ hero-only `heroHand`; Raw withholds it.
30
+ - `renderDecisionState` — `canonical_json` / `compact_json` / `markdown`.
31
+ - `aggregateActionProbabilitiesByFamily` / `probabilityStats` — legacy flat
32
+ probability folding into family mass, plus entropy/top-second-gap stats.
33
+ - `diagnosticsCounters` — process-local HTTP request/retry/rate-limit counters.
34
+
35
+ ### Production (`src/app.js`)
36
+
37
+ - Hierarchical is the production default; flat legacy is diagnostics-only.
38
+ - Tournament-wide `benchmarkMode`, `decisionArchitecture`, `representation`,
39
+ `spectatorExplanations` settings, recorded in tournament meta, events and
40
+ replays.
41
+ - Deterministic engine-validated size set built once per decision and shared by
42
+ the request and the UI.
43
+ - Final action re-validated by PokerTools after both stages.
44
+ - Spectator explanations run after the move in an isolated serial queue with an
45
+ 8-second budget, never feed model context, and never count toward primary
46
+ latency. Jev gets typed telemetry, never fabricated prose.
47
+ - `decisionMeta` carries `decisionArchitecture`, `family`, `sizing`,
48
+ `finalAction`; events carry `primaryDecisionLatencyMs`.
49
+ - Current Decision panel shows stage 1 (`Action family`, "Stage 1 of 2 · action")
50
+ and stage 2 (`BET size`, "Stage 2 of 2 · sizing") with identical geometry for
51
+ all models.
52
+ - Recent Decisions and replay show translated family/sizing telemetry; legacy
53
+ flat events show "Aggregated from legacy flat action probabilities" without
54
+ changing the historical action. Raw `A0/A1` identifiers are no longer shown in
55
+ the primary UI.
56
+ - New UI: Benchmark mode selector (Strategy/Raw), and a Diagnostics/developer
57
+ section for Decision architecture, Representation and Spectator explanations.
58
+
59
+ ### Diagnostics and tests
60
+
61
+ - `tests/unit/hierarchical-decision-tests.mjs` — 16 offline fairness assertions.
62
+ - `tests/real/real-decision-diagnostics.mjs` — hierarchical strict diagnostics,
63
+ `action_fragmentation` (flat A/B/C vs hierarchical D), four-way probe matrix,
64
+ flat-vs-hierarchical and Jev family-telemetry tables, acceptance answers,
65
+ HTTP request accounting, `--from-json` offline re-render.
66
+ - `tests/real/real-tournament-ab.mjs` — real flat-vs-hierarchical tournament A/B.
67
+ - `tests/analysis/diagnostics-summary.mjs` — concise release report with `--merge`.
68
+ - `tools/release/archive.mjs` — source archive builder with secret/exclusion guards.
69
+
70
+ ### Release
71
+
72
+ - Version `0.3.0` in `package.json` and `package-lock.json`.
73
+ - `RELEASE_NOTES.md`, `CONTEXT.md`, `THIRD_PARTY_NOTICES.md`, updated README and
74
+ `tests/README.md`, new `0.3.0` CSS section, release-check invariants.
75
+
76
+ ## 2. Bugs found and fixed
77
+
78
+ 1. **Jev hierarchical questions were double-wrapped.** `buildJevFamilyQuestions`
79
+ returned `{ action_family: { type: 'choice', … } }`, which the transport
80
+ wrapped again into `questions.action_family.action_family`; OpenRouter rejected
81
+ it (`invalid_union`, "No matching discriminator"). Fixed to return the bare
82
+ choice object.
83
+ 2. **Hierarchical sizing lost the deterministic amount.** `resolveHierarchicalAction`
84
+ fell back to the nearest flat candidate when the exact amount was absent,
85
+ silently replacing e.g. a 33%-pot size with a different amount. Fixed so the
86
+ validated deterministic size amount is authoritative.
87
+ 3. **`player` was out of scope** in the production final-validation path; changed
88
+ to `agent.id`.
89
+ 4. **Flat menus leaked into hierarchical prompts**, giving Jev both the family
90
+ question and a flat action list. Fixed by stripping `legalActions` from
91
+ hierarchical state and text.
92
+ 5. **Legacy flat-event aggregation required typed saved actions.** Added
93
+ description-based inference so old logs aggregate correctly.
94
+ 6. **Tournament A/B `playersRemaining` mismatch** — the harness counted only
95
+ live stacks while production counts still-seated players; fixed to match.
96
+ 7. **Tournament A/B percentage formatting** double-multiplied already-fractional
97
+ values; fixed with a value formatter and proper denominator counts.
98
+ 8. **Offline re-render wiped transport counters**; fixed to preserve saved
99
+ counters (and the saved run files were restored).
100
+
101
+ ## 3. Before/after diagnostic results
102
+
103
+ Broad run: 369 decisions, 415 HTTP requests, 0 request errors.
104
+
105
+ | Metric | Before (flat) | After (hierarchical) |
106
+ | --- | --- | --- |
107
+ | Layer A action-id mapping | 100% | n/a (flat-only by design) |
108
+ | Layer B hand recognition | 62% | 62% (unchanged, cross-model weakness) |
109
+ | Layer D strictly dominated | 100% | 94% |
110
+ | Strict overall | 83% | 94% |
111
+ | Jev family entropy (bits) | 0.34 | 0.80 |
112
+ | Jev selected-family probability | 37% | 73% |
113
+ | Jev mean aggressive family mass | 45% | 56% |
114
+
115
+ ## 4. Flat vs hierarchical comparison
116
+ On identical shared action scenarios (fragmentation/probe menus excluded):
117
+
118
+ | Model | Architecture | Agg rate | Check rate | Mean agg family mass | Mean latency |
119
+ | --- | --- | --- | --- | --- | --- |
120
+ | Gemma | Flat | 40% | 20% | — | 1583ms |
121
+ | Gemma | Hierarchical | 40% | 20% | — | 2176ms |
122
+ | Qwen | Flat | 40% | 20% | — | 7197ms |
123
+ | Qwen | Hierarchical | 33% | 27% | — | 5663ms |
124
+ | Jev | Flat | 40% | 20% | 40% | 407ms |
125
+ | Jev | Hierarchical | 60% | 0% | 46% | 777ms |
126
+
127
+ ### Fragmentation experiment (aggressive-selection rate by menu)
128
+
129
+ | Menu | Gemma | Qwen | Jev |
130
+ | --- | --- | --- | --- |
131
+ | A · CHECK / BET ALL-IN | 0% | 89% | 100% |
132
+ | B · CHECK / BET SMALL / ALL-IN | 0% | 56% | 56% |
133
+ | C · CHECK / BET SMALL / MEDIUM / LARGE / ALL-IN | 0% | 56% | 33% |
134
+ | D · hierarchical | 0% | 44% | 100% |
135
+
136
+ Jev's aggression collapsed from 100% to 33% purely by adding almost-identical
137
+ bet-size classes, and hierarchy restored it to 100%.
138
+
139
+ ### Real tournament A/B (12 hands/arch, 10000 stack, 50/100 blinds, 5 hands/level, ×1.5)
140
+
141
+ | Model | Architecture | Decisions | Agg opps | Aggressive | Agg rate |
142
+ | --- | --- | --- | --- | --- | --- |
143
+ | Gemma | Flat | 36 | 36 | 6 | 17% |
144
+ | Gemma | Hierarchical | 26 | 23 | 11 | 48% |
145
+ | Qwen | Flat | 35 | 34 | 13 | 38% |
146
+ | Qwen | Hierarchical | 12 | 12 | 2 | 17% |
147
+ | Jev | Flat | 30 | 30 | 2 | 7% |
148
+ | Jev | Hierarchical | 24 | 21 | 6 | 29% |
149
+
150
+ 163 tournament decisions, 0 errors, 0 fallbacks. Win rate is not a conclusion at
151
+ this sample size.
152
+
153
+ ### Representation sensitivity (accuracy on the fixed-answer action scenarios)
154
+
155
+ All representations scored 100% for all three models, with aggressive rate
156
+ varying only within small-sample noise (Gemma 20–40%, Qwen 20–40%, Jev 20–40%).
157
+ No provider needs a richer representation: canonical JSON, minimal JSON, flat
158
+ JSON, raw text, markdown, semantic keys and canonical+heroHand all carry the
159
+ same semantics.
160
+
161
+ ### Context ablation
162
+
163
+ Accuracy was 100% in every context variant for every model. Jev's aggressive
164
+ rate stayed at 100% for immediate/action-history/public-stats/full context and
165
+ 50% for recent-hands (small sample); no context field is required for legality
166
+ and none is provider-specific.
167
+
168
+ ## 5. Fairness verification
169
+
170
+ Automated (`npm run test:hierarchical`, 16 assertions) plus `decision-diagnostics`:
171
+
172
+ 1. Same canonical decision semantics for all models.
173
+ 2. Identical action families for the same engine state.
174
+ 3. Identical sizing candidates for the same engine state.
175
+ 4. Strategy/Raw mode applies globally, never per seat.
176
+ 5. `heroHand` is deterministic.
177
+ 6. `heroHand` describes the hero only.
178
+ 7. Opponent cards remain hidden.
179
+ 8. Opponent hand evaluation is never exposed.
180
+ 9. `recentHands`/`publicPlayerStats` equivalent across adapters.
181
+ 10. Jev criteria exactly match the chat schema enums.
182
+ 11. Chat models cannot select a size not presented to Jev.
183
+ 12. Jev cannot select a size not presented to chat models.
184
+ 13. Final engine actions are validated after both stages.
185
+ 14. Free `CHECK` never exposes `FOLD`.
186
+ 15. The total action timer spans both hierarchical stages (one abort signal).
187
+ 16. Spectator explanations cannot affect future model context.
188
+ 17. Spectator explanation latency is not counted as primary action latency.
189
+ 18. Diagnostic perfect-information fixtures cannot enter tournament mode.
190
+
191
+ ## 6. Jev diagnosis after fragmentation is removed
192
+
193
+ - Fragmentation, not poker policy, drove most of the observed passivity. The
194
+ two-choice menu produced 100% aggression; five aggressive classes produced 33%;
195
+ hierarchy restored 100% on the same states.
196
+ - Jev's aggressive probability mass was always substantial but fragmented
197
+ (flat family entropy 0.34, selected-family probability 37%). Hierarchy raised
198
+ selected-family probability to 73% and entropy to 0.80.
199
+ - On the 20-rep river probe, Jev bets the wheel straight 100% of the time with
200
+ hierarchy (both raw and heroHand), with mean aggressive family mass 61–82%.
201
+ - Residual passivity (e.g. flat 7% aggressive rate in one real tournament) is
202
+ best explained by the model's own policy and by raw-card hand recognition, not
203
+ by the option list. The arena now presents identical, symmetric choices to
204
+ every model.
205
+
206
+ ## 7. Exact commands run
207
+
208
+ ```bash
209
+ npm install
210
+ npm test
211
+ node tests/real/real-decision-diagnostics.mjs --experiments strict,hierarchical,fragmentation,probe --reps 3 --cap 380 --delay 50 --out logs/release-0.3.0
212
+ node tests/real/real-decision-diagnostics.mjs --experiments probe --reps 20 --cap 250 --delay 50 --out logs/release-0.3.0
213
+ node tests/real/real-decision-diagnostics.mjs --experiments representations,context,herohand --reps 2 --cap 320 --delay 50 --out logs/release-0.3.0
214
+ node tests/real/real-tournament-ab.mjs --hands 12 --cap 150 --models gemma,qwen,jev --architecture flat,hierarchical --delay 60 --out logs/release-0.3.0
215
+ node tests/analysis/diagnostics-summary.mjs --dir logs/release-0.3.0 --diagnostics <broad.json> --merge <probe.json> --tournament <ab.json> --out logs/release-0.3.0/diagnostics-summary.md
216
+ node tools/release/archive.mjs --out pokertools-arena-0.3.0.tar.gz
217
+ ```
218
+
219
+ ## 8. npm test result
220
+
221
+ `npm test` passes: build, release-check, `.env` bootstrap, `@pokertools/engine`
222
+ integration, decision scenarios, offline diagnostics, and the new hierarchical
223
+ fairness suite.
224
+
225
+ ## 9. Real API request/error counts
226
+
227
+ - Broad run: 369 decisions, 415 HTTP requests, 0 errors (1 retry, 1 rate-limit event).
228
+ - Probe (20 reps): 240 decisions, 323 HTTP requests, 0 errors.
229
+ - Representation/context/heroHand run: recorded in its own report.
230
+ - Tournament A/B: 163 decisions, 0 errors, 0 fallbacks.
231
+ - Total: >750 real decisions, 0 decision errors.
232
+
233
+ ## 10. Remaining caveats
234
+
235
+ - Layer B (raw hand recognition) remains 62% for all models; Strategy mode exists
236
+ precisely because of this, and Raw mode keeps the recognition benchmark alive.
237
+ - Hierarchical Layer D was 94% vs 100% flat on 36 samples (Qwen bet a smaller
238
+ value size or checked in two synthetic always-calls spots); this is a model
239
+ behavior, not an arena legality issue, and the sample is small.
240
+ - Win rate is not used as a conclusion at these sample sizes.
241
+ - The tournament A/B uses the same action clock but hierarchical aggressive
242
+ decisions require two calls; observed latencies are reported rather than
243
+ normalized.
244
+
245
+ ## 11. Release archive
246
+
247
+ `pokertools-arena-0.3.0.tar.gz` — full source archive (source, tests,
248
+ diagnostics, bin, browser shims, GitHub workflows, `package.json`, lockfile,
249
+ documentation). Excludes `.env`, secrets, generated logs, `dist/`, and
250
+ `node_modules`. Verified: 49 entries, no real `.env`, no API key.
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "pokertools-arena",
3
+ "version": "0.4.0",
4
+ "description": "Browser-first AI poker benchmark powered by @pokertools/engine with generic OpenAI-compatible endpoints, optional OpenRouter/Jev Decisions routing, deterministic hierarchical decisions, paired fixed-state methodology, and reproducible reporting.",
5
+ "type": "module",
6
+ "bin": {
7
+ "pokertools-arena": "bin/pokertools-arena.mjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "dist/",
12
+ "src/",
13
+ "docs/",
14
+ "README.md",
15
+ "LICENSE",
16
+ ".env.example"
17
+ ],
18
+ "scripts": {
19
+ "start": "node bin/pokertools-arena.mjs",
20
+ "start:chrome": "node bin/pokertools-arena.mjs --chrome",
21
+ "build": "node build.mjs",
22
+ "og": "rsvg-convert -w 1200 -h 630 -o src/assets/og-image.png src/assets/og-image.svg",
23
+ "check": "node --check src/app.js && node --check src/benchmark/scenarios.js && node --check build.mjs && node --check bin/pokertools-arena.mjs && node tests/release-check.mjs",
24
+ "test": "npm run build && npm run check && npm run test:unit && npm run test:integration",
25
+ "test:unit": "node tests/unit/decision-scenarios.mjs && node tests/unit/decision-diagnostics.mjs && node tests/unit/hierarchical-decision-tests.mjs && node tests/unit/methodology-tests.mjs && node tests/unit/size-bucket-tests.mjs && node tests/unit/paired-architecture-tests.mjs && node tests/unit/archive-content.mjs && node tests/unit/report-consistency.mjs",
26
+ "test:integration": "node tests/integration/pokertools-integration.mjs && node tests/integration/env-bootstrap.mjs",
27
+ "test:diagnostics": "node tests/real/real-decision-diagnostics.mjs",
28
+ "test:diagnostics:dry": "node tests/real/real-decision-diagnostics.mjs --dry-run",
29
+ "test:real": "node tests/real/real-decision-diagnostics.mjs && node tests/real/real-paired-corpus.mjs",
30
+ "test:tournament-ab": "node tests/real/real-tournament-ab.mjs",
31
+ "test:engine": "node tests/integration/pokertools-integration.mjs",
32
+ "test:env": "node tests/integration/env-bootstrap.mjs",
33
+ "test:scenarios": "node tests/unit/decision-scenarios.mjs",
34
+ "test:diagnostics:offline": "node tests/unit/decision-diagnostics.mjs",
35
+ "test:hierarchical": "node tests/unit/hierarchical-decision-tests.mjs",
36
+ "test:tournament": "node tests/real/real-tournament-ab.mjs",
37
+ "report:diagnostics": "node tests/analysis/release-report.mjs",
38
+ "report:release": "node tests/analysis/release-report.mjs --docs",
39
+ "analyze:decisions": "node tests/analysis/diagnostics-analyze.mjs",
40
+ "summarize": "node tests/analysis/diagnostics-summary.mjs",
41
+ "release:archive": "node tools/release/archive.mjs",
42
+ "test:browser": "node bin/pokertools-arena.mjs --chrome",
43
+ "prepack": "npm run build"
44
+ },
45
+ "keywords": [
46
+ "poker",
47
+ "llm",
48
+ "benchmark",
49
+ "openrouter",
50
+ "openai",
51
+ "jev",
52
+ "pokertools",
53
+ "ai-agents"
54
+ ],
55
+ "license": "MIT",
56
+ "engines": {
57
+ "node": ">=24.0.0"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/pokertools-arena/pokertools-arena.github.io.git"
65
+ },
66
+ "homepage": "https://pokertools-arena.github.io/",
67
+ "bugs": {
68
+ "url": "https://github.com/pokertools-arena/pokertools-arena.github.io/issues"
69
+ },
70
+ "dependencies": {
71
+ "@pokertools/engine": "1.0.20",
72
+ "@pokertools/evaluator": "1.0.20"
73
+ },
74
+ "devDependencies": {
75
+ "esbuild": "^0.28.2"
76
+ }
77
+ }