# Seeded policy samples

By Luke Steuber. Measured 2026-10-08 with `node ballista/sim-sides.js --seeds 200 --json`. Each row runs **200 complete games**, seeds **1000–1199** (3,200 games total). Both sides' rates are reported for each matchup. Attacker wins at three or more hits; defender wins with fewer than three. There are no draws. These are policy outcomes, not a human win-rate estimate; no parameters were adjusted to target a rate.

## Defender against the computer attacker

The computer fires the scenario's fixed rock/decoy manifests at every public astronomical window. The defender starts after the first launch flash. `balanced` shares telescope time among the nearest volley's ambiguous tracks, budgets interceptors across lanes and begins early enough for the pad limit; `greedy` studies the most ambiguous tracks globally and waits until the deadline's step; `early` commits to every track as soon as possible; `never` spends nothing. Exact implementations remain in `bots.js`.

| Scenario | Defender policy | Defender wins | Attacker wins | Mean hits | Mean interceptors spent | Mean spent on decoys |
| --- | --- | ---: | ---: | ---: | ---: | ---: |
| skirmish | balanced | 14.5% (29/200) | 85.5% (171/200) | 3.695 | 10.565 | 4.260 |
| skirmish | greedy | 0.0% (0/200) | 100.0% (200/200) | 5.785 | 5.980 | 1.765 |
| skirmish | early | 0.0% (0/200) | 100.0% (200/200) | 6.610 | 14.000 | 10.610 |
| skirmish | never | 0.0% (0/200) | 100.0% (200/200) | 10.000 | 0.000 | 0.000 |
| campaign | balanced | 46.0% (92/200) | 54.0% (108/200) | 2.550 | 13.960 | 4.510 |
| campaign | greedy | 3.5% (7/200) | 96.5% (193/200) | 4.080 | 9.860 | 1.940 |
| campaign | early | 0.0% (0/200) | 100.0% (200/200) | 6.000 | 18.000 | 12.000 |
| campaign | never | 0.0% (0/200) | 100.0% (200/200) | 12.000 | 0.000 | 0.000 |

## Attacker against the computer defender

All rows use `balanced` defence with the normal stock and two pads per five-day cycle. Manual attacker games start ten days before the first lane, so the pad-cycle phase and the information opportunities differ from the standard defender scenario above. Each plan reserves its stock before play; unused stock remains unused. Every choice obeys the same platform and window constraints as the player.

- `rocks`: scenario rock count on each lane at window open; zero decoys.
- `mixed`: scenario rock/decoy manifest on each lane at window open, clipped to remaining stock and the 24-object platform capacity.
- `held`: the same manifest as mixed, held 30 days, clipped at the lane's closing time.
- `screened`: process lanes having any solar-glare interval first, departure time breaking ties. Allocate up to six rocks on those lanes, otherwise the scenario rock count; decoys use the scenario count clipped to remaining stock/capacity. Release at the first glare time if it lies inside the launch window; otherwise at window open. This explicitly includes intervals outside the release window when prioritizing stock. Exact planning code is `plan()` in `sim-sides.js`.

| Scenario | Attacker policy | Attacker wins | Defender wins | Mean hits | Mean defender spending | Mean spent on decoys |
| --- | --- | ---: | ---: | ---: | ---: | ---: |
| skirmish | rocks | 9.5% (19/200) | 90.5% (181/200) | 1.220 | 8.780 | 0.000 |
| skirmish | mixed | 90.0% (180/200) | 10.0% (20/200) | 3.905 | 10.505 | 4.410 |
| skirmish | held | 95.0% (190/200) | 5.0% (10/200) | 4.115 | 10.665 | 4.780 |
| skirmish | screened | 100.0% (200/200) | 0.0% (0/200) | 4.820 | 6.615 | 1.435 |
| campaign | rocks | 6.5% (13/200) | 93.5% (187/200) | 1.055 | 10.945 | 0.000 |
| campaign | mixed | 63.0% (126/200) | 37.0% (74/200) | 2.805 | 13.910 | 4.715 |
| campaign | held | 68.5% (137/200) | 31.5% (63/200) | 3.015 | 13.950 | 4.965 |
| campaign | screened | 100.0% (200/200) | 0.0% (0/200) | 6.760 | 6.140 | 0.900 |

Sun-screened attacks won every sampled game against balanced defence. A release concealed past the commit deadline cannot be intercepted by that defence. This is a material strategy advantage, not evidence of a balanced human contest. It has been retained and disclosed; neither the measured rates nor the game's objective was tuned after sampling.

## Exact sources and limits

The separate simulator fixture remains `test-reference.json`, from `lukeslp/solar-war` c4fc949, `src/solarwar/scenario/ballista.py`, seed 20260809. `test-engine.js` still verifies exactly 52 diverted rocks, 14 hits and 18 balloon interceptions across both reference directions. The platform holding, per-cycle pad limits, telescope pointing and three-hit win objective are declared game extensions; they do not replace that reference.

Sampled source SHA-256:

- `engine.js`: `21872b3d110556a32cccb7b740db25433e1286bd4388a94f354072cd73d3d829`
- `bots.js`: `65930102ee349cda02daf6c967ce237af6e10b6116e1f22aef65d739c3917aa7`
- `sim-sides.js`: `18e20165d8917a61a4da709e46c41201de453c119fc8d900dd976df33b41641c`

The JSON report and browser/measurement artifacts are external evidence, separate from game source. The final source commit and artifact paths are recorded in the implementation handoff. Headless checks do not establish physical phone, VoiceOver or published behavior.
