Command the campaign. Let the Umpire handle the paperwork.
Sandtable is an in-development digital adaptation of SPI's 1979 board wargame The Campaign for North Africa: The Desert War, 1940-43. The original game models the desert war at an extraordinary level of detail. Players command Axis or Commonwealth forces, maneuver formations across North Africa, manage scarce supplies and transport, fight battles, and pursue the victory conditions of the chosen scenario.
Sandtable aims to preserve those decisions and the character of the original game while asking the computer to handle the rules, calculations, record-keeping, and hidden information. It is not a simplified game merely wearing the same theme: the rules target is the original 1979 SPI edition, corrected by the September 1979 errata, with any necessary interpretations recorded explicitly.
The project uses original software and presentation assets. Scans, rules prose, maps, and counter art from the published game are not distributed in this repository.
A campaign is overseen by a digital Umpire. Players issue orders; the Umpire checks what is legal, resolves movement and combat, applies uncertainty, reveals only what each side is allowed to know, and records what happened.
In the simulated campaign calendar, each turn represents one week and contains three Operation Stages. That does not mean a turn takes a real-world week to play: local sessions advance as the players make decisions. Initiative shapes which side acts first or last in each stage, and play moves through repeated movement and combat segments rather than one simple move-then-fight pass. Over the course of a scenario, players must balance position, combat power, cohesion, supply, transport, reinforcements, and the need to meet their own victory conditions.
The first playable release is planned as:
- the six-turn, Land-only Graziani's Offensive scenario;
- two-player local hot-seat play through the Maproom interface;
- an original schematic map with selectable formations and legal-action guidance;
- save and resume support, strict fog of war, and a complete campaign history; and
- deterministic replay from the same starting seed and accepted orders.
Later releases can add the detailed Air and Logistics Games, longer scenarios, the full 111-turn campaign, remote multiplayer, and optional AI commanders and narrative. AI is intended to advise or play a side; it will never decide the rules or secretly change the campaign state.
Important
Sandtable is a tested pre-alpha simulation engine, not yet a playable adaptation of the published game. Current scenarios are synthetic rules-laboratory fixtures, not released campaign content.
| Area | Current state | Meaning |
|---|---|---|
| Deterministic Umpire | Working | Versioned rules, seeded randomness, canonical commands/events, replay, checkpoints, and side-safe action boundaries are implemented. |
| Playable rule path | Working through Combat entry | Runner can execute Initiative, stage preamble, Reserve Designation, Movement, bounded ZOC/Reaction, and Breakdown, then stops before Combat adjudication. |
| Combat and continual cycle | Dormant Core through first positive Reserve Release | Creation and inherited-history restore, identity, decisions, costs, results, loss/retreat settlement, custody, relationships and round closure are implemented and reviewed through Task016. Isolated Release bases and lifecycle (017A1/A2) are also reviewed, including timed choices, deterministic fallback and completion. Task017B also connects verified settled Combat to empty Release opening/completion across32 reviewed contexts. Held-I no-move predecessor replays genuine first-opening history through empty Combat to Reserve Release. Task017C connects that history to owner release-I or deterministic I→II fallback, preserving other World state. Public Combat play and full cycle closure remain future gates. |
| Exercise and Maneuver tools | Working | Deterministic single runs, multi-run matrices, paired comparisons, strict readback, and evidence bundles are available from CLI. |
| User interface | Not started | site/ is project website only. Maproom hot-seat client is future work. |
| Published scenario | Not started | First target is six-turn, Land-only Graziani's Offensive after working Combat loop. |
| Durable save/resume | Not started | Replay/checkpoint contracts exist; user-facing campaign persistence comes later. |
| Model-backed commanders | Scaffold only | Gateway and worker exist, but no provider is configured and AI never owns authority. |
Current boundary in plain language: you can build engine, run full test suite, launch Aspire service stack, and simulate checked rules-lab Movement/Reaction/Breakdown paths. You cannot yet play a campaign or resolve Combat through public Runner actions. Combat internals are exercised through dormant Core tests; they are not yet exposed as playable actions.
Next delivery sequence:
- Complete released-I Movement and exception expiry, then use repeated cycles to complete later-II/consumed Reserve lineage (remaining Tasks017–019). Movement delivery plan defines first slice; Task018A provides relationship-aware costs; Task018B adds dormant atomic Movement/replay at an explicit isolated boundary. Task019A computes pure movement-continuation witnesses from admitted projections. Task019B authenticates released-I history/progress and armed support. Task019C adds native guarded repeat/finish for that path, opening ordinal2 Movement or entering Truck Convoy. Task018C admits one actual released-I ordinal2 move. Next: Movement completion and exception expiry; settled source/progress integration remains open.
- Activate certified, side-safe public Combat actions (Tasks020–021), then prove Exercise/Runner replay and repeatability (Tasks022–024).
- Reconcile all 72 acceptance criteria and demonstrate the authentic continual cycle (Task025). Actual publication evidence remains a separate obligation under HOST-PUB-001.
- Measure and implement the exact six-turn scenario content and remaining Land/victory rules, then add durable save/resume and minimal hot-seat Maproom. MVP exit requires two complete, reproducible six-turn games.
See current roadmap for authoritative status and Combat plan for detailed task graph.
- .NET SDK 10.0.302 or later .NET 10 feature band
- Just for short commands (optional)
- Git
- Docker only for future container-backed Aspire resources; current stack does not require it
global.json selects .NET 10 and Microsoft.Testing.Platform. Check installed SDK with
dotnet --version.
git clone https://github.com/dills122/sandtable.git
cd sandtable
just setup
just checkWithout Just:
dotnet restore Sandtable.slnx
dotnet build Sandtable.slnx --no-restore
dotnet test --solution Sandtable.slnx --no-buildjust runEquivalent command:
dotnet run --project src/Cna.AppHost/Cna.AppHost.csprojOpen Aspire dashboard URL printed in terminal. It shows Orleans host, Decision Worker, and Intelligence Gateway. This launches development services—not a playable Maproom. Stop with Ctrl+C.
Run current bounded Reaction Maneuver and write validated artifacts under artifacts/exercises:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.reaction.serial.breakdown.v1.json \
--artifact-root artifacts/exercisesRunner prints child bundle paths, aggregate report path, and deterministic fingerprint. More checked manifests and diagnostic modes are listed in detailed runbook.
python3 -m http.server 4173Open http://localhost:4173/site/. Website is dependency-free project documentation, not game UI.
git switch -c feature/my-change
just checkUse feature branch; never commit directly to main. Read contributor guide,
architecture, and vocabulary before changing boundaries.
Update contracts before consumers, add focused deterministic test before behavior, keep remote/model
I/O outside authoritative turns, then run just check before PR.
| Command | Purpose |
|---|---|
just --list |
Show repository recipes |
just setup |
Check SDK and restore dependencies |
just build |
Restore and build solution |
just test |
Build and run all tests |
just boundary-check |
Run user-space disclosure boundary suite |
just format-check |
Verify formatting without edits |
just check |
Full local gate: format, build, boundary tests, all tests |
just run |
Launch Aspire development stack |
just docs-links |
Check tracked Markdown links; requires Lychee 0.24.2 |
Build artifacts live under artifacts/. Do not commit generated artifacts/bin or artifacts/obj
content. See security policy for vulnerability reports.
Expand implementation ledger and contract history
[!IMPORTANT] Sandtable is pre-alpha infrastructure, not yet a playable adaptation of the published game.
Executable product and forward contract work are intentionally different. Today, public Rules9 authority and checked Runner evidence stop at first-side Combat entry. Parent003 frozen contract evidence composes 28 selected future Combat/cycle histories and exact Task004 handoff, but no Combat or Reserve Release runtime is registered. The pre-alpha roadmap is the canonical delivery ledger and defines the status vocabulary used below.
The current foundation can create a campaign from an exact ruleset, setup, Content Pack, and
scenario; project the scenario's initial mutable element locations; resolve Initiative
Determination and both admitted no-obligation Naval Convoy checkpoints; let the initiative holder
declare whether to act first or last in Operation Stage 1; resolve Weather; emit authoritative
events; explicitly resolve empty Organization, Naval Convoy Arrival, Fleet Assignment, and Fleet
Repair obligations; adjudicate the first-acting side's Reserve Designation; execute supported
first-side Movement; open, adjudicate, close, and resume bounded ZOC Reaction interrupts; complete
Movement through Breakdown Determination to unsupported first-side Combat; resolve explicit
route stops with exact BP checks and persistent broken-vehicle lots; and replay those events to byte-identical state. Reserve authority now carries per-element status,
owner-only observation, exact acting-side candidates, closed command mapping, bounded checkpoints,
and canonical designation/completion events. The Movement foundation additionally records exact
per-Operation-Stage expenditure/Cohesion state and opaque one-to-one map representations. It now
also carries typed move/completion candidates, deterministic action identities, an exact side-safe
cost breakdown, strict non-authoritative readback, internal authoritative non-contact move
adjudication/replay, and observation-derived public action membership with exact submission
revalidation. Ruleset manifest contract 9, setup schema 6, snapshot contract 11,
Campaign World snapshot contract 6, Campaign Observation contract 7, legal-action-set contract 2
with policy v3, and Content Pack schema 6 / canonical format v5 use original synthetic
rules laboratories to develop game systems without redistributing published assets.
Campaign Observation derives deterministic side-safe public topology, audience-visible turn
revision, exact own mobility/ledger/Reserve and approved vehicle-risk facts, plus only opaque
opposing representation/location rows and the source-unmapped current-ZOC aggregate. It exposes neither complete Content identity,
real opposing bindings/force facts, nor hidden Reserve counts. Legal Actions v1 exposes those
mechanics through an opaque campaign-authority handle,
deterministic system/side action sets, exact-audience membership enforcement, and side-safe
acceptance receipts. Weather Determination v1 resolves corrected source-cited Weather through that
same boundary and records pair-keyed evidence. Operation-Stage Entry v1 then resolves only the four
explicitly admitted empty obligations through mechanic-specific actions and events. Side-safe
queries derive the Reserve audience from the recorded first/second actor order while its symbolic
sequence position keeps ActiveSide unset; current Movement materializes that resolved side because
successor Movement and Reaction identities bind it. Raw snapshots, commands, events, content
context, projection, and replay are not public mutation seams.
Campaign Observation 7 uses the
sandtable.observation.breakdown-side-safe.v1 policy, one canonical source-unmapped aggregate
of apparent enemy-controlled locations, exact owner-visible Movement-ended membership, and a closed
normal/phasing/reacting/Breakdown-waiting decision-state union. Pending stops expose one
System capability and generic player waiting; own lot summaries contain cohort/location counts
without lot IDs or evidence, and reactor waiting omits owner rows that could reveal bindings. Its reacting view contains only the apparent trigger,
the observer's current state-scoped capability handles with closed current move-option/cost
capabilities, and the optional active own participant. Raw element Movement, ledger, Cohesion,
Reserve, mobility, organization, and stacking inputs remain inside Core. Reacting construction and
readback reject identity-bearing root owner-element rows, so no representation-to-element binding
is published. Admission also recomputes capability-bound opportunity handles, validates published
route/hexside cost claims against their selected edge, and binds reacting/phasing decision labels
to the observer's relationship with the active side. Both sides receive the same audience-safe
window handle, never the authoritative
window identity; phasing receives only generic waiting while retaining its ordinary owner facts. A
versioned disclosure manifest and mandatory boundary-check gate register
this outward surface and protect retained cross-state transcripts from copied-fingerprint joins.
A distinct strict projected-history contract retains the same redacted decision state without
authority bindings, source mappings, evidence, or internal reasons. The current action layer derives
topology-local ordinary Movement and first/later Reaction movement, participant
completion, player decline, and reason-specific System close membership with canonical identities,
strict current readback, and unpublished typed submission intents. Public Core query, submission,
checkpoint, serialization, and replay paths now use this complete successor set; bounded Exercise
Runner Reaction controllers implement ZOR-TASK-007A: explicit bounded policies support
participant ordering, one/two-step episodes, decline/subset close, and System fallback.
Current Movement completion preserves accepted Reaction costs through the Breakdown boundary;
explicit Breakdown completion advances to unsupported Combat without another draw.
The historical ZOR-TASK-007B package closed with strict evidence, matching clean-run fingerprints,
and a Ready independent review; see historical Reaction trajectories.
Owner accepted Breakdown decisions BRK-DEC-004–007. Tasks 001–005 supplied the frozen contracts,
certified world, BP accounting and deterministic stop lifecycle. Task 006 public activation
activates that complete identity set, Observation 7, projected history 2 and disclosure manifest 2.
Current creation, checkpoints and event admission reject legacy or mixed contracts; retained
Initiative, Weather and preamble evidence is recomputed, while full history is verified separately
by replay. Public queries stop at first-side Combat entry. Positive ZOC, motorized-infantry losses
and later-stage reset remain outside the certified profile. Task 007 implements fourteen checked
successor manifests and a Truck study, using certified battalion, Reaction and Truck-only inputs.
The original fixtures remain historical with
unchanged bytes. The profile permits zero cohorts: land.breakdown-cohorts is required exactly
when a pack contains a cohort; all other capability, organization and stacking checks remain strict.
Task 007 closeout records 1,655 passing tests and two matching clean runs of 47 campaigns each. AC-009 follow-up adds fifteen transcript/privacy cases, bringing verification to 1,670 tests and 81 boundary cases. Review 5 accepts the bounded coverage; its status-only follow-up is corrected. Tasks 006–007 are complete within the certified profile.
The local Cna.ExerciseRunner supports that synthetic rules-laboratory path as either one
bounded, deterministic Exercise or one serial Maneuver. An Exercise uses a fresh opaque Core
capability, selects only current legal actions, stops at its exact declared boundary, proves both
event-history reconstruction and fresh-session re-adjudication, and writes a manifest-last
trusted-authority evidence bundle. The original Organization, Reserve and Reaction checked fixtures are historical. Current regression
tests and checked .breakdown.v1 successors use certified battalion, Truck and contact inputs. A serial-unpaired Maneuver
strictly admits one canonical ordered serial-unpaired manifest,
derives explicit child identities from its sole parent root seed, and runs each child in process
through the same coordinator. Each completed child bundle is read once for semantic validation and
identity-matched aggregation; snapshot facts are accepted only after the complete Core-owned
snapshot/world decoder validates their canonical structure. The resulting transactional report
separates deterministic counts, outcomes, and fingerprint material from noncanonical timing/path
diagnostics and is strictly read back before completion is claimed. Compact, forensic, and debug
Exercise detail tiers expose progressively richer evidence without changing simulation truth. The
current two-setup serial-unpaired Maneuver retains predetermined and contested initiative paths.
A checked six-child controller matrix crosses act-first/act-last with Reserve
none/one/all, using two non-cohort battalions per side so all three choices remain distinct.
The corresponding Movement matrix includes explicit route stops and System resolution before
Breakdown entry. The thirteen-child Reaction successor
retains ordering, one/two-step episodes, decline, active System closure and later-trigger recurrence
with separated battalion reactors. The two historical positive-ZOC children remain deferred from
public authority. Optional serial-paired Maneuvers run
isolated baseline and candidate arms
sequentially from identical declared initial conditions, initial role-specific random streams,
campaign creation inputs, build cohort, and initial snapshot. Its strictly read-back comparison is
descriptive only: trajectories and random consumption may diverge after the first differing choice,
and it makes no causal, statistical-significance, gameplay-balance, recommendation, or
synchronized-post-divergence claim. Runner model controllers and side-safe exports are not
implemented.
The checked Exercise and serial-unpaired Maneuver profiles use manifest v2, with unpaired report
scheme sandtable.maneuver-report.v1; the separate paired Maneuver uses
sandtable.paired-maneuver-manifest.v1 and
sandtable.paired-maneuver-report.v1. Current successors use Ruleset 9, Snapshot 11, World 6, strict
trusted-authority evidence admission, and deterministic v2 controller configuration identity.
The first two historical simulator studies recorded repeated Movement-terminal determinism,
counterbalanced-order timing, and contested root seeds 0-31. Every sampled run passed strict
readback; the results also show that future back-testing needs explicit act-last and Reserve
none/one/all controller profiles rather than seed variation alone. See
Baseline 1 and
Baseline 2. The follow-on
controller-policy matrix closes that explicit
coverage gap with 6/6 strictly read-back trajectories and a repeatable aggregate fingerprint.
The merged Movement trajectory study retains its
pre-Reaction 48-trajectory baseline across six controllers and four deliberate seed probes. Under
the historical Rules 8 authority, Reserve-none repeats stopped at the opened Reaction window while
the other profiles retained exact Breakdown evidence. The historical follow-on
Movement cost-sensitivity study compared
stable-route and lowest-public-cost policies: its stable arm failed at Reaction after a cost-8 move,
while its lowest-cost arm completed a 1/2-plus-1 route. Current paired cost successors use
unladen Trucks and retain exact CP, BP and stop evidence. The added
act-first-reserve-all-move-each-once-by-lowest-cost-then-complete policy selects one lowest-cost
public move per eligible element. act-first-reserve-all-repeat-highest-cost-stops-then-complete
repeats highest-cost public moves, stops after each edge, and drains each pending System resolution.
These are bounded simulator policies; Core still determines legality and every result.
Contact, combat, published scenario content, persistence, and the Maproom player interface remain future work.
The reviewed Player Intent Composer is also future work. After the movement/contact/combat skeleton proves one representative multi-field decision, a no-model prototype will validate contextual suggested approaches, a private typed draft, bounded clarification, deterministic Staff planning, and hot-seat isolation. Deterministic Maproom integration belongs in Sprint 8; Needle or any other parser remains behind a post-MVP evidence gate and cannot block the playable campaign.
The current delivery boundary is:
See the current checkpoint and next gates for contract versus runtime status, the Combat simulator gate, and the accepted bounded Orleans investigation, now complete with a bounded Rules9 probe. Its production publication/storage proposal remains unapproved. Combat contract checkpoints through 003C3c/D2a/D2b private checkpoints and D2c.1 successor/opening contracts are complete; D2c.2a opening provenance now reaches Weather entry from validated Created11 bytes. D2c.2b Weather now reaches Organization entry. D2c.2c stage entry now reaches Reserve entry; D2c.2d Reserve designation/completion now derives actual first-cycle opening. D2c.3a inherited Movement now derives ordinary Move4 from that history. D2c.3b route lifecycle adds deliberate stop, empty-cohort resolution and Movement completion with actual end proof. D2c.3c Breakdown completion now reaches actual Combat entry. D2c.3d actual-entry selection now admits the moved CP12/14 state and closes its zero-candidate selection without a decision. D2c.3e no-attack traversal carries that closure through six exact structural completions to same-slot Reserve Release without material state change. D2c.3f Reaction trigger instead replays one actual Move4 prefix and opens one frozen-opportunity Reaction interrupt for either owner. D2c.3g Reaction lifecycle moves that sole participant once, completes it through mandatory empty-stop resolution, and resumes phasing only after no-eligible closure. D2c.3n direct Reaction closure instead closes either exact trigger by reacting-owner decline or reason-specific System unavailable/timeout and resumes the same suspended phasing route without material effects. D2c.3o active Reaction fallback instead starts after the participant's first move, closes active authority through reason-specific System unavailable/timeout, resolves the mandatory empty stop, and only then resumes phasing. D2c.3p active Reaction second move instead advances that same active participant from rear to supply at cumulative CP2→4, preserving route identity and active opportunity for later completion. D2c.3q Reaction movement completion then explicitly completes that exact CP4 participant, resolves its mandatory empty stop, closes the exhausted window, and resumes the original phasing route. D2c.3h Reserve cycle entry instead carries each owner's real held Reserve-I unit through a no-move first cycle to same-slot Reserve Release while preserving designation history, location and CP0. D2c.3i inherited Reserve Release opens the actual release window, records owner release-I and completes it with the exact pending ordinal-2 Movement exception. D2c.3j armed continuation proves that exact ammunition10 released-I profile reaches one supported next-cycle Combat candidate for either owner without emitting an event. D2c.3k guarded cycle control composes that proof with exact Release state and freezes both-owner repeat into ordinal-2 Movement or finish into Truck Convoy. D2c.3l released-I Movement then moves either exact released member one Clear hex at CP0→2 under ceiling10. D2c.3m released-I Movement completion closes both exact routes through deliberate stop, empty resolution and completion at authority31, then expires each pending exception with its accepted completion receipt. D2c.4 authority composition now reconciles CON-002–004 across 28 creation-rooted traces and freezes parent003's exact Task004 handoff. Parent003 is complete; Task004 and checkpoint B are accepted through the outward integration index. The latest smoke check verifies the existing Rules9 path; prospective Combat contracts are not executable game support.
| Area | Executable today | Forward evidence / next gate |
|---|---|---|
| Authority foundation | Versioned provenance, synthetic content, commands/events, deterministic randomness, replay, side-safe observations, and exact-audience legal actions for the admitted profile | Extend the same compatibility, recovery, and fog boundaries with each mechanic |
| Preamble and Movement boundary | Initiative through Reserve Designation, bounded Movement, ZOC/Reaction, and Breakdown through first-side Combat entry | Positive scenario-specific obligations and broader vehicle/ZOC profiles remain gated |
| Combat and continual cycle | Dormant Core through first positive Reserve Release | Creation and inherited-history restore, identity, decisions, costs, results, loss/retreat settlement, custody, relationships and round closure are implemented and reviewed through Task016. Isolated Release bases and lifecycle (017A1/A2) are also reviewed, including timed choices, deterministic fallback and completion. Task017B also connects verified settled Combat to empty Release opening/completion across32 reviewed contexts. Held-I no-move predecessor replays genuine first-opening history through empty Combat to Reserve Release. Task017C connects that history to owner release-I or deterministic I→II fallback, preserving other World state. Public Combat play and full cycle closure remain future gates. |
| Working skeleton | Not reached | One authentic movement/contact/combat/release repeat-or-finish loop plus identical replay |
| Playable MVP | Not started | Source-verified six-turn content/rules/victory, durable save/resume, hot-seat privacy, and minimal no-model Maproom |
| Exercise Harness | Current bounded Exercise/Maneuver and paired descriptive comparisons | Add Combat actions and terminals only after public Core activation |
The approved high-level path to a playable game is:
- Finish the Combat contract freeze, then implement dormant authority, public side-safe actions, strict Runner evidence, and one authentic repeat-or-finish loop.
- Freeze the exact six-turn scenario surface—rules, tables, content, sources, rights, termination, victory, and remaining decisions—before splitting later implementation tasks.
- Implement only that measured Land surface and source-verified
Graziani's Offensivecontent. - Add durable local save/resume and recovery, then minimal Maproom with complete no-model actions and hot-seat isolation.
- Complete two deterministic six-turn playthroughs and replay/privacy/source gates before calling the MVP playable. Optional parsing, hosted play, and model-backed intelligence remain later work.
The serial-Maneuver portion of Exercise Harness v1 now provides validated local multi-run regression
evidence without adding game rules. The implemented Operation-Stage Entry package retains its
research,
specification, and
technical design. Reserve Designation is the latest
completed player-action vertical before Movement. Its
research,
specification, and
technical design define an incremental designation flow
that stops at Movement. Rules, state, owner projection, legal candidates, command mapping,
designation/completion events, finite checkpoint validation, replay, and checked harness evidence
are implemented. The completed engine package is the approved Movement Foundation
research,
specification, and
technical design. It defines a fog-safe apparent-presence
gate followed by exact CP/Cohesion state, normalized lab terrain and stacking, repeatable
non-contact moves, and explicit completion to Breakdown Determination. The plan is owner-approved;
its source/ruling lock, exact Rules foundation, MOV-TASK-003 Content mobility contract, and
MOV-TASK-004 replay-complete world/representation contracts are complete. Task 004 records exact
Cohesion/expenditure and opaque internal representation
bindings in the Task 004 snapshot v8/world v3 creation history. On 2026-08-29 the owner approved sequential-d6
Breakdown coordinates, continuity-now, and the Table 21.38 Sandstorm-attributed-BP basis.
MOV-TASK-004B implements the exact Rules/Content/World seam and passed the repository gate plus
two fresh-context review instances. MOV-TASK-005 implements the contract-5 owner/apparent
projection and strict canonical readback. MOV-TASK-006 freezes dormant move/completion
candidates, exact cost semantics, deterministic IDs, pure observation-derived vectors, and strict
non-authoritative action/submission/receipt readback while preserving the existing contract
versions. MOV-TASK-007 adds the internal move command and canonical event, authoritative
cost/provenance recalculation, engine dispatch, atomic projection, and deterministic replay.
MOV-TASK-008 atomically publishes observation-derived move and completion membership, maps only
exact current submissions, adds canonical Movement completion through the Breakdown Determination
checkpoint, and preserves deterministic fog-equivalent actions and zero/one/many-move replay.
MOV-TASK-009 is merged in PR #78 and adopts that supported Movement path in checked
Exercise/Maneuver evidence. MOV-TASK-010 completed synchronization and independent review and is
merged in PR #79. At that historical milestone, Breakdown public actions and adjudication were absent.
The subsequent ZOC/Reaction package follows the
specification and
technical design. ZOR-TASK-002A-006B implement dormant
Rules/Content/fixture, Campaign World 5/creation 9, Snapshot 10, and ElementMoved v2 successors,
including exact current-TOE provenance, nullable/empty Reaction-window truth, strict canonical
readback, atomic projection, checkpoint replay, and the side-safe Observation 6/policy and redacted
decision-history contracts described above. Dormant topology-local Movement/Reaction candidate,
strict current-readback, stable-identity, unpublished mapping, move-option capability,
manifest-registration, semantic-admission, and retained-transcript contracts are also complete.
The direct-only authority path reconstructs atomic move/window truth, freezes only individually
adjacent eligible reactors, applies topology-local enemy-ZOC entry/exit semantics, and closes
player-declined, unavailable, timed-out, or empty windows with exact Movement resumption and no
cost/RNG mutation. It also selects the first participant atomically with its move, keeps later
steps bound to that active participant, accumulates exact shared Movement CP/provenance, and resolves
participants without World or RNG mutation. ZOR-TASK-006C now activates the complete successor
identity set on public Core creation, observation, action, checkpoint, and replay paths; legacy
creation and Movement roots reject. Bounded Runner adoption in ZOR-TASK-007A is implemented; 007B verification and independent review are complete.
The optional paired comparison is implemented Runner instrumentation and does not block
gameplay-engine progress.
Combat policies and the 25-task plan are owner-approved.
TASK-001 source evidence is complete: 357 defined loss
values preserved, three source gaps filled by accepted amendment CMB-SRC-RUL-001, and calendar/
break-off findings retained. TASK-002 Content7 contract is frozen
in c465a0f, with canonical bytes and70 passing rejection vectors. Checkpoint A author validation
is recorded; TASK-003A Setup/initial ledger is frozen in
23c3fff, with63 passing rejection vectors. TASK-003B World/settlement packet
is complete as a contract slice. Progress review5 returned
Ready with non-blocking follow-ups; its status correction is applied.
003C1 rules inputs and timing is complete as a contract
slice; review6 returned Ready, no actionable findings
(6of7 used at that checkpoint). 003D1 sequence/cycle contracts
are complete; review7 returned Ready, no actionable findings.
Review9 returned Ready with non-blocking follow-ups at
a96d2a1; its documentation corrections are applied. Review10 returned Ready with non-blocking follow-ups
for D2b.2/D2c.1; both findings are corrected. Review11 across mergedPR95–98 returned Ready with no
findings; budget11of11 is exhausted. The subsequent Weather and stage-entry slices have author verification only. 003C2 Rules10/creation envelopes
are complete for the creation cut. 003C3a selection/step control
is complete with author checks; 003C3b sealed round/commitment
is also complete as a bounded authority fragment. HOST-RSH-001 research,003C3c contracts and003D2a
ordinary movement contracts are complete. D2b Release and guarded control contracts are complete;
D2c.1 inherited successors/first opening is complete
as an isolated boundary:20 event declarations, four opening traces.
D2c.2a opening preamble freezes four of those successors
with6 creation-rooted traces/30 cuts through Weather entry. D2c.2b Weather
adds34 traces/68 cuts through Organization entry, preserving all four outcomes and exact RNG/receipt
evidence. D2c.2c stage entry adds12 traces/60 cuts through
Reserve entry, preserving all accepted history. D2c.2d Reserve designation/completion
closes creation-to-first-opening contracts for empty/I selection and both acting sides.
Movement preparation maps the next inherited
successors. D2c.3a inherited ordinary Movement
traces both sides through seven safe Clear moves, cumulative CP14 and four excess-CPA DP.
D2c.3b route lifecycle adds8 traces/24 events
through Breakdown Determination, with actual first Movement-end proof and unchanged World/RNG.
D2c.3c Breakdown completion adds8 one-event
traces into first Combat Position Determination while retaining that proof and full state.
D2c.3d actual-entry selection adds4 traces/8 events,
derives zero candidates from the moved World and closes selection while retaining stepIndex0.
D2c.3e no-attack traversal adds4 traces/24 events and
reaches same-slot Reserve Release. D2c.3f Reaction trigger
adds2 actual owner traces that open one frozen opportunity.
D2c.3g Reaction lifecycle adds2 traces/8 events
through participant movement/completion, required stop resolution and exact phasing resumption.
D2c.3h Reserve cycle entry adds2 traces/20 events
through no-move Movement, idle Breakdown and no-attack Combat while retaining actual Reserve I.
D2c.3i inherited Reserve Release adds2 traces/6
events through owner release-I and deterministic completion. Guarded repeat/positive Reserve
movement and broader Reaction remained open at that child boundary; D2c.4 now closes selected
composition.
D2c.3j armed continuation adds2 pure proofs
for the actual released-I ammunition10 profile, one candidate per owner, with full-result support
pins; it does not repeat the cycle or execute Combat.
D2c.3k guarded cycle control adds4 exact
repeat/finish traces while preserving private/non-runtime boundaries.
D2c.3l released-I Movement adds2 exact
ordinal-2 Clear moves with released ceiling10.
D2c.3m released-I Movement completion
adds2 three-event stop/resolution/completion traces and applies the exact D2b.2 expiry projection
from each accepted completion receipt; broader profiles remain open while D2c.4 now closes selected
composition.
D2c.3n direct Reaction closure adds6 one-event
forks covering both owners across player decline and distinct System unavailable/timeout authority;
D2c.3o active Reaction fallback adds4
two-event forks from exact post-first-move authority through reason-specific closed stop and
mandatory resolution. D2c.3p active Reaction second move
adds2 one-event owner traces from the same fork point through rear→supply at CP2→4 while retaining
active authority. D2c.3q Reaction movement completion
adds2 three-event owner/System traces through explicit completion, empty-stop resolution, and exact
phasing resumption at authority18. Multiple-opportunity Reaction and vehicle profiles remain open;
D2c.4 now closes selected composition.
Result/settlement and
full snapshot composition retain synthetic pre-Combat
lineage; review9 assessed these bounded artifacts. Parent003 closed through D2c.4; future
maturity execution remains open, while combined checkpoint B was subsequently accepted. The
ordinary movement packet freezes break-off/CP/DP
and corrects the former Clear1 example to the existing Clear2 rule. The
Reserve Release packet freezes single-deadline control
and retained history. The cycle-control packet freezes guarded
repeat/finish and Movement exception expiry:19 cases/64 traces,164 cuts. Its exhausted-ammunition
continuation surface remains private; D2c.4 now composes full history, armed Combat assessment and
Snapshot integration evidence. Later dormant World7 and codec work is summarized in the current
delivery table; Combat gameplay remains inactive.
See the pre-alpha roadmap for the capability-level plan and completion criteria.
Expand all Exercise and Maneuver recipes
Running the repository today launches the development service scaffold and Aspire dashboard. It does not yet launch a playable Maproom client.
The repository also includes a dependency-free project website under site/. From the repository
root, preview it with:
python3 -m http.server 4173Then open http://localhost:4173/site/. The website explains the intended player loop, authority
model, current implementation frontier, and developer quick start. It is project documentation and
outreach—not the future authoritative Maproom client.
The website deploys to https://dills122.github.io/sandtable/ through the dedicated GitHub Pages
workflow whenever website files land on main. The workflow can also be run manually from the
repository's Actions page. It uploads only site/; the simulation source and build artifacts are
not part of the published site.
- .NET SDK 10.0.302 or a later .NET 10 feature band
- Just for the shortest command workflow (optional)
- Docker (optional; required only when future Aspire resources need containers)
global.json requires .NET 10.0.302 or later and rolls forward to the highest installed .NET 10
feature band. It also selects Microsoft.Testing.Platform for dotnet test.
git clone https://github.com/dills122/sandtable.git
cd sandtable
just setup
just check
just runOpen the Aspire dashboard URL printed in the terminal to inspect the Orleans host, decision worker, and intelligence gateway. Press Ctrl+C to stop the application.
dotnet restore Sandtable.slnx
dotnet build Sandtable.slnx --no-restore
dotnet test --solution Sandtable.slnx --no-build
dotnet run --project src/Cna.AppHost/Cna.AppHost.csprojThe checked Runner commands below use certified Task 007 successors. Original Rules 8 manifests remain frozen historical inputs and are rejected by current admission. The closeout evidence records two clean runs of these current commands.
Run the Organization-boundary Exercise:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
exercise run --manifest scenarios/exercises/rules-lab.organization.breakdown.v1.json \
--artifact-root artifacts/exercisesThe command prints the finalized bundle path. The checked-in manifest is explicitly exploratory, so a dirty development tree is recorded honestly as nonbaseline and nonreproducible.
The corresponding Stage Entry profile runs all nine accepted actions to the Reserve boundary:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
exercise run --manifest scenarios/exercises/rules-lab.reserve.breakdown.v1.json \
--artifact-root artifacts/exercisesFrom a clean checkout, request a fail-closed baseline bundle with the checked baseline twin:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
exercise run --manifest scenarios/exercises/rules-lab.organization.baseline.breakdown.v1.json \
--artifact-root artifacts/exercisesThe Reserve profile has the corresponding clean-checkout twin
scenarios/exercises/rules-lab.reserve.baseline.breakdown.v1.json. Run the 12-step Reserve Designation path
through first-side Movement with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
exercise run --manifest scenarios/exercises/rules-lab.reserve-designation.breakdown.v1.json \
--artifact-root artifacts/exercisesIts clean-checkout twin is
scenarios/exercises/rules-lab.reserve-designation.baseline.breakdown.v1.json.
Set the manifest's detail to compact, forensic, or debug. Forensic adds correlated audience
queries, controller selection, checks, proofs, payload sizing, and the progressively assembled
context of failed query/controller/submission decisions. Debug also retains every available
monotonic phase timing on failure and prints a structured post-readback artifact trace. These
diagnostics are trusted local instrumentation and never participate in replay equality.
Run the checked two-child serial Maneuver with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.serial.breakdown.v1.json \
--artifact-root artifacts/exercisesRun the two-setup Stage Entry regression Maneuver to Reserve with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.stage-entry.serial.breakdown.v1.json \
--artifact-root artifacts/exercisesRun the two-setup Reserve Designation Maneuver through Movement with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.reserve-designation.serial.breakdown.v1.json \
--artifact-root artifacts/exercisesRun the six-policy Movement-entry matrix with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.controller-matrix.serial.breakdown.v1.json \
--artifact-root artifacts/exercisesRun the optional serial-paired Reserve-policy comparison with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.reserve-policy.paired.breakdown.v1.json \
--artifact-root artifacts/exercisesThe pair runs baseline then candidate sequentially in isolated Exercise sessions. Its report may describe first divergence and outcome/count deltas only; it cannot support causal, statistical, balance, recommendation, or synchronized-post-divergence conclusions.
Run the paired Movement route-cost sensitivity comparison with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.movement-cost.paired.breakdown.v1.json \
--artifact-root artifacts/exercisesThis unladen-Truck pair keeps declared inputs and initial evidence equal while comparing stable-route and lowest-public-cost controllers, including each move's BP accounting and explicit stop resolution. It is simulator instrumentation, not an Umpire rule or gameplay recommendation.
The command prints each validated child bundle path in manifest order, followed by the strictly read-back aggregate report path and deterministic report fingerprint. The report's local paths and timings are diagnostics and do not participate in that fingerprint.
Run the bounded Reaction successor or repeated Truck-stop study with:
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.reaction.serial.breakdown.v1.json \
--artifact-root artifacts/exercises
dotnet run --project src/Cna.ExerciseRunner/Cna.ExerciseRunner.csproj -- \
maneuver run --manifest scenarios/maneuvers/rules-lab.breakdown-truck.serial.v1.json \
--artifact-root artifacts/exercisesThe intelligence gateway currently reports that no model provider is configured and its decision
and narrative RPCs return gRPC Unavailable. The Decision Worker is a service-discovery/client
scaffold; it does not yet dispatch live campaign decisions or execute fallback policy. This is
expected because model-backed commanders are outside the pre-alpha gameplay target. Future gameplay
integration must keep inference outside authoritative turns and use a deterministic scripted
decision whenever a model-backed service is unavailable.
Run just --list to see all available command recipes. See
CONTRIBUTING.md for the development workflow and
SECURITY.md for vulnerability reporting.
Codex-managed worktrees use .codex/environments/environment.toml to seed the repository's
Git-ignored AI Central skills and steering before a task starts. The setup expects AI Central at
$HOME/.ai-central by default; set AI_CENTRAL_HOME when the shared checkout lives elsewhere.
The seeder copies only its allowlisted AI context and does not overwrite worktree-owned files.
Sandtable separates the authoritative simulation from optional external services. The Umpire owns the game state and rules. Command and Staff choose objectives and plans. Dispatch carries orders and reports. The Chronicle records authoritative history, and the Maproom presents the campaign to players.
Command decides. Staff plans. Dispatch carries. Umpire adjudicates. Chronicle remembers. Maproom shows.
The planned intelligence path sends only redacted observations and accepts only untrusted proposals. It must never own game state, resolve rules, see hidden opposing state, or hold an authoritative Orleans grain turn open while a model responds. The current gateway and Decision Worker are scaffolds; when live decision dispatch is implemented, an unavailable model-backed service must select a deterministic scripted decision rather than fail the turn.
| Project | Responsibility |
|---|---|
Cna.Core |
Pure Umpire domain, authoritative decisions, rules, and events |
Cna.OrleansHost |
Authoritative campaign activation and grain hosting |
Cna.DecisionWorker |
External decision dispatch outside grain turns |
Cna.Intelligence.Contracts |
Versioned protobuf and generated gRPC contracts |
Cna.Intelligence.Gateway |
Non-authoritative model/provider gateway |
Cna.ServiceDefaults |
Shared discovery, resilience, health, and telemetry defaults |
Cna.AppHost |
Aspire development orchestration |
Cna.ExerciseRunner |
Local deterministic single-Exercise, serial-unpaired, and optional serial-paired Maneuver orchestration with trusted artifacts |
site |
Static project website for developers and prospective players; non-authoritative and separate from Maproom |
Cna.Core.Tests |
Deterministic Umpire unit tests on xUnit v3 and MTP |
Cna.ExerciseRunner.Tests |
Exercise contracts, replay, artifact, and CLI tests on xUnit v3 and MTP |
Cna.Intelligence.Contracts.Tests |
Protobuf compatibility tests on xUnit v3 and MTP |
The current Umpire foundation is intentionally pure and in-process:
Cna.Core.Rulesowns source references, adopted-ruling metadata, the canonicalcna-1979.1ruleset hash, Initiative Ratings, and the hierarchical Land sequence catalog.Cna.Core.Randomnessowns the versioned deterministic random stream and published golden vectors used by authoritative mechanics.Cna.Core.Setupsowns recognized provenance-bearing synthetic setup fixtures; callers cannot supply free-form initiative inputs.Cna.Core.Contentowns validated immutable topology, force structure, scenario declarations, per-datum origins, canonical bytes/hash, and the original nonhistorical rules laboratory.Cna.Core.Campaignsowns internal exact-content authority, mechanic commands/events, deterministic Initiative and opening-preamble adjudication, canonical history, replay, and the public opaque authority handle/creation facade.Cna.Core.Observationsowns the Campaign Observation v1 allowlist, typed projection result, handle-based query facade, structural values, and canonical side-safe JSON writer/strict reader.Cna.Core.Actionsowns typed system/side candidates, canonical action identity, observation-only side generation, exact-audience query/submission enforcement, and side-safe receipts.Cna.Core.Exercisesowns the fresh-only opaque simulation capability, immutable trusted step evidence, strict canonical snapshot-to-checkpoint decoding, and reconstruction from its retained canonical event history.Cna.ExerciseRunnerowns deterministic controllers, bounded execution, re-adjudication, versioned Exercise/Maneuver evidence contracts, build identity, transactional bundles and reports, summaries, and CLI exits.- The sequence catalog cites the original Land Rules without embedding copyrighted rules prose or component art. Inspecting that catalog is not authoritative adjudication.
- Package versions are centralized in
Directory.Packages.props. - Shared C# and analyzer settings are in
Directory.Build.propsand.editorconfig. - Build output is isolated under
artifacts/. - CI runs restore, formatting verification, a Release build, and all MTP tests.
- Protobuf changes must preserve field numbers and reserve removed fields.
- Warnings are errors; do not suppress diagnostics without a documented reason.
- Documentation index
- Technical design
- Naming and domain vocabulary
- Campaign for North Africa source-material spike
- Commander personas spike
- Pre-alpha roadmap
- Initiative Determination research
- Initiative Determination specification
- Initiative Determination technical design
- Content Pack v1 research
- Content Pack v1 specification
- Content Pack v1 technical design
- Campaign World v1 specification
- Campaign World v1 technical design
- Observation and fog boundary research
- Reconnaissance and contact knowledge research
- Campaign Observation v1 specification
- Campaign Observation v1 technical design
- Turn-preamble action-boundary research
- Legal Actions v1 specification
- Legal Actions v1 technical design
- Player intent input and Needle feasibility research
- Player Intent Composer v1 proposed specification
- Player Intent Composer v1 proposed technical design and delivery plan
- Operation-Stage Preamble research
- Weather Determination v1 specification
- Weather Determination v1 technical design
- Exercise Harness capability and replay research
- Exercise Harness evidence artifact research
- Exercise Harness reproducibility and pairing research
- Exercise Harness v1 specification
- Exercise Harness v1 technical design and delivery plan
- Simulator controller policy matrix evidence
- Operation-Stage Entry source and contract research
- Operation-Stage Entry v1 specification
- Operation-Stage Entry v1 technical design and delivery plan
- Reserve Designation v1 source and contract research
- Reserve Designation v1 specification
- Reserve Designation v1 technical design and delivery plan
- Movement Foundation v1 source and contract research
- Sprint 4-5 research-gate audit
- Breakdown continuity decision packet
- ZOC and Reaction interruption research
- CONTACT-001 accepted ZOC and Reaction rulings
- Combat and continual-cycle source inventory
- Combat rules and result-surface spike
- Movement Foundation v1 specification
- Movement Foundation v1 technical design and delivery plan
- Microsoft Orleans documentation
- ASP.NET Core gRPC services
- Aspire AppHost and ServiceDefaults
- Microsoft.Testing.Platform overview
No license has been selected yet. All rights are reserved until a license file is added.