Milestone 30 is a measurement milestone. The roadmap asked for one thing: profile the simulation against larger battles and larger maps, and only then decide whether Project Nightfall needs to move toward jobs, Burst, or DOTS. No gameplay code changed — the deliverable is a numbers document and a decision, not a feature.
Measuring without disturbing what you’re measuring
The profiling harness lives entirely in the test tier. It drives the same twelve simulation phases the match tick drives, in the same order, timing each one individually — so cost is attributable per system instead of arriving as a single blended number.
Pathfinding needed separate treatment. A* isn’t a tick phase: it’s called synchronously from several phases and from order issuance, outside the tick entirely. Timed per phase, it would simply be billed to whichever system happened to trigger it. A counting decorator around the navigation service captures all of it instead.
Four guards keep the harness honest: that its phase list matches the real one, that the phases account for the whole tick, that harness-driven ticks produce bit-identical durable state, and a self-test for the comparison doing that check. The one known gap — a private per-tick list the harness cannot reach — is disclosed rather than glossed over. The suite is gated by category, so the default test run stays around two seconds.
What the numbers said
Tick cost is superlinear, and increasingly so: per-doubling growth climbs from 1.62× to 2.96× across 24 to 400 units. One confirmed algorithmic cause was found — combat target acquisition scans every unit in the match, per attacker, per tick, making that phase quadratic. Separately, the A* open set is a linear scan, costing roughly 90 ms for a single 100-unit move order; that one is invisible to per-phase timing, and it is the finding that degrades the game as it exists today.
Movement’s similar growth turned out to be crowding in the test fixture rather than complexity, and is explicitly not filed as a bottleneck. Projectiles were measured and ruled out — below noise at 110 concurrent. Authored vision range proved the most performance-sensitive content parameter measured, scaling at roughly the square of the radius.
The decision, and a note on being wrong first
The recommendation is not to adopt DOTS or Burst. The superlinearity is a wrong-algorithm problem, not a parallelism limit — Burst would only deliver a faster quadratic scan. Absolute cost remains tractable at 22 ms median at 400 units, four times any current scene’s scale, so the follow-up work is ordinary: a priority queue for pathfinding, the spatial index this codebase already owns for target acquisition, and some redundant per-tick bookkeeping to delete.
Three separate fixture artifacts produced confident but wrong conclusions before these numbers: a default vision range covering the entire map, geometry where large armies never actually engaged, and a cluster spawning half off-grid. Each would have justified a firm, incorrect recommendation. The suite now asserts its own scenarios are valid — damage was dealt, projectiles existed, orders were accepted — so that class of error fails loudly instead of producing plausible fiction.