Spaces:
Paused
Paused
Commit History
-
Odyssey: bound the living galaxy to 3 seed-drawn background worlds
Claude +1: Claude Opus 5Unverified signaturecreateGalaxy instantiated and simulated all 11 worlds from turn one. It now brings up the start seat plus a pseudo-random draw of BACKGROUND_WORLDS (3) others — backgroundWorldIds, keyed on the galaxy seed and the start world from its own distinctly-seeded stream, returned in fixed roster order so the background scheduler and every galaxy-wide scan read exactly as before. Which neighbours are alive is now part of what a seed means; same seed still replays the same galaxy. The rest of the roster stays DORMANT: still on the starmap, still jumpable, still a full skirmish map — built in on arrival (jumpCapital already did this for a never-visited destination) and simulating from then on like any world you leave behind. addPlanet now honours a standing claim when it builds a world in, so a dormant world the faction-spread sweep claimed flies those colours when the player finally lands on it. Three paths assumed every world's state existed, and are fixed here: - initiateJump treated a mis…b88cc9c
-
Close the guard gaps behind the last three bugs; withdraw one review finding
Claude +1: Claude Opus 4.8Unverified signatureFindings 4, 5 and 8 of docs/code-review-2026-08.md, plus a correction to 7. #8 tools/ ships to the browser but was outside the purity guard. boot.js imports tools/selfplay.js; competition.js, competitionWorker.js and playerFingerprint.js import tools/duelCore.js and tools/genome.js. So three "Node bench" files run in a browser Worker and decide the outcomes that become persisted Elo ratings, while the purity scan only ever walked engine/ and what engine/ imports — structurally identical code guarded on one side of a directory line and unguarded on the other. The review said moving the files was "simplest and better". Measuring first showed otherwise: 30+ prose references across engine/, README and docs would have had to move with them, for no safety gain. Extended the scan instead, and DERIVED the extra roots by walking out from index.html (plus the Worker entry, whose `new Worker(new URL(...))` edge no import walk can see) so a fourth file pulled into the app tomorrow is covered the…021c865
-
Tier 2c: the property and meta tests that would have caught Tier 1's bugs
Claude +1: Claude Opus 5Unverified signatureConservation of matter — the domain's defining property, asserted nowhere. Every economy test pinned a specific number at a specific site instead, which is how a completed wonder that kept eating its feed and a deposit that overfilled a hold both lived inside green suites. test/_helpers.js gains totalHoldings (treasury + every building's store/input + every freighter's freight + every worker's cargo), and two tests assert a full haul cycle moves matter without creating or destroying it. Verified by mutation: restoring either bug turns the relevant one red. Persistence coverage — the two NET round-trip tests are structurally blind to a FORGOTTEN field, since one serPlanet never writes is absent from both sides of the comparison. That is exactly how galaxy.rivalAscended shipped unpersisted. Two denylist tests now walk the live State and Galaxy shapes and require every field to be either in the payload or on an explicit transient list with a one-line reason. Verified: dropping rivalAscen…e505378 -
Tier 1, step 3: harden the save load path past the entity boundary
Claude +1: Claude Opus 5Unverified signaturecleanEntity coerces ~20 per-field cases well, and that discipline stopped exactly at the entity boundary. Three whole sub-objects reachable from an Odyssey save were written into live state verbatim, two lane invariants the runtime enforces were dropped on load, and one field was never persisted at all. Sixteen new tests, every one verified red first. A5 — galaxy.rivalAscended, the idempotency latch the code names as such, was never written to the payload (zero hits in persist.js, zero across test/). Continuing a campaign silently undid a Rival Gate ascension: with the Gate razed the "permanent" stance ceiling could never be re-applied, because checkRivalGate can only re-latch by finding a completed Gate; with it standing, the ascension event re-fired on every Continue. Autosave runs every 12 s. Additive, so no GALAXY_SAVE_VERSION bump. B1 — the diplomacy block was `{ ...createDiplomacy(), ...P.diplomacy }`, the untrusted object winning every key. engine/diplomacy.js's clamp() is the…0974cb1 -
Tier 1, step 1: make the static guards actually guard
Claude +1: Claude Opus 5Unverified signatureSix findings from docs/code-improvement-tiers.md (C1-C4, C12, C13). Each was verified red before the fix and, where the guard is new, re-verified by reproducing the bug it exists to catch. C1 — determinism.test.js fingerprinted with its own hand-rolled snapshot that had drifted into a WEAKER one than test/_helpers.js's shared entitySnapshot: it recorded only order.type, and no cargo, tier, charge, constructing flag or state.time. So a float-accumulation drift moving a hauler's cargo or a move order's destination replayed "identically". It now imports the shared fingerprint, and a new sensitivity test mutates each sim-owned field in turn and requires the fingerprint to move (red against the old snapshot on all seven). C2 — the all-worlds roster sweep ran 400 ticks, which measurably produced ZERO combat orders on all eleven worlds: an opening-only replay that could not see a divergence in combat, veterancy, wreckage or separation under pressure. Running longer doesn't fix it (the playe…9af10ec
-
Extend determinism coverage to the rival Gate's charge
Claude +1: Claude Sonnet 5Unverified signaturetest/_helpers.js's entitySnapshot now folds a wonder's `charge` into its per-building fingerprint tuple, so a charge-path float divergence (player's or a rival's) actually surfaces in a determinism comparison instead of only in the coarser rounded-count galaxy-persist checks. New determinism-roster case: two galaxies from the same seed, each with an AI-owned rival Gate mid-charge on a background world, replay byte-identical through stepGalaxy's real background-world schedule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>2f96159 -
Colony economy rework: Freight Lanes + Colony standing orders
Claude +1: Claude Sonnet 5Unverified signatureThe roadmap calls these "two halves of a single colony-economy rework" and they share the same background-scheduler plumbing in stepGalaxy/persist.js, so they land together as designed, even though each is its own mechanic: Freight Lanes (engine/galaxy.js): a galaxy.lanes array. At a Spaceport, assign parked freighters to a LANE (source -> destination, commodity filter) via createLane/assignShipToLane. Every LANE_PERIOD galaxy ticks, runLanes moves min(assigned cargoHold, filtered stock) straight from the source world's treasury to the destination's — a standing investment, not free teleportation: assigned ships are revalidated every cycle (still alive, still parked within JUMP_LOAD_RADIUS of a source Spaceport) and are excluded from stagedRiders/jumpManifestAll so they never get swept off on a jump. UI: a lane-management panel on the Spaceport selection panel (hudSelection.js) plus a read-only summary on the starmap. Colony standing orders (new engine/colonyPolicy.js): a per-planet …84220dc
-
Tier 5: group the AI controller's bookkeeping under state.ai (no behaviour change)
Claude +1: Claude Opus 4.8Unverified signatureMove the 13 flat state.aiThink / state.aiScoutId / state.aiWaveCount / … fields into a single grouped state.ai object, decluttering the top-level state (which is the shared sim world) from the AI *controller's* private scratch state. This is the safe half of the two deferred Tier-5 refactors; the entity-id-counter move was deliberately skipped (moving it per-state would reintroduce cross-planet id collisions — the current single reset-per-construct counter is correct). Kept strictly behaviour- and format-neutral: - The save WIRE shape is unchanged: serPlanet still writes `ai:{aiThink,…}` and rehydrate still reads `P.ai.aiThink`, so every existing save loads untouched — no GALAXY_SAVE_VERSION / SAVE_VERSION bump. Only the live in-memory shape nests. - The think/wave/attack-schedule fields (previously set lazily on first AI tick and read `|| 0` / `?? …`) are now initialised in createGameState, so state.ai has a complete, self-documenting shape. Values are identical to the old …f1048a5 -
Tier 5: harden the test net (roster sweep, full-state compare, static + DOM guards)
Claude +1: Claude Opus 4.8Unverified signatureAdd the coverage a no-build-step, determinism-critical codebase needs to fail loudly instead of silently shipping a white screen or a desync. - test/_helpers.js: shared full-precision fingerprints (entitySnapshot / galaxySnapshot) that capture every sim-owned fact in a fixed, order-immune field layout, plus jumpReadyGalaxy() — the recurring "poised to jump" setup. - determinism roster sweep: same-seed replays must be byte-identical on EVERY settleable world, not just ferros — each world has its own map/terrain/AI, so a nondeterminism bug could hide on one the headline test never touches. - galaxy continues-identically at FULL precision: the existing check compares a rounded, count-only fingerprint; this compares exact positions/hp/orders/ economies/stance/pressure, so an un-persisted transient that shifts the sim by an epsilon surfaces. (It did during development — an unset-vs-0 AI wave counter the engine treats identically; normalised in the fingerprint, not the sim.)…302a725