09-roadmap.md · non-normative

09 — Implementation Roadmap

This document sequences the work described by the specification set into buildable phases with explicit exit criteria. It is the only document in the set that is not a specification of the product: it makes no normative claims about behaviour, carries no requirement IDs of its own, and where it conflicts with any other specification, that document wins. Its purpose is to answer "what gets built first, and how do we know a phase is done?"

Status: Draft v0.2 · Owner: unassigned · Depends on: docs/design/00-direction.md, docs/design/01-decision-turn-model.md, and the specification set — 00-overview.md, 01-game-rules.md, 02-units-and-industry.md, 03-architecture.md, 04-ui-ux.md, 05-multiplayer.md, 06-ai.md, 07-modding-content.md, 08-services-platform.md, 10-turn-model.md, 11-combat.md, 12-economy.md, 13-command.md, 14-victory.md

What changed in v0.2. The v0.1 plan was sequenced around reproducing another game: a golden-master corpus as the first deliverable, reference data as a Phase 0 gate, four inherited unit sets spread across three phases, and a definition of "done" that ended with a veteran being unable to name a rule that behaved differently. That premise is withdrawn (docs/design/00-direction.md). The plan is now sequenced around a different and harder problem: the design is original, seven rules documents deep, and has never been played. Verification against an oracle is replaced by verification against the specification plus playtesting, which now gets a phase of its own. The AI is promoted from a late add-on to the product pillar the owner asked for. Phase numbers after 2 have shifted; §2.9 maps the old numbers to the new ones.

1. Sequencing principles

  1. Determinism is a Phase 0 gate, and it is closed. The fixed-point representation, the determinism harness, the lint rules and the cross-platform CI job all existed before the first line of rules code. This is done (§2.1), and it is listed first because it is the only principle that could not have been applied later.
  2. Get to a played game as early as the design allows. There is no external oracle any more. Every constant in the rules documents is a first guess, argued in prose and never tested against a person. The plan is therefore optimised for time to first played game, not for time to feature-complete: Phase 1 builds the smallest rules surface that is genuinely a game, which the design conveniently already identifies — Industry tier 1, described in 02-units-and-industry.md §8.1 as "the complete simple game."
  3. The turn machine is built first and never stubbed. Orders, the Cascade and the Reckoning (10-turn-model.md TM-020) are the spine every other system keys off. Initiative order, activation semantics and "resolve against the world as it is at that instant" cannot be approximated in Phase 1 and corrected in Phase 2, because every rule in every other document is written against them.
  4. The order vocabulary is rules code, not a convenience layer. 13-command.md is core: its Postures and Sanctions reach the simulation through the order log (CM-2040) and changing one is a versioned rules change that breaks stored replays (CM-2060, CM-2070). It ships in Phase 1 with the turn machine. Deferring it is the single most expensive mistake available in this plan; see the first row of §4.
  5. The core is never bypassed. No phase adds a shortcut where UI, netcode, or AI mutates state directly. If a phase needs behaviour the core lacks, the core gets it.
  6. Every phase ships something playable. Each phase ends with a build a person can play, even if that build is a CLI in Phase 1.
  7. Content is data from day one. The shipped roster is authored in the shipping JSON format (02-units-and-industry.md US-700, US-1340) and loaded through the same content path a custom set will use, in Phase 1, not hardcoded and migrated later.
  8. Verification is the safety net, not review. The implementation is largely AI-authored. With no original to check against, the anchors are the requirement IDs themselves: every requirement maps to at least one named test, plus property tests (03-architecture.md AR-950), the cross-platform replay job (AR-960), and the worked test vectors the rules documents already nominate (14-victory.md VC-3310 is the model — a document naming its own reproducible computations).
  9. Instrument before tuning. Each rules document nominates the metrics that would show it was wrong (10-turn-model.md TM-1440, 02-units-and-industry.md §14, 14-victory.md VC-3300). Those emitters are built with the systems they measure, not retrofitted when balance becomes urgent.
  10. The AI is a pillar, not a phase-three afterthought. The owner has named advanced AI opponents as the headline advancement. Most play of a game of this shape is one person against AI seats, so a client with no credible opponent is not a playable build in the way that matters. A baseline opponent therefore lands in Phase 2, and the AI proper gets a full phase of its own ahead of multiplayer.
  11. One client, six platforms. The browser build is the primary delivery target; the desktop and mobile apps are the same web client packaged, not a second implementation.

2. Phase plan

2.1 Phase 0 — Foundations · complete

Done, and verifiable in the repository.

Done since this section was written.

Void, and named so a reader of v0.1 can see they were dropped rather than forgotten.

Exit: rights path chosen; the browser leg green in the determinism matrix; no document in docs/spec/ claiming to reproduce, match, or be faithful to another game, and no (EDCE p. N) citation anywhere in the set.

Status: complete (2026-09-03). The rights decision — the one item left open, and the owner's rather than an engineer's — was taken offline by the owner on 2026-09-03. The browser leg is green across Chromium, Firefox and WebKit; the documentation sweep is complete and verified mechanically — pnpm check-spec passes across the set, and the only occurrences of the forbidden citation pattern anywhere in docs/spec/ are in this document, quoting the rule that forbids it. The completed items are not re-gated.

2.2 Phase 1 — The turn machine, the core, and the first played game

Build @everylastcity/core up to the smallest rules surface that is a game, and get a person to play it. The order below is a build order, not a list.

Milestone P0 — first game played by a human, in the CLI, hot seat, tier 1. This is the earliest point at which anything in the design can be falsified, and it sits deliberately inside Phase 1 rather than at its end. From P0 onward, playtesting is a continuous track (§2.4), not a later stage.

Exit: a full tier-1 game is playable end-to-end in the CLI and has been played to a decided finish by people who did not write it; identical replay hashes across the AR-960 platform matrix, browser included; every requirement ID maps to a named test and the gaps are listed rather than absorbed; the stance-fallback rate is emitted per game; the measured V8 numbers are recorded against the (restated) AR-760 budgets with any shortfall named.

Ruling, 2026-09-06: "by people who did not write it" moves to Phase 2. P0 keeps the part the CLI can actually prove.

The clause was written when "playable end-to-end in the CLI" was assumed to describe something a person could sit down to. Built, it does not. The hot seat asks the player to type JSON order objects — a March Posture is some 180 characters of nested braces — naming units by id and destinations as flat tile indices, against a character-grid map. That form can establish that the rules run, that a game reaches a decided finish, and that the quantities move as the documents say. It cannot establish whether the turns are interesting, whether the decisions read as decisions, or whether committing before seeing is thrilling or merely frustrating, because everything it would measure is swamped by the cost of the interface.

Phase 2's exit (§2.3) already asks the real question in the only form that can answer it: a person who has never seen the design plays a tier-1 game to a finish without reading anything and can say what they were deciding. Asking a weaker version of that question here spends an outside reader's first session on the interface rather than on the game, and a first session is not repeatable — US-2220's two failures and VC-3300's M13 are exactly the things a spent first session can no longer be used to find.

P0's exit therefore reads: a full tier-1 game is playable end-to-end in the CLI and has been played to a decided finish, with the container kept and every finding recorded as a defect or a design question rather than absorbed — the authors may play it. The rest of the clause is unchanged, and the independent reading is Phase 2's to gate, where it already is.

What this gives up, named rather than absorbed. Until Phase 2's exit, nobody outside the two authors will have exercised these rules. The exposure is a shared authorial assumption that no author can see, and no amount of machine coverage finds it: the 33-game determinism corpus and the requirement ratchet both prove the engine agrees with itself, never that the game is worth playing. Two things bound it. First, this milestone is not the last gate before players — Phase 2 cannot close on the same evidence, and its exit clause is the one that must not be softened. Second, author play is not nothing when it is recorded: the first CLI game played through on 2026-09-06 produced two crashes, a Reflex loop that makes the natural movement order useless against its own standing order, terrain a quarter of the map wide that no land unit may enter, and a capture-then-attrition-then-revolt arc that returns a hard-won city to neutral for no net gain. None of those needed a stranger. What needs a stranger is the question of whether any of it is enjoyable, and that question is now asked once, in Phase 2, on a screen.

Consequence for §2.4: Phase 3's "human playtest, closed then widening" is unchanged and remains the tuning instrument. This ruling moves the first independent session from P0 to Phase 2; it does not move Phase 3.

Status: in progress (2026-09-04). First increment landed: the turn machine in @everylastcity/core — the explicit phase value, createGame and applyOrder as the whole mutation surface (AR-030), the Initiative score and the frozen activation order it sorts, Stance and the committed-Stance determination, the Cascade with its tile-entry and reaction procedures and skip tests, the Reckoning's fixed step order and clocks, and the state and turn hashes — with 10-turn-model.md's §20 worked example held as a normative test vector. The command, world, combat, economy, and victory increments land in place through the seams this increment defines (the CascadeRules and ReckoningRules interfaces); the public API does not change when they do.

Second increment landed (2026-09-04): the world's static surface — the map and coordinate system (GR-100–GR-240), the eleven base terrains and terrain-set validation (GR-260–GR-370), installations and river crossings (GR-400–GR-500), movement cost and legality with zones of control (GR-550–GR-700), occupancy and stacking (GR-710–GR-810), the closed eighteen-flag capability vocabulary (US-470), the deterministic pathfinder (AR-750), and the city slices — the capture procedure (GR-920–GR-990) and the Ports (GR-890–GR-910), wired into the Cascade at the moment of entry (TM-1510). Setup/map generation lands in the following slice; createGame carries world: null until the map-generation slice does.

Third increment landed (2026-09-04): vision, line of sight, and fog — the observer set and the effective vision radii (GR-1000, GR-860), the sight ray with its candidate tiles, strict block test and symmetry (GR-1010–GR-1030), the City's block/view adjustment (GR-870), the air exception (GR-1070) and the layer rules (GR-1080, GR-1090), the three tile states and the Terrain Record (GR-1120–GR-1170) with the no-leakage discipline (GR-1180), and the production knowledge view (CM-130): the virtual world the true-world step model runs against (CM-140). The per-player records ride GameState.fog (hashed) and refresh at every activation (GR-1100) through the afterActivation seam.

Fourth increment landed (2026-09-04): the Intelligence Picture — the Contact Register (GR-1200–GR-1250), the fidelity ladder (GR-1260–GR-1290), decay (GR-1300–GR-1320, GR-1680 via the afterReckoning seam), position uncertainty (GR-1330–GR-1360), and the predictor interface (GR-1370, GR-1380). The registers ride GameState.contacts (hashed); the setup slice wires the per-activation refresh and the once-per-turn decay.

Fifth increment landed (2026-09-04): perceptible events — the loud half of the Intelligence Picture (GR-1390–GR-1450): a combat, a bombardment, or a spent expendable creates a Trace at the named tile for every player who hears it (the observer's own effective radius plus 4 or 6, line of sight ignored; the expendable, every player map-wide), evaluated at the instant it resolves in the Cascade (GR-1450). The event is a set-not-raise refresh of the register: a higher-fidelity Contact at the same tile is untouched, at another tile it is downgraded to the Trace there, and the event reveals nothing (GR-1410) — a City's recorded owner is kept (GR-1290). The City ownership announcement (GR-1430) updates only the recorded owner for explored fogs, and the owner's own loss (GR-1440) raises the UnitLost and CityTaken Attention Events with the tile. Pure functions over state that already exists; the setup slice wires the call sites.

Performance re-baseline (2026-09-05): the budgets are missed by three orders of magnitude, and the cause is a single requirement not implemented. Run with pnpm bench; the fixture is the simulation-only half of AR-760 on the surface that exists, since the normative one needs the roster, Industry tiers and PlayerView, none of which are built.

This finding was acted on and is closed — see "Re-baseline resolved (2026-09-07)" below. The measurements and the present-tense diagnosis in the rest of this subsection are the 2026-09-05 record of what was found, kept because the reasoning is what located the seam. They are no longer a description of the engine.

Units Turn Per activation vs AR-760 (100 µs) Fog share Fog per activation vs AR-740 (40 µs)
25 0.09 s 3,488 µs 35× 77 % 2,675 µs 67×
100 0.61 s 6,108 µs 61× 70 % 4,278 µs 107×
250 5.08 s 20,314 µs 203× 93 % 18,796 µs 470×
500 23.58 s 47,155 µs 472× 95 % 44,872 µs 1,122×

The cost is quadratic in unit count and the probe stops at 500 — AR-760's fixture calls for 10,000. Extrapolating the observed curve, one turn at that size is measured in hours.

Isolating it takes one line: stub the afterActivation seam and 70–95 % of the turn disappears. turn/world-rules.ts answers that seam by recomputing, for every player, a from-scratch observation set and a full fog and Contact-register refresh — after every activation. AR-740 requires the opposite in terms: "fog updates MUST be incremental: a unit move recomputes visibility only in affected radii (dirty-region tracking per chunk), so the cost is a function of the sight footprint, not of map size or player count."

The individual operation is not slow; it is being called in the wrong place. AR-740 budgets a from-scratch recompute of one player's whole fog at ≤ 50 ms, and the measured cost is about 6 ms per player — comfortably inside that. The defect is that the ≤ 50 ms operation runs where the ≤ 40 µs one belongs, once per player per activation. Nothing about the state layout needs to change to fix it, which is the good news in these numbers: AR-740's dirty-region tracking is an addition to the world module rather than a re-shaping of GameState, so the roadmap's fear — that a late re-baseline would force a state-layout change — does not materialise.

Recorded rather than fixed: world-rules.ts was in another session's working tree when this was measured. The roadmap asks for this re-baseline "early enough that the answer can still change the state layout", and running it now is what makes that answer cheap — every increment landing on top of a fog refresh this expensive is one more caller to re-time later.

Re-baseline resolved (2026-09-07): the fog is incremental, the cost is no longer quadratic, and the overrun is now a roughly constant factor. AR-740's dirty-region tracking landed in f55f1a2 and 9febc86 — the observation set, the fog and the Contact register are maintained as a function of what changed, with the tracker kept out of the canonical hash (AR-620) so determinism is untouched. The prediction above held exactly: it was an addition to the world module, and GameState's layout did not move.

Same-host comparison, the P0 host, against the 2026-09-06 re-run recorded in the status paragraph below:

Units Before (2026-09-06) After (2026-09-07) Change
25 14,800 µs 9,558 µs 1.5×
100 35,100 µs 11,489 µs 3.1×
250 82,200 µs 9,524 µs 8.6×
500 did not complete 17,335 µs —
1000 did not complete 40,746 µs —

Independently re-run on the Windows development host, which is a different machine and so is not comparable to the figures above in absolute terms — it is here because the shape is the result, and the shape reproduces:

Units Map Per activation vs AR-760 (100 µs) Fog share Fog per activation vs AR-740 (40 µs)
25 Small 2,302 µs 23× 58 % 1,338 µs 33×
100 Small 2,347 µs 23× 27 % 623 µs 16×
250 Standard 1,971 µs 20× 26 % 503 µs 13×
500 Standard 3,149 µs 31× 30 % 949 µs 24×
1000 Large 7,221 µs 72× 34 % 2,484 µs 62×

Three things changed, and only the third is a number:

Still open, named rather than absorbed: the normative AR-760 fixture needs the roster, Industry tiers and PlayerView, so every figure here remains the simulation-only half; and no run yet reaches the fixture's 10,000 units. The next re-baseline should be run once PlayerView exists, against the normative fixture, and should not reuse this subsection's diagnosis.

Cascade profile (2026-09-07): the fog is one of two halves, and the other half is per-activation Cascade machinery. The prediction above — that the next profiling pass "will find a different bottleneck" — held. Method: on the bench's fixture at 500 units / Standard (P0 host, warm steady state), the afterActivation seam and the Reckoning's heavy steps are stubbed in a 2×2, and the differences isolate each phase. Stubbed runs diverge in trajectory (no fog, so the knowledge views are empty; no Reckoning, so nothing produces or attrites), so the split is an approximation — the ordering, though, is stable round to round:

Phase (500u, warm, median of 4 rounds) µs/activation Share
Full turn 17,800 100 %
Cascade + Reckoning, fog stubbed 9,900 56 %
Cascade + fog, Reckoning stubbed 18,400 ≈100 %
Pure Cascade 9,300 52 %

The overrun at 500 units is now ~178× AR-760's 100 µs, warm and simulation-only — a constant factor with named targets: GC pressure in the hot paths, the per-activation interruption scan, and the per-activation knowledge view. The normative 10,000-unit fixture still cannot be built (AR-500's PlayerView, the roster and Industry are absent), so this profile closes the simulation-only question and defers the rest to the re-baseline the "Still open" note above asks for.

Exit instrumentation (2026-09-04). The exit clause above asks that every requirement ID map to a named test and that the gaps be listed rather than absorbed. pnpm check-req-coverage now measures it: 273 of 2,793 (9.8%) — 01-game-rules.md 56%, 10-turn-model.md 33%, 13-command.md 24%, and 0% for the documents whose increments have not started. It is a ratchet, not a threshold: it fails when a requirement that was covered stops being covered, and lists the rest. A gate demanding 100% at this stage is one nobody passes and everybody disables, and the number is only a floor on traceability — a cited requirement can still be tested badly, which is what the risk register's "spend scarce human review on spec-to-test correspondence" is for.

Where the testing actually stops (2026-09-05). pnpm check-req-coverage answers "how much of the roadmap has been reached", which at this stage is mostly a progress figure: Victory reads 0 % because Victory does not exist. pnpm coverage-gaps asks the narrower question this clause is really about — within each section of each document, is the testing partial?

Sections Requirements
Fully covered 17 206
Partially covered 72 546 untested
No coverage — unbuilt, expected 133 1,538

The middle row is the risk surface, and it is the one neither number showed before. A section nobody has started reads as unbuilt and is honest about it. A section tested in part reads as done and is not: somebody built the area, tested some of it, and moved on, and the untested remainder is code whose neighbours are covered — which is exactly where §4's register says the dominant failure mode hides, "a plausible-looking rule that is subtly wrong" in work that "more code is produced than anyone will read closely".

The register is a tool rather than a committed list, so it cannot go stale; --ids <PREFIX> names the requirements in any partial section. The first two entries it was read against were §9 The Cascade, the most-exercised code in the engine, at 7/23, and §8 Initiative at 41 %. Spot-checking the Cascade's gaps found TM-1280 among them — "nothing that happened after activation i MAY influence activation i" — a causality property the whole determinism guarantee rests on, which no test named. §9 now reads 23/23, §10 Order evaluation 17/17, §11 Reactions 23/23, §4 The Orders phase 15/15, §6 Stance 18/18, §13 The Reckoning 12/12, §8 Initiative 26/27 and §19 Contracts 6/12 and §16 Determinism hazards 8/12. With §1, §2, §3, §7 and §12 closed as well, every requirement in the turn model is now either tested or carries a written reason why not.

What reading the register against those sections actually produced. §9 found no defect: the Cascade held all fourteen of its untested requirements. §8 found three, §10 one open call, §11 a requirement with nothing behind it, §4 another plus a side channel, §6 a normative table written down twice, §13 a revolt nobody is told about, §19 a contract that is broken rather than untested, §16 a replay the repo could not yet perform, and §12 a clock that credited a unit with a turn it had not spent — none of which a passing test suite would ever have surfaced, because in each case the code was self-consistent and merely did not do what the document says.

TM-1010 is the one §8 requirement still uncovered, and deliberately so: its substance is the condition under which the In-command term applies — Posture Attach, within the Formation's cohesion radius of its Command Reference Point — which is 13-command.md §7's derivation, and Formations are not built. inCommand is written false at creation and nothing ever writes it again. The turn model's own half of it, that the flag contributes +4 at Tier 3 and 0 below, is covered.

§10 produced one open call and one confirmation of a ruling already made.

§11 found one requirement with no implementation behind it at all.

§4 found one requirement with nothing behind it and one side channel nobody had looked for.

TM-460 is worth a note in the other direction, because it is the one place this pass found the code ahead of the reading. Hotseat and concurrent play must produce identical hashes, which looks false at first sight: the order log keeps arrival order, and the two schedules interleave differently. turnRecordToCanonical regroups the orders by player and renumbers within each player's own stream before anything is hashed, so the interleaving — an artefact of who typed when — is erased by construction. The test asserts the two arrival sequences genuinely differ before asserting the hashes match, because without that guard it would be comparing a run against itself.

§6 found the normative Stance table written down twice. reactionCapacityFor in stance.ts carried the reaction-capacity column of TM-640, was exported — and was never called. The Cascade kept its own private copy of the same switch. The two agreed, so nothing was broken today; what was broken was the arrangement, because a table with two homes has two places to change and only one of them is reachable from the public surface. That is the argument TM-700 already makes about the entrenchment counter in as many words — "MUST NOT define a second counter, a second name, a second range, or a second increment or reset condition" — and it applies to the capacity column for the same reason. The private copy is gone and the freeze reads the exported table. The hash is unchanged, because the two produced identical values.

The rest of §6 held, including the part worth holding. The split between the committed Stance, bought during Orders at a stated price, and the effective Stance, which a Reflex may force mid-Cascade, exists to close two specific holes that §6's rationale names: a March column that takes cover must not acquire an overwatch shot it never paid for, and a Hold unit driven off its tile by a Withdraw must not lose the reaction it already did. Both are now tested as behaviour rather than inferred from the fields — a mutation that recomputes capacity from the effective Stance after each activation fails both, and nothing else in the suite notices it.

§13 held everything this document owns, and found a defect in the seam where it meets another. Steps 5, 6 and 9 move nothing, solicit nothing, log nothing, and run in a fixed explicit order. What the section could not check about itself is what its seams do — and one of them does two things TM-1970 forbids by name.

Both sit in the economy increment another session owns and had just landed when this was found, so they are recorded rather than applied. AGENTS.md carries the pointer.

Resolution (2026-09-07, implemented, 7627623). The owner ruled as recommended: the city-owner change stays in the Reckoning — it is the bookkeeping the announcement half makes player-visible — and the displacement is deferred. UnitState carries two hashed marker fields, displacementPending and displacementTo (null = destroy at consumption); the revolt sets them during the Reckoning and the next Cascade consumes them at its start, before any activation, under the CM-380 displacement cause, so the displaced marker and the ReturnToPost Reflex behave exactly as for any external effect. A unit destroyed in the same Reckoning voids its mark, and a game that ends in the marking Reckoning never consumes it. The two hashed fields move every state hash, so the re-emission was full: all 33 corpus games (the three revolt games' trajectories additionally diverge from their revolt turn; every hazard event timing the corpus README documents was re-verified unmoved), both artifacts re-emitted with byte-identical entry bytes and logs (no city changed hands in either), the two CLI goldens, and the container pins in cli/test/binary.test.ts.

§19 is the section where "not testable yet" is the answer for half of it, and saying which half is the useful output. A contract on another document is checkable only where the other side exists. Six of its eleven open requirements have a built counterparty and are now covered — what 01-game-rules.md owes the Cascade, what 11-combat.md owes initiative and the entrenchment counter, and the three that draw the boundary with 13-command.md and 14-victory.md. The other six are not covered, for reasons that differ and matter:

Counterparty Why it is not covered
02-units-and-industry.md No class table exists in the core: no commitment bands, no per-class Stance restrictions, nothing to check the contract against. The two ranges this document polices on its behalf are covered where it enforces them.
12-economy.md The contract is broken, not untested — the revolt moves units and changes tile ownership inside the Reckoning, which the contract forbids in as many words. Citing it would book a known violation as satisfied.
03-architecture.md Four of its five clauses are provided; incremental visibility with a proof of equivalence is not, which is the same gap the performance re-baseline found.
05-multiplayer.md, 06-ai.md No implementation at all.
04-ui-ux.md No implementation. Every datum it must present is queryable from the core today and each query is tested where this document requires it — but supplying a number is not presenting it.

The distinction in the second row is the one worth keeping. A register that cannot tell "nobody has tested this" from "this is known to be false" will read the same in both cases, and the second is the one that needs a person.

The citation-in-passing failure has now happened three times, and it is time to state it as a rule rather than a caution. Each time it was a docstring or a comment explaining why something was not covered, and each time naming the identifier booked it as covered — CM-960 in the §8 suite, the In-command requirement in the same file, and three more here, including the very requirement whose paragraph said it was out of scope. The scanner reads every identifier a test file contains and cannot tell an explanation from a claim, and no amount of care at review time catches it, because the prose reads as scrupulous either way. The rule: a requirement identifier appears in a test file only where an assertion reaches it. Everything else — the reasons, the exclusions, the open calls — is named by document and section here, where no scanner is watching.

§16 needed something the repo did not have: a replay that starts from the record. The existing replay test says so about itself — it drives two games through the same calls and compares them, which proves the engine is deterministic but cannot prove the record is sufficient, because both runs had the caller feeding them. The two claims are different, and only the second is what a save file, a desync investigation or a spectator stream rests on.

A replay driver now exists in the test suite: it starts from the setup, the seed and the recorded turn records, re-runs the game through the public entry point, and compares. It found nothing — the log is sufficient today, which is the answer one wants and could not previously assert. It is worth saying what that test would have caught: a mutation adding a module-level counter to the Cascade, or dropping a single order kind from the record, diverges the hash immediately, and neither is visible to a reproduction test.

The driver lives in the tests because the production entry point is the save-format increment's, and that increment owes one more thing than it did before:

The three other uncovered requirements are 05-multiplayer.md's activation-order hash exchange, 06-ai.md's prohibition on invoking AI code during a replay — there is no AI to prohibit — and the obligation to bump RulesVersion when a rule changes, which is a process the reference-hash gate enforces at the moment of the change rather than a behaviour a test can observe.

The turn model is finished, in the sense that matters: every requirement in it is either tested or has a written reason why not. §1, §2, §3, §7 and §12 join the seven sections already complete, and what remains across the whole document is fifteen requirements in four groups, each recorded above — the host-side deadline and reserve configuration (§5), the In-command condition that waits on Formations (§8), the four in §16 that belong to multiplayer, to AI, to process, or to a replay entry point that does not exist, and the six in §19 whose counterparties are unbuilt or, in one case, whose contract is broken rather than untested.

§2's clauses are prohibitions on how the engine may reach an answer, not on the answer, and the only way to test one is to build the same situation two ways and show it does not move. Four variations carry that section: the seed (a Cascade that consulted the PRNG outside combat would answer differently under a different one), the order the host listed the starting units in, the route by which a committed state was reached, and what the unit behind the acting one has been told to do — which is the clause §2's own rationale calls the easy one to get wrong.

§12 found a defect in a clock. reckonUnitClocks guards age against being credited to a unit created in the same Reckoning — that is what TM-1940 is for — but did not guard the on-tile count. A unit placed by step 4 has not changed tile, so step 5 immediately credited it with a full turn on ground it had occupied for none. The consequence runs through three requirements: 13-command.md's CM-390 derives Entrench from turnsOnTile >= 1, so a unit built last night opened its first Orders phase already deriving the deepest defensive Stance; it therefore took −12 initiative rather than Hold's −6, on top of the −8 it already owes to Forming Up, making a new unit slower than TM-960's curve intends; and at the following Reckoning it would accrue a dig-in level under TM-700 without its owner ever having chosen to dig, which is precisely the tempo price that requirement's rationale says entrenching must pay. Fixed by extending the existing guard. The reference hash did not move, so no fixture depended on it.

One observation recorded rather than changed. Two hosts describing the same game with the starting units listed in a different order produce identical games — the units come out with the same ids, sequence numbers and tiles, because TM-850 sorts the enumeration — but different state hashes, because the setup block is canonicalised verbatim, listing order included. In practice both peers read the same scenario file and no divergence arises; the hazard is a host that re-serialises through an unordered structure, which would desync at the first comparison and name a bug that is not there. Normalising the block would move the reference hash and is therefore a RulesVersion decision (TM-2450) rather than a fix to make in passing.

Two cautions the register's first real use taught, both about reading it rather than about the code. A test that cites a requirement is not necessarily a test that exercises it: the first TM-1280 test compared two empty event arrays, and would have booked the requirement as covered while asserting nothing at all. A test written against a property no other test reaches is worth one deliberate check that its observable actually moves when that property breaks — the §9 suite was accepted only after each of its assertions was shown to fail against a deliberately broken engine. And the headline number can rise while the work improves: covering the first requirement in an untouched section reclassifies that whole section out of "unbuilt, expected" and into the risk surface, so the §9 work moved 14 requirements out of the middle row and brought 6 in behind them. The corollary is a discipline — cite a requirement in a test only where the test reaches it, because a citation in passing books its entire section as started.

The roster increment moved the middle row up, 536 → 546, by the mechanism the cautions above describe: its tests are the first to cite anything in four sections of 02-units-and-industry.md, so those sections left the bottom row for the middle one and brought their untested remainder with them.

The 546 is an upper bound on work, not a count of defects. Some of those requirements are contracts on other documents, presentation obligations or performance bounds that a unit test cannot express, and the honest response to those is to say so at the requirement rather than to write a test that pretends. The number's value is that it points at sections, and the sections are real.

A caution for anyone reading the increments above as progress toward the exit. The world increments are landing as tested modules, but most of them are not yet wired: defaultCascadeRules still answers tileEntryEffects with cost 1, throws from chebyshev and settleCityCapture, and no-ops resolveAttack. Only tests supply real implementations. So no unit moves over real terrain through the Cascade yet, no game can end, and Milestone P0 — a human playing a tier-1 game in the CLI — is unreachable until the setup slice wires the seams and the combat, economy, units and victory increments arrive. The seams are the integration surface and they are the part nothing currently covers.

The units increment, first slice (2026-09-05): the schema, the validator, and the tier-1 roster. packages/core/src/units carries the complete unit-definition schema of 02-units-and-industry.md §2–§3 — every field, every closed enumeration — and the set validator of §4, as a pure function of the document that reports every failure in one pass (US-800). The shipped set is a JSON document in the format of US-700, loaded and validated at module import so that a broken roster fails the first import rather than the first game, and it holds tier 1 exactly as §8.1 and §8.2 print it: the five manoeuvre units and the three auxiliaries, the latter priced by 12-economy.md as the ruling in §8.2 requires. setupUnitFrom turns a definition into a starting unit, so a game can now be built from the roster rather than from a test fixture, and the first such game activates its Scout, Field Gun and Infantry in exactly the commitment order US-290 argues for. The build times of §12.1 come out of the data to the turn.

The schema is complete; the roster is not, and the roadmap says so above. Tiers 2 to 4 are authored against the same schema, and until they are the coverage checks of US-110 and US-480 report the gap as warnings — ten classes and ten flags no shipped unit carries — which a test pins exactly, so that the moment the roster is complete the warnings become the CI failures those requirements ask for.

Pointing the validator at the roster found the specification disagreeing with itself twice, and both are ruled in docs/design/02-spec-rulings.md: US-390 required every bombarding class to engage land, and three shipped warships bombard while engaging sea alone; and zoc and mayOccupyCity are required by the schema, read by 01-game-rules.md and 13-command.md, and assigned by no table in §8. Three further inconsistencies are recorded here rather than ruled, because each belongs to a document another increment owns:

Two things the roster does not yet carry because no document supplies them: reactionReach, which §8 has no column for, so every unit takes the TM-1580 default of 1; and the widened clause 9 of the domination test is implemented but has nothing to exercise it until a cross-role pair appears on the same domain and tier, which tier 1 does not contain.

The CLI increment, and the first played game (2026-09-06): Milestone P0's exit, on the engine's side. @everylastcity/cli landed the P0 verb set of AR-810 — new (host-minted GameId, a deterministic starting force with complete Hold/Defend postures), play (hot seat on stdio with the full-state display), apply, save, replay --verify, hash — over one container as the save (AR-550): a ZIP holding manifest.json, initial.bin (the setup and the seed; loading re-materializes through the sanctioned path, AR-200) and orders.log (AR-260 envelopes, gapless seq, chain re-derived on verify). The load path is AR-030's third entry point, loadFrom, in packages/core/src/turn/load.ts. Two core fixes landed with it, each named by the first played game. GR-280: the roster bridge fed the raw move attribute into movementAllowance; tier 1 now runs at move × 4 (scout 20, infantry 8, militia 4) — the missing multiplier was the near-immobility. GR-330, the minimum move, was specified but unimplemented: a unit that has spent no MP in the current activation may enter one adjacent legal tile whose entry cost exceeds its entire allowance, spending all remaining MP. A third defect was found and fixed by re-playing the game with the ×4 in place: the March policy's waypoint loop re-tested the minimum move with the original spentBefore after its own first step had already paid most of the allowance, so the policy consumed a tile the engine could not pay for and the March cache (CM-1470) desynced by one step — the unit then spent the rest of the game consuming stale cache the engine rejected as unenterable, frozen for 199 turns. All three carry named tests, and the ratchet rose 763 → 764 with GR-330.

The caveat above is retired: the setup slice wired the seams, and the combat, economy, units and victory increments (the Seal — V1 at 0397688) had landed before this one. The first tier-1 game was played end-to-end in the CLI to a decided finish — elc new (seed 00000000cafe0042, two players, Small, four units each) into elc play on hot-seat stdin: the 200-turn horizon, winner P1, final stateHash 01def33c8fb09492 — re-hashed on 2026-09-06 as the canonical form and the victory seams moved (VC-3320, the EC-1450 claimant, the VC-1470 mark transfer; 2fb6914c6217c32e was that era's value), re-hashed again that day as the March follow-on the hashed posture carries went from the bare string the old validator stored to the well-formed order object the fixed one requires (59429c0c7441cc4a was that era's value), and re-hashed a third time that day as setupToCanonical began sorting the starting force in the canonical TM-850 clause-3 order (the AR-090(e) shuffle-harness fix: the container's setup was enumerated in the placement's walk order, so its state hashes moved) — same seed, orders and trajectory, record for record, at every re-hash —; the container (artifacts/reference-game.elc, re-emitted 2026-09-07 so its manifest carries the current value) replays at 601 records with the chain re-derived, elc replay --verify fully green on a fresh clone, and the stance-fallback rate is emitted per game (0.9950). The remaining exit items stand as recorded: the AR-960(a) corpus has passed the P0 stage floor (the first-milestone 25-game minimum is met with 33 — the 25-game idle grid plus the eight TM-2360 hazard vehicles that landed 2026-09-06, one whole-turn game per named hazard), and identical replay hashes across the AR-960 matrix are verified locally (the browser leg 221/221 on chromium, firefox and webkit — the 187 determinism primitives plus the full 33-game corpus, replayed against the same expected-hashes.json the node lane uses; the webkit leg on this host without root, its dependencies extracted to user space because noble ships no WPE packages — and the golden hash unchanged through both core fixes), with the macOS/Windows leg on CI; the V8 numbers are recorded against the restated AR-760 with the shortfall named — re-run on the P0 host on 2026-09-06, 14.8 / 35.1 / 82.2 ms per activation at 25 / 100 / 250 units with fog at 73–93 % of the cost, the same single named cause; and the played-to-a-finish clause is now read per the 2026-09-06 ruling above — the authors play it, the container is kept, the findings are recorded, and the independent session is Phase 2's to gate. The hot seat it is played in is pnpm elc new … then pnpm elc play … from the repository root, with corepack enable first on a machine where pnpm is not yet a command; docs/PLAYTEST.md is the procedure, and it draws the map rather than listing coordinates. The last two victory-surface defects (the EC-1450 claimant seam and the VC-1470 double mark) were closed on 2026-09-06 alongside the canonical-form gap (VC-3320); one P0 risk (no P0 path makes a player not-live — the elimination machinery is Phase 2) remains logged in SESSION.md's Possible issues.

2.3 Phase 2 — The client, the full rules surface, and an opponent

Make it a game people want to look at, finish the rules, and give the solo player someone to play.

Exit: a person who has never seen the design plays a tier-1 game to a finish without reading anything and can say what they were deciding; a full four-tier game runs to a decided end against Constraint Floor opponents; accessibility audit passes; 60 fps in the browser on the reference hardware (03-architecture.md AR-700) at the performance fixture's map size, with the Tauri desktop and mobile packages of the same build inside AR-700's device allowances; the Cascade playback of a 150-unit turn is watchable and skippable.

Status of the exit clause, 2026-09-24, one clause at a time, because they are six different kinds of evidence and none stands in for another.

2.4 Phase 3 — Playtest and the tuning pass

This phase is new in v0.2, and it exists because the premise changed. When the plan was to reproduce another game, balance was inherited: the numbers had been played by other people for decades and the job was to match them. Now every number is ours and none has been played. Seven interlocking systems — the Cascade, the order vocabulary, Clash and rout, Integration and Cadre, the Industry ladder, Tracks and the Vigil — have never run together in the same game. That is not a risk to be mitigated at the end; it is the largest single unknown in the project and it gets time on the schedule.

The rules documents already asked for this in their own voices. 02-units-and-industry.md US-2230 requires the design's known hard edges to be "revisited after the first full playtest." US-2220 names two failures no metric will catch. TM-1440 makes the stance-fallback rate the fastest diagnostic in the design and puts a band on it. VC-3300 defines thirteen acceptance metrics with targets and makes a metric outside its target a release blocker. Every rules document ends with open questions that say, in effect, settle this with a build. This phase is where those obligations are paid.

Exit: the VC-3300 metrics computed and inside their targets, or explicitly and publicly revised; the stance-fallback rate under TM-1440's 8 percent band across a corpus of real games; the alarm table of 02-units-and-industry.md §14 clear; every open question listed above closed by a build with the evidence recorded; a written list of every constant changed during the window and why. A metric that cannot be brought inside its band exits this phase as a named design defect, not as a silently widened target.

2.5 Phase 4 — The AI proper

The headline feature, and the largest engineering ambition in the project after the turn model.

Exit: the mid-tier AI beats a competent human less than half the time but more than never on a standard map; every tier beats the tier below it at a clear margin over a large round-robin; zero Constraint Floor violations at any tier, as a build gate rather than a metric with a band; the farm runs a nightly batch with zero desyncs and no illegal orders; and the human-survey row nobody can automate — did the opponent do anything that surprised you? — comes back yes more often than not.

2.6 Phase 5 — Multiplayer

Connect people. Async is the primary mode and this turn model is unusually kind to it: one submission per player per turn, whenever each player happens to sit down, rather than a network round-trip per unit (docs/design/01-decision-turn-model.md, "What decided it").

Scheduling boundary (owner ruling, 2026-09-19). Phase 5 does not include the signed-file mode of 05-multiplayer.md §10. Its MP-750–MP-880 contract is retained intact in Phase 7. Bundle-specific work must not be selected before this phase's exit, except where shared container, replay, signing, encryption or verification machinery independently satisfies a current-phase requirement. This does not move server-hosted correspondence: §9 remains a Phase 5 launch candidate.

Exit: an async game survives a week of real play across three time zones and two platforms; a self-hosted instance runs the same test suite green; fog enforcement holds against a client modified to ask for hidden state; an eight-player Cascade resolves and plays back inside its budget.

2.7 Phase 6 — Openness

Hand the game to its community. The design already made this cheap: a custom unit set is a single JSON document using the closed flag vocabulary, with no scripting of any kind (US-2050, US-2060), and its content hash is in the canonical game hash so a version skew desyncs loudly rather than silently (US-2090, US-2100).

Exit: a third-party author, given only the public docs, ships a custom unit set and a map generator that other players install in-game and use in a multiplayer match without desync.

2.8 Phase 7 — Long tail

Exit: the VC-3300 metrics recomputed on live data with the deltas from Phase 3 explained; no Track, Charter or unit outside its balance band on population data; and a four-seat signed-file game completes a full turn through one opening bundle and three order packets, rejecting a stale packet and a tampered hand-off by name.

2.9 Old phase numbers

For readers of v0.1 and for any document that cites a phase by number: old Phase 3 (AI) is now Phase 4, old Phase 4 (multiplayer) is Phase 5, old Phase 5 (modding) is Phase 6, and old Phase 6 (the Enhanced set and long tail) is Phase 7 with its unit-set content removed — there is one shipped set, and the Industry ladder rather than a fourth content pack carries the complexity curve. Phase 3 is new.

3. Dependency structure

Phase 0  fixed-point ✓ · determinism CI ✓ · lint gate ✓ · browser leg ✓ · doc sweep ✓ · rights decision ✓
   │
Phase 1  turn machine + order vocabulary + core rules (tier 1) + CLI ──── Milestone P0
   │
Phase 2  Client · full rules surface · Constraint Floor opponent
   │
Phase 3  Playtest & tuning ◄──── the farm needs Phase 2's opponent
   │                              (continuous from P0; a dedicated window here)
   ├──────────────┐
Phase 4  AI    Phase 5  Multiplayer
   └──────┬───────┘
          │
     Phase 6  Modding & workshop
          │
     Phase 7  Signed file play · stats · polish · second tuning pass

Phases 4 and 5 can run concurrently once Phase 3's tuning has settled the constants both are built against; neither depends on the other, and the ordering shown reflects the owner's stated priority rather than a technical dependency. Phase 3 is drawn as a phase because it needs dedicated time, but it begins at Milestone P0 and never stops.

4. Risk register

Risk Impact Mitigation
The conditional-order vocabulary ships thin, and the turn model collapses into blind WEGO. Named in docs/design/01-decision-turn-model.md as the single biggest execution risk in the design, and it is a scheduling risk as much as a design one: the vocabulary is the easiest thing in the plan to defer, because it looks like a UX convenience and is actually the load-bearing element The central design decision was wrong. Committing orders before seeing them becomes a gamble rather than a skill, players correctly report the game feels like guessing, and the fix is a rework of the spine rather than an addition to it Ship the six Postures (CM-330) and four Sanctions (CM-570) in Phase 1 alongside the turn machine, not in the client phase (§1.4). Instrument the stance-fallback rate (TM-1440) from the first playable build and treat its 8 percent band as a gate, not a dashboard — it is a direct proxy for "is the player's intent surviving contact with the turn," it responds immediately to changes in the vocabulary, and if it is unhealthy nothing else about the model matters. Note the asymmetry that makes early investment cheap and late investment expensive: command-layer behaviour is core and versioned, so every later change to a Posture algorithm or a Sanction test breaks stored replays (CM-2060, CM-2070)
AI ambition exceeds what a small team can build. The owner has named advanced AI as the headline feature, which is exactly the condition under which an over-promised AI ships weak and the failure is invisible to the team until players find it in week one The pillar the product is sold on is the thing players complain about; and because the failure is a plausible-looking opponent rather than a crashing one, it survives internal review Build in confidence order, not ambition order: the Constraint Floor in Phase 2, because it is arithmetic against closed integer specifications and is where opponents in this genre visibly fail; the search layer only after its plan-ranking falsification test passes (§2.5), with a named fallback — greedy plus local search over a good candidate set — that is still a competent opponent. Keep the AI a client rather than core, so its orders enter the order log and improving it never invalidates a save. Make "zero Constraint Floor violations at every difficulty tier" a build gate. State the honest ceiling in public — beat most players, lose to experts — rather than letting marketing set it
Seven interlocking new systems, 1,790 requirements, never playtested together. Nothing in the design has been played. Every constant is a first guess, and the systems couple: Industry feeds the economy, the economy prices combat losses, combat feeds Tracks, Tracks set the tempo the command layer is sized for The failure is not a bug. It is a game that is coherent on paper and unpleasant to play, discovered late, when the constants are baked into fixtures, saves and player expectations Phase 3, with dedicated time and exit criteria (§2.4). Milestone P0 as early as the design allows, on the smallest rules surface that is a game. Instrument before tuning (§1.9) so the first balance conversation has numbers in it. Freeze schemas and requirement IDs, not constants, and mark the knobs in advance. Treat each rules document's "what could go wrong" section as a work item rather than as reflection
The design's own open questions are load-bearing and unsettled. Each rules document ends with questions its author could not close by argument — the movement metric, the Yard's granularity, how much initiative to disclose, Vigil defaults. Several change how the game feels, not merely how it computes Answering them by argument produces a defensible wrong answer; answering them late produces a rework across documents that already cite each other They are chartered to Phase 3 and closed with a build (§2.4). Where a question can be settled by a cheap experiment, the experiment is the deliverable, not the memo
Committing before seeing loses players who came for the interactive feel. An honest cost the turn model decision names rather than hides Bounce on first session; reviews describing the game as "you don't get to play, you submit forms" Instant Cascade with optional step-through in solo and two-player games, and no Orders deadline unless one is asked for, per the decision document's first amendment. Treat playback quality as a Phase 2 feature (§2.3), because the playback is the compensation. Measure first-session abandonment during Phase 3, and treat a bad number as a presentation problem to solve rather than a model to relitigate
The determinism rules are a discipline, and disciplines decay. TypeScript has one number type; nothing in the language stops a plain * on two plain numbers from entering rules math a year in The violation is invisible at review — one correct-looking expression — and surfaces later as a rare desync, or a replay that diverges at turn 300 with no obvious cause Already mechanised rather than discouraged: the branded Fixed/Int types, the lint bans, and the cross-platform hash-agreement job, all in place from Phase 0. What remains is upkeep — nightly re-replay so a violation surfaces within days rather than inside a player's save, and an audit of every eslint-disable in the core at each release, because the real leak is suppression rather than absence
V8 performance on large-map turn resolution against budgets written for AOT-compiled native code The AR-760 budgets may be missed at the upper map tiers, and the miss lands hardest on the target with the least headroom — the browser tab, which is the primary one Re-baseline in Phase 1 while state layout can still change; typed arrays and structure-of-arrays state, no allocation on hot paths, monomorphic call sites, simulation in a worker. Note that the turn model helps here: the Cascade is computed once per turn rather than interactively, and playback is decoupled from computation. If a budget still cannot be met, the fallbacks in order are: relax the budget and publish the new number; cap the top map tier on the weakest targets; and only last, a WASM kernel for one isolated hot path — acceptable only behind a bit-identical differential test, since a second implementation of anything is itself a determinism risk. The AR-760 fixture must first be restated in terms of the current design
The implementation is largely AI-authored The dominant failure mode is not a crash but a plausible-looking rule that is subtly wrong: code that reads correctly, survives a casual review, and computes the wrong number in one branch. Volume makes it worse — more code is produced than anyone will read closely. The withdrawal of the fidelity premise makes this worse, not better: there is no longer an external oracle that would have caught a wrong constant Anchor verification to the requirement IDs, which are now the only authority: every requirement maps to at least one named test, plus the worked test vectors the documents nominate (VC-3310 is the pattern), property tests (AR-950), determinism CI (AR-960), coverage gate and fuzzing (AR-990). Spend scarce human review on spec-to-test correspondence — does this test assert what the requirement actually says — because that is precisely what a reviewer skimming plausible code will not catch. Prefer loud failure to defensive defaults; a silent fallback hides the mistake until it reaches a save file
Scope: fifteen documents describe more than a small team can build Nothing ships Phases 1–3 plus hot seat and a Constraint Floor opponent is a legitimate product; everything after is additive. The ordering above is chosen so that the cut line falls in a defensible place at the end of every phase
Rights and naming unresolved at ship time Cannot publish, though development is unaffected Much smaller under clean-room than under the withdrawn premise (§2.1). Resolved: the owner took the decision offline on 2026-09-03 and Phase 0 is complete (§2.1)

Retired with the fidelity premise, named here so a reader of v0.1 can see they were dropped deliberately rather than forgotten: the drain and combat-mod formulas may not be recoverable from the original — there is no original and both systems are specified in 11-combat.md and 12-economy.md as original design; reference data may be unavailable — no reference data is needed or wanted; and the Enhanced set's special cases resist data-driven modelling — there is no Enhanced set, and the closed eighteen-flag vocabulary of 02-units-and-industry.md §3 with its ban on branching by unit id (US-060) is the structural answer to that whole class of problem.

Retired earlier by the stack change, and still retired: Godot C# on iOS cannot host WASM plugins — the plugin host is now the platform's own WASM engine, present in every browser and in Node; and browser delivery is unreachable — the browser is the primary build rather than a second client that would have had to be written twice.

5. What "done" means for the project

The v0.1 answer was that a veteran could play the game they remembered and not point to a rule that behaved differently. That is no longer a goal; it was never the owner's goal, and it is a ceiling rather than a target. The replacement is harder to measure and worth more:

Open questions

  1. Team size and shape is unstated. The phases are sequenced by dependency, not staffed. A one-person effort would likely cut Phases 6–7 and ship 1–5; a two-person effort probably has to choose between Phase 4's AI and Phase 5's multiplayer rather than doing both. This plan does not make that choice and cannot.
  2. Where does the AI specification live? Settled: 06-ai.md. It has been rewritten from the four AI design documents and carries 219 AI-prefixed requirements specifying the Staff — the layered architecture, the fairness constraints, the six Ranks, the personality roster and the self-play pipeline. It keeps its original number, so every existing citation of it still resolves. Phase 4 has a normative document to point at.
  3. Who owns the telemetry contract? Phase 3 depends on metrics nominated across five documents (TM-1440, 02-units-and-industry.md §14, 11-combat.md, 12-economy.md, VC-3300) and no document currently owns the emission, aggregation and retention of them. 08-services-platform.md is the natural home. Until someone owns it, Phase 3's exit criteria have no implementation.
  4. Is a public beta warranted, and when? Without an external oracle, outside play is worth more than it was — but a beta of an untuned game teaches the wrong lesson and an audience can only be burned once. The current instinct is a closed playtest during Phase 3 and a public one only after its exit criteria are met, but that is a judgement about audience, not engineering.
  5. Does the AI ship before, alongside, or after multiplayer? §2.9 puts AI first on the owner's stated priority. The counter-argument is that async multiplayer is unusually cheap under this turn model and would put real humans in front of the design sooner, which is exactly what a never-playtested design most needs.
  6. How much tuning budget is spent before first outside play, and who decides a metric is "close enough"? VC-3300 makes an out-of-band metric a release blocker; someone has to be allowed to revise a target publicly rather than quietly, and the plan does not say who.
  7. Does the farm need to exist before Phase 3, and who pays for the compute? The farm is the only instrument that produces thousands of games, it is what VC-3290's CI check and most of VC-3300 assume, and it has an ongoing cost nobody has budgeted.
  8. Do the AR-760 and AR-770 budgets survive V8 at the upper map tiers? Related: does the answer differ between the browser build and the Tauri builds, and is a tier cap that applies only in-browser acceptable given that the browser is the primary target? The fixture itself must be restated before the question can be answered, since as written it specifies content that no longer exists.
  9. Where do the human review gates sit, given that most code is AI-authored? Reviewing every diff neither scales nor catches the failure that matters; reviewing spec-to-test correspondence might. §1.8 asserts the principle and staffs nothing.
  10. Do the Tauri packages ship alongside the browser build at the end of Phase 2, or one phase later once store presence is being handled anyway?

Closed since v0.1: which fixed-point representation — signed Q16.16, one global scale, chosen and implemented (§2.1), and largely moot besides, since most of the rules surface specifies integer-only arithmetic (US-030 and the economy and turn-model documents throughout). Whether the browser client is a second implementation — it is not; one web client, packaged by Tauri 2. Whether iOS can host WASM plugins — the platform's own WASM engine hosts them. Whether Phase 0 VERIFY resolution needs cooperation from a rights holder — void with the premise; there is nothing to verify against and nothing to ask for.


Built from source 47fa2827eff0 · VERSION.json