Commit graph Aetheria/tests
Author SHA1 Message Date
Meta Vens
97adf07aec TurnIsClampedToOne: say that the consumers clamp too
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 17:17:49 +02:00
Meta Vens
6833f5aa7f TurnIsClampedToOne: compare against the starting heading, not the hull's own
The reference-turn assertion measured the angle between the hull and itself.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 16:35:00 +02:00
Meta Vens
b0d7ccb4f8 Pin the agent steering writes and the helm rules Soul found unpinned
Holding heading after a state stops piloting (SteeringTests, and a Minion that
loses its target), Combat leading a moving target, MoveTo's Aim and Turn in the
low-delta regime, the behind-the-hull threshold, the Turn clamp, and the hold
branch clearing a stale MovementDirection.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 16:23:56 +02:00
Meta Vens
5681e64c52 SteeringTests: pin Accelerate's thresholds, its velocity-error term and the exact-astern sign
Stryker survivors on the first run: the low-delta branches of Accelerate had no behavioural test,
the velocity error was only exercised from rest, and astern was asserted by magnitude only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 14:38:15 +02:00
Meta Vens
9beb5e9c9f SteeringTests: measure the rotation over a short window, before it can wrap
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:43:29 +02:00
Meta Vens
1458dbb676 SteeringTests: report the measured turn in the rotation test's failure
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:41:33 +02:00
Meta Vens
c86423936e Helm split, simulation: Ship.Turn is the only facing command; LookDirection becomes Aim
Ship.Update reads Turn and feeds the rotation thrusters and aether drives; it no longer reads the
look direction or snaps Direction toward it. Steering.Toward is the one law from heading to demand
(a heading astern now turns at full demand). HelmInput owns the face-the-aim state. Accelerate,
Combat and MoveTo write Turn through Steering.Toward. Entity.LookDirection is renamed Aim in the
simulation, the Unity readers and the tests. Unity player input follows in the next commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:33:20 +02:00
Meta Vens
daa9a83940 StationServicesTests: pin partial-cell armour wear and a repair fraction above the sell fraction
Armour repair is priced at fractional wear (a fraction of a cell on every cell, and a thousandth of one cell), and
gear repair is priced exactly when RepairFraction exceeds SellFraction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 04:05:50 +02:00
Meta Vens
467a50431a StationServicesTests: armour repair is priced at odd and even hull prices
An armour price one credit low survived: ceil absorbs it at the fixture's even hull price. The armour test now runs
the same wear patterns at five hull prices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 03:01:19 +02:00
Meta Vens
2ac420edec StationServicesTests: pin the repair-sell seam and the armour and gear repair prices
A price and durability sweep (1..3000 by 20, three fraction pairs) and the 360 at 7 of 20 case assert repairing then
selling never nets a credit. Armour tests wear several cells, partial and full strip, different cell values, and
check every cell is restored and the cost is the worn share of the hull price. A gear test pins the repair share at
odd and even prices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 02:08:39 +02:00
Meta Vens
0857dbe15c StationServices: repair mends armour, never costs less than the sell value it restores, and owns the buy commit
RepairCost adds the worn share of hull armour priced as that share of the hull's price, and TryRepair restores it. The per-unit-of-wear charge is the larger of RepairFraction and SellFraction. TryBuy checks credits with the same boundary as TryRepair and charges after delivery. A 100-unit ore sale pins the commodity sell scale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:47:07 +02:00
Meta Vens
1a42ac7758 StationServices.BuyPrice: the one number the station charges, which the buy path shows, checks and charges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:56:05 +02:00
Meta Vens
864bb0c6a4 StationServices tests: hulls five cells square, so a second bay has an interior cell to sit in
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:53:10 +02:00
Meta Vens
1baa89645d StationServices tests: a full first station bay does not refuse a sale; worn docking bays are mended
Kills the two survivors Stryker left in StationServices.cs: Any() to All() over the station's bays, and Concat() to Except() over the docking bays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:50:58 +02:00
Meta Vens
c82b28851a StationServices tests: a full first station bay does not refuse a sale; worn docking bays are mended
Kills the two survivors Stryker left in StationServices.cs: Any() to All() over the station's bays, and Concat() to Except() over the docking bays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:49:57 +02:00
Meta Vens
9308f71b78 StationServices tests: a single unit of seven-credit ore sells for three, rounded down
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:43:44 +02:00
Meta Vens
9651f62ad4 The run's credits are saved and seeded: SavedGame key 13, ScenarioStage.Credits, Staged.Credits
RunSave.Capture takes the credits; a scenario may set the starting amount, defaulting to the gameplay settings'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:30:32 +02:00
Meta Vens
39b6d28f3a StationServices: one engine-free owner for sell price, repair cost and the sale and repair commits
Settings gain SellFraction, RepairFraction and StartingCredits. A sale pays the price scaled by condition and moves the
item into a station bay or refuses with everything unchanged; a repair restores every durability and charges the wear,
or refuses when short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:30:31 +02:00
Meta Vens
d9f85dc639 Merge origin/master into mining: resolve five conflicts by owner, delete the belt-task machine
Mining owns belts, chunks and target picking; scenarios owns admission and run
staging; master owns ships and fire control (rule scenarios-cut.md S4).

- AetheriaStores.CatalogTypes: nine-type union, master's list plus FieldKindData, no Scenario.
- tools/AetherDb/Program.cs: both cases (ship-authoring, field-kinds), one usage string.
- Zone.cs: master's MineAsteroid dropped (mining deleted its inputs); scenarios' SettleBelts and its three calls deleted.
- RunStartTests: the two belt-task tests deleted (they read belt.Transforms and MineAsteroid).
- FireControlCut124Tests: master's strict Exact assertions; mining's CompatibleDrift allowance and its comment dropped.
- GameData/Aetheria.cc: master's pointer 70a7b0a9. This commit lacks the Asteroid field kind in the catalog, so
  TheShippedCatalogHasAPickableFieldKind fails here by design; the next commit rebuilds it.

Builds: this commit builds (verified at the end with commit 2); the catalog pin test fails at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:29:29 +02:00
Meta Vens
561a21f3b2 Mining target queries tests: the blind ship needs no tick; it has no equipment to bring online
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:20:37 +02:00
Meta Vens
9e10166c76 Mining target queries tests: press pruning pinned by per-press examined ceilings near the measured costs
A second density-equal belt size and reach, held-target presses and the reticle at three headings,
each ceiling within about 10% of the measured count; the shared ceiling drops from 1500 to 700.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:19:23 +02:00
Meta Vens
c57466a398 Mining target queries tests: tie-break across belts by field key, and nearest-first pruning from no target
Pins two Stryker survivors: Entity.Order's field comparison and DistanceKey.Bound's forward bound.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:06:30 +02:00
Meta Vens
7a01e608ba Mining target queries tests: a launcher-only ship may see a ship but picks no rock; name the press ceiling
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:49:55 +02:00
Meta Vens
793fdc8789 Mining target queries tests: pick the sensor that sees a share of the rocks in reach; report every press cost together
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:44:38 +02:00
Meta Vens
60383cf00e Mining target queries tests: brute-force order, farthest, smallest angle, cost, reach, enemies
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:38:21 +02:00
Meta Vens
8cd68f4e65 Pin that a failed start's own writes are removed: the failed starts write a record the saved run does not hold, and the open store must not keep it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 22:36:04 +02:00
Meta Vens
d44df96fb0 SeedRules scrambles the item random between the arena and staging, so the staging step's own seed is pinned
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:04:17 +02:00
Meta Vens
8a1e205cf0 A new run replaces the saved run only once it has staged; a failed start says why and leaves the saved run
Launch cleared the run store before generating, and a generation or staging failure only reached the log: the
Generating Galaxy dialog stayed up, StartGame threw, and the saved run was already gone.

RunSave.Replace runs a start with the saved run still stored: when it returns a staged run the saved run's records go,
and when it returns null or throws, only the records it wrote (the arena's orbits and bodies) go. StartGame's
new-run branch is StartScenario, chosen by PendingScenario rather than by the absence of a SavedGame; it mints into an
empty ledger, and a failed start clears CurrentGalaxy (so quitting saves nothing) and refuses on the main menu with
every failure. Launch no longer clears; a galaxy that throws is refused on the title menu. The menu offers Continue
whenever no run is live, which replaces MainMenu.InGame (cut, with its prefab value and scene override), so a
failed start can resume the saved run in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:03:50 +02:00
Meta Vens
02e7fd4b7e A fixed seed fixes every fit: RunStart seeds the run's item draws from the galaxy's seed
ScenarioStage.Generated picked from ItemManager.Random, which is clock-seeded per process and advances in play, so a
relaunch of Djinni Shakedown or Long Haul in one session gave the player a different fit; every branded lot's
workmanship and role fills came from the same clock stream, so arena gear and explicit fits varied in quality too.
Galaxy now keeps the seed it was generated at, and RunStart.GenerateArena and Stage each reseed the item manager's
random from it, one stream per step, so what runs between them cannot shift either.

SeedRules relaunches every fixed-seed scenario around a clock-free Main Galaxy launch and a scrambled item random,
and compares the galaxy (links, factions, homes, exit too), the arena down to each item's maker and workmanship, and
the staged fits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:01:17 +02:00
Meta Vens
e56af28892 Galaxy links zones along a double-precision Delaunay triangulation: the vendored float MIConvexHull dropped zones, so ~2% of galaxies threw
The vendored MIConvexHull (NIH, ported from double to float) returned triangulations that left whole sets of
interior zones with no cell at all (prelude seed 103: 22 of 64 zones; main seed 4247651650: 182 of 196). Those
zones had no link, Distance lacked them, and the constructor threw KeyNotFoundException placing the antagonist
home (prelude) or the entrance (main). Galaxy was its only consumer; Delaunay.Edges (Bowyer-Watson, double) replaces
it, and the 3,896 vendored lines go.

The three RestoredHullsTests loops that skipped seeds whose galaxy threw now require every seed to build, and the
stale comment that Galaxy mutates Faction.InfluenceDistance goes with them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 21:59:09 +02:00
Meta Vens
494d795550 Pin that generating a galaxy leaves the catalog's faction influence as authored
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:55:02 +02:00
Meta Vens
d0782a7d14 Every new run is a scenario: the script harness, the tutorial and main galaxies as scenarios, the New Game submenu and six test arenas
A Scenario is an abstract C# class compiled with the game: Generate picks the galaxy through GalaxyStage (Main or
Prelude, at the scenario's seed, the background noise drawn from the same seed), Stage places the run's first
entities through ScenarioStage (Fit, Bare, Generated, Preset, Player, Place, Cargo), which collects named failures
and admits nothing. RunStart generates the galaxy, the arena under Ambient and admits everything through Zone.Admit,
all or nothing. The aetheria.scenario record, ScenarioShip, ScenarioEntity, RunStart.Check and the null-scenario
branch are cut.

New Game opens a submenu: Tutorial Galaxy and Main Galaxy, then (editor and development builds) Djinni Shakedown,
Starved Reactor, Arcs, Duel, Launcher Angles and Long Haul, each with its brief. MainMenu.Launch is the one way into a
new run; ActionGameManager.PendingScenario carries the scenario to StartGame once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:33:55 +02:00
Meta Vens
8a0a29e0de Galaxy.IsPrelude is the one owner of whether a run is the prelude: ActionGameManager.IsTutorial and PlayerSettings.TutorialPassed are cut
IsTutorial duplicated Galaxy.IsPrelude; its readers read CurrentGalaxy.IsPrelude, and RunSave.Capture writes
SavedGame.IsTutorial from galaxy.IsPrelude with no isTutorial argument. TutorialPassed was never written and its only
reader was New Game's unreachable main-galaxy branch, which goes with it (S2 brings the main galaxy back as a
scenario). spawnturret's two identical generator branches collapse to one. Old player.cc files still load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:26:30 +02:00
Meta Vens
aca1d53e6f ship_cc: replace_visual writes ShipAuthoring's model asset and anchors, pinned to the C# keys
MODEL_ASSET_SLOT, ANCHORS_SLOT and ANCHOR_MEMBERS sit beside the other slot constants and ShipSchemaPinTests binds them
to ShipAuthoring's and ShipAnchor's [Key]s. replace_visual carries an anchor's slots past Order by Id, refuses a blank
or duplicate id, a wrong-length row and a changed ship id, and leaves the hull record and the lines alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:07:10 +02:00
Meta Vens
f98be434f0 AetherDb ship-authoring: create --like a shipped hull, and validate reads the GLB when present
ShipAuthoringStore.HullLike copies a reference hull through its MessagePack round trip and resets Name, Shape,
Hardpoints, Prefab, Schematic and Visual. 'create ... --like <name>' opens the shipped catalog read-only and refuses an
unknown or non-ship hull. 'validate' runs ReadPackage when ModelAsset names an existing file and says which it judged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:07:09 +02:00
Meta Vens
f5743cbad2 Ship packages: a thruster or radiator anchor on a mesh-less GLB node is refused at bind
ReadNodeIds is the one GLB parse and now records, per aetheria.id node, whether it carries a mesh. Bind refuses a
thruster-emitter or radiator-mesh anchor whose node has none, naming the ship and anchor (ruling
thrusters-radiators-are-meshes), so Compose and validate refuse such a package before the catalog sees it. AetherDb
'ship-authoring validate' judges the GLB when it exists (next commit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:07:08 +02:00
Meta Vens
16f7bdbfab Mining index pins: a belt region's bounds stay tight and a rock exactly at reach is found
Three tests in MiningIndexTests, no production change. RegionsStayNearTheSearchArc bounds the share
of a small search's regions that lie past reach on both sides (window widened, nearest loosened);
VisibilityBoundPrunesADimBelt bounds rocks examined against rocks in reach in a half-lit belt of
largest rocks; ARockExactlyAtReachIsFound searches from 1-300 units with reach set to a rock's exact
distance, a third of them radially outward from a belt's outermost rock. Each threshold's unmutated
and mutant values are in its comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 16:48:05 +02:00
Meta Vens
ed15d34b35 Tests: generated loadouts give every reader its hardpoint (Soul's headless probe)
Soul's scenarios-adopt probe S4 as a committed test: on generated ships,
stations and turrets every weapon, thruster and radiator holds a non-null
Hardpoint containing all its cells, and Tool gear and the hull hold none.
It pins the input the muzzle, arc, thruster-emitter and radiator readers
dereference (finding headless-reader-input).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 16:14:10 +02:00
Meta Vens
cfd9884a33 Merge master into eureka/aetheria-release-scenarios: take the ship-mounts lane
The one conflict is EntityInstance's SoundBank block, which this branch had
moved onto item.Hardpoint and ship-mounts deleted: it stays deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:41:54 +02:00
Meta Vens
9787df6f4b Tests: a full hardpoint offers no space (Stryker survivor at TryFindSpace's last return)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:35:51 +02:00
Meta Vens
a4e8e14718 Mining index: the index alone decides reach; tests pin what Stryker found loose
BeltTargets drops its own reach skip (TargetRegion.CanHold owns it) and an
empty-belt guard AsteroidBelt already makes unreachable. Tests add an
off-centre sun, whole-belt searches across the antipode, cost after time
passes, a late short step that re-keys nothing, and an entity search off the
origin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:25:32 +02:00
Meta Vens
944baa02a7 Mining index tests: fit the observer before it activates; break distinct rocks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:08:48 +02:00
Meta Vens
6a79f87a64 Mining index tests: brute-force equality, bounds, pruning and cost
The two chunk-query tests compare sets through Zone.Targets.Within.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:02:52 +02:00
Meta Vens
bba169cac5 Tests: an equipped item knows its hardpoint (Soul's P30 fixtures)
Soul's scenarios batch-4 probe P30 lived only in a session scratchpad. Its
fixtures are now tests: an L gun in an L hardpoint whose origin lies outside
it, an edge gun whose origin lies in a neighbouring radiator hardpoint,
TryFindSpace finding what ItemFits accepts (unrotated and turned), reload into
the same hardpoint, and Tool gear holding none. Three batch-4 minors are
pinned too: IsFilledBy against a cell oracle written in the test, the last-row
placement search, and billing independent of heater equip order.

The file is a part of RunStartTests, so it shares that fixture's scratch-hull
and catalog helpers instead of a second copy of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:00:00 +02:00
Meta Vens
80de88f267 Ship mounts: each weapon needs a muzzle of its own
Kills the Stryker survivor that armed every weapon with any muzzle on the ship
(the && in the per-weapon muzzle check turned into ||): a second weapon mount
with no muzzle is refused even when the first has one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:54:03 +02:00
Meta Vens
2d39c83504 Merge master into eureka/aetheria-release-scenarios: adopt the scenarios lane onto master's base
The one conflict is AetheriaStores.CatalogTypes: keep ShipAuthoring from the
ships lane and Scenario from the scenarios lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:53:29 +02:00
Meta Vens
976b711905 Ship mounts: anchors only for visible hardpoints, every role rule in Validate
ShipAuthoringStore.Validate now alone decides which hardpoints carry anchors
and which role each plays. A thruster, radiator, energy, ballistic or launcher
hardpoint needs an anchor of its mount id with role thruster-emitter,
radiator-mesh or the new weapon-mount; every other hardpoint is internal and
no anchor may take its id. A mount-role anchor must be a hardpoint's mount, a
muzzle must hang off a weapon mount, and each weapon needs a muzzle; these
checks move out of ShipModPlan.Build, which now only maps a validated pair to
slots and throws nothing itself. 'articulation' stays in the vocabulary for
pivots and is never a mount.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:39:08 +02:00
Meta Vens
23976aada7 Ship mounts: delete EquipmentHardpoints and the plan's Equipment list
The array's only reader was the dead SoundBank block in EntityInstance, which
looked up a hardpoint transform and did nothing with it. ShipModPlan.Equipment,
ShipModShips' assignment, the preview check, the FBX builder's HP.Equipment
case and its smoke assertion all fed that one dead reader. An HP.Equipment node
is now refused by the builder as an unknown hardpoint kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:34:05 +02:00
Meta Vens
83d8371e9c Mining Cut 3 tests: commit Soul's probes and the shipped field kind check
- AFirstLoadKindIsSavedFromACleanStore: FieldKinds.Ensure's kind is saved
  when the store was clean at load (ZoneData.cs:162).
- SetTargetRefusesALitChunkBeyondSight: a lit rock too far to see is
  refused (Entity.cs:345).
- TheChunkQueryMatchesBruteForce: 3000 random queries, off-origin, two
  belts, across the outer skip edge (Soul F7).
- ThePingArmIsUnchangedByTheGainExtraction: Soul's ping sweep, golden
  recorded at cb4a1dbd; kills the Sensor.cs:168 and :189 mutants.
- TheShippedCatalogHasAPickableFieldKind (Soul F2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:02:27 +02:00
Meta Vens
f88d1fc1b3 Mining Cut 3 fix: launchers do not count toward rock reach (Q12 A)
Weapon.CanMine is the one mining predicate; LockWeapon overrides it to
false. Entity.VisibleChunksInReach counts only weapons that can mine.

Tests: LaunchersDoNotCountTowardChunkReach (a launcher-only ship is offered
no rock; a gun of 200 beside a launcher of 400 is offered the near rock
only) and AnOfflineWeaponAddsNoReach (Soul F8: reach reads Active, not
Enabled).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:02:26 +02:00