Findings  ›  Game probes

Game probes — findings & proposed fixes

The single evaluation document. Each famous game is authored as a definition file (game-defs/), imported, and simulated; everything it cannot express becomes a numbered finding with a proposed fix. The Decision column is deliberately empty — it is yours. Nothing here gets built until decided.

shipped open — fix proposed forecast — game not yet probed ceiling — deliberately out of scope

Method & where things stand

A probe is authored faithfully, including what we expect to fail — recorded failures are the deliverable. The import prints card-validation problems; setup prints engine warnings; simulation shows emergent wrongness (games ending at birth, draws that should be wins). Definition files live in game-defs/; import with php8.2 game-tool.php import game-defs/<file>.json.

#GameGenre stressStatus
1Star Realms (as Starforge Rivals)Combat deck-builder — the home genreplays fully · families untested
2DominionSupply piles, budgets, most-VP endingplays · 5 of 14 findings shipped
3AscensionCenter row, dual currency, defeat, shared poolplays wrongly · 8 findings
47 Wonders Duel (proposed)Tableau/pyramid, computed costs, multi-winforecast only
5Clank!Board movement fused with deck-buildingdeclared out of reach
6Slay the SpireSolo vs scripted enemies, block/intentsstretch — not probed

1 · Star Realms — via Starforge Rivals

Not a probe file: authored end-to-end through the real wizard, now the engine's reference game. Plays fully — 100% of greedy games end by the authored combat win. Remaining distance to real Star Realms:

IDObserved / missingProposed fixEffortStatusDecision
S1Faction ally bonuses (“if you control another Blob card…”) — families are an empty scaffold: no authoring UI, no AI awareness, no effect can target a family Finish the families axis: authoring UI on Step 2, AI prompt context, and an effect condition “count cards of family F you control” (the evaluator's count_cards already filters by card fields — small) ~1 dayopen
S2Bases with activated abilities (“tap for 2 Trade”) Q1's wire-but-disabled plan: abilities[] on card types + use_ability composite + exhausted state ~2 daysshipped (U3, 2026-08-06) — Salvage Outpost taps for 2 Trade
S3Scrapping (banish a card from hand/discard permanently) Player-chosen selector for move_cards + a void-style zone (shares machinery with Ascension A1) with A1open

2 · Dominion — game-defs/dominion.json

The founder: 17 supply piles, Action/Buy/Coin budgets, most-VP ending. First import ended on turn 1 with zero actions; after G5/G6/G7/G8/G1 it plays 41-turn games that end by the authored “Province pile empty” condition. Findings:

IDObserved / missingProposed fixEffortStatusDecision
G1No card-facing draw effect existed in the catalogAdded draw_n_cards_to_self; engine branch already existeddoneshipped
G5Supply piles never filled; deck→zone authoring unreadSetup as the game's first automatic phase: fill_zone/draw steps, authored or compiled, by deck namedoneshipped
G6One bindable market zone; Dominion has 16 buyable pilesmarket_zones set: every visible shared zone that refills or was deck-filleddoneshipped
G7highest_tracker winner rule resolved by fallthroughAll winner rules implemented; ties are draws; unknown rules refuse to invent a winnerdoneshipped
G8Ending true at setup ended the game on turn 1Arm endings after setup; true-at-birth = authoring warning, suppressed for the rundoneshipped
G12Games end 0–0: VP lives on cards (Estate 1, Province 6), nothing counts itScore-from-cards: implement resolution.metric as a JSON Logic expression evaluated per player at game end (+ a sum_cards(zones, field) evaluator aggregate for clean authoring). Makes Dominion AND Ascension produce real winners~½–1 dayshipped
G9Playing an Action card should spend 1 Action; play is freePer-play tracker cost as a binding parameter on play_card~1 day togethershipped (point 7)
G10Any card playable in any phase; Estates played as no-opsPer-phase card-type filters + an unplayable-from-hand propertyshipped (point 7)
G11Buys unlimited; the Buys tracker is decorative (100-card end decks)Per-turn action-use limit fed by a tracker (binding parameter)shipped (point 7)
G2Militia/Council Room: effects targeting the other playerEffect target scope each_opponent / all_players in the effect executor + catalog entries~½ dayopen
G4Gardens: VP computed from deck sizeDerived trackers (model doc B.7) — or covered by G12's metric if expressed as JSON Logicwith G12shipped (with G12)
G13“Any 3 supply piles empty” inexpressibleEvaluator count_zones_where (its own TODO #5)~½ dayopen
G3Moat's Reaction (interrupt an attack)Behaviour catalog entry is trivial; real interrupt semantics need the resolution stackceiling
G14Phases reference cleanup helpers not in the enabled-action list (warning)Harmless; authoring-side polishcosmetic

3 · Ascension — game-defs/ascension.json

Center-row deck-builder, dual currencies, defeat-to-void, shared honor pool. Structurally it nearly played on arrival (markets, refill, dual costs, constructs all worked — G5/G6/G1 paying off). Seed 1: p1 ends 88 honor to 53 — declared a draw. Findings:

IDObserved / missingProposed fixEffortStatusDecision
A588 vs 53 honor resolved as a draw at the turn limit (fallback compares the life tracker; Ascension has none)Turn-limit fallback: life-role tracker, else score-role tracker, else drawminutesopen — quick win
A1Defeated monsters land in the buyer's discard and get drawn later; the Void stays emptyA second acquisition composite: defeat — pay a (different) tracker, card goes to a named zone (void), reward fires. Destination + currency become per-action bindings (D4)~1 dayopen
A2on_defeat triggers silently rewritten to on_play; validation runs post-normalisation and saw nothingCoercion half FIXED by point 6: unknown triggers are preserved + flagged loudly, never rewritten. The defeat/acquire vocabulary itself still arrives with A1 — and can now be expressed as event patterns (card_moved to discard/trash)with A1half-shipped
A3Honor pool never drained; the authored ending was unreachableEffect target scope shared (adjust a shared tracker; optionally paired transfer: player +N, pool −N)~½ dayopen
A4terminates_at: end_of_round ignored (would end mid-round)Ending timing: immediate / end-of-turn / end-of-round in engineCheckEndings~½ dayopen
A6“Always available” Mystic/Heavy piles sold out at 20 copiesUnlimited-supply flag on a zone (refill from nothing)smallopen — minor
A7Honor printed on owned cards uncounted= G12 (score-from-cards)with G12shipped (with G12)
A8Deliberate typo'd effect key was correctly flagged— positive control: validation worksconfirmed

4–6 · The pending games

GameWhat probing it would test that nothing else hasForecast
7 Wonders Duel (proposed as probe #4) The pyramid (positional availability — taking a card uncovers others), resource production vs pools, opponent-dependent trading costs, science set-collection win, three coexisting win conditions ~Half maps (military track = shared tug tracker ✓, multi-endings ✓, age decks ✓); half fails newly: tableau tier, computed costs, set-membership counting. Best next probe precisely because it is not a deck-builder.
Clank! Deck-building fused with board movement Declared out of reach: spatial movement has no home in the model (the structured-tableau/board tier). Probe only if we want to write the spec for that tier.
Slay the Spire Solo mode, scripted enemy AI (intents), block-vs-attack, energy Energy/block are pure tracker work ✓; needs solo mode + scripted opponents (a bot that follows a card script — new but bounded) + card-targeted damage (P1). A plausible probe after P1 lands.

The decision matrix — one row per buildable feature

Deduplicated across all probes, ordered by how many games each unlocks. My recommendation is marked; the Decision column is yours.

FeatureFindings it closesGames it unlocksEffortRecommendationDecision
Turn-limit fallback uses score trackerA5Ascension (real winners today)minutesdo immediately
Score-from-cards (resolution.metric + sum_cards)G12, G4, A7Dominion + Ascension produce true results~1 dayshipped
Defeat/acquire transaction + trigger vocabulary + warn-on-unknown-triggerA1, A2, S3 (partly)Ascension correct; Star Realms scrapping~1 dayafter G12
Shared-tracker effects (pools)A3Ascension's real ending; 7WD military track later~½ daywith A1 batch
Binding parameters: play costs, phase type filters, use limitsG9, G10, G11Dominion faithful; groundwork for the Rules step UI (P7)~1 daywhen Rules step starts
Opponent-targeted effectsG2Dominion attacks (Militia, Witch)~½ daymedium
Families finished (UI + AI + effects)S1Real Star Realms ally system~1 daymedium
count_zones_where + ending timingG13, A4Dominion's real end trigger; Ascension round-end~1 daymedium
Activated abilities (Q1 wiring)S2Star Realms bases; tap-style designs~2 dayslater
Unlimited-supply zonesA6Ascension polishsmalllater
Tableau/positional tier7WD pyramid, Clank!Whole genres beyond card rowsbigonly after a probe writes its spec
Resolution stack (reactions/interrupts)G3Dominion Moat; TCG-style playvery bigstays ceiling

Verification probe — Dominion, kingdom 2 2026-08-05 · all green

Per the method note (verification probes verify fixes, they don't discover): dominion-verification.json swaps Woodcutter → Guild Broker ("this turn, every card you buy pays back 1 coin" — a point-6 pattern trigger) and Moat → Sacrifice ("trash 2 cards of your choice" — points 2+3 composed: chosen discard redirected to the trash). First game ever to import with a clean card validation (zero problems).

VerifiedEvidence
Point 6 through the full pipelineimport detects the pattern (hasPatternTriggers); micro-proof: with Broker in play, a 3-cost buy nets −2 coins (paid 3, rebated 1)
Points 2+3 in a real game184 Sacrifice plays across 10 seeds → 318 logged decisions, 348 cards in the trash; greedy trashes its deadest cards (deck thinning emerges)
Point 7 + G12 stack20 greedy games: 13–7 real winners, no draws among the 14 Province-depletion endings
Point 1 at 3 players3p × 10 seeds: 4/5/1 wins, expression piles at 12/20, games complete
Bot-quality signal intactrandom bot: 20/20 hit the turn limit with expensive piles dead — the known "decisions don't matter for random" detector, now with scored results via A5

Still deliberately inexpressible (recorded, untouched by this probe): gain-from-supply (Witch/Workshop — A1), reactions (Moat — G3, waits for points 4+3), "any 3 piles empty" (G13), static modifiers (Merchant — point 5).

Probe: Jaipur 2026-08-06 · the first non-deck-builder

Goal-built to force user-definable actions: no deck-building, shared draw deck, tokens-as-cards with descending values, one action per turn. The entire turn structure is action_definitions — three preset instances + one composer action (sell, needing three bonus tiers). Endings: G13 (count_zones_where three-piles-empty) + deck exhausted; scoring: G12 over won tokens.

ResultEvidence
It plays40 games both bots: ~0 draws among proper endings, e.g. 43–64 on token points; all four actions used (26 takes / 21 sells / 19 trades / 8 sweeps, 85 decisions in one game); bonus tiers firing
Engine additions forcedshared-deck opening deal (draw_n_cards from a shared zone); greedy learning to pick custom actions (it passed forever — a bot gap, found in minutes)

Approximations, recorded in the def (_approximations): market opens unseeded (fills to 5 turn 1); precious goods may sell single; trade gives from hand only (no camels); no hand limit, no herd bonus, single round. None move the six metrics materially; all expressible later (min-count filters per action binding, herd bonus as an ending-metric term).