Commit graph

2,008 commits

Author SHA1 Message Date
Meta Vens
76c331e9bc Test the lot ledger, its GC, and stats reading through it
Every existing ItemManager/RunSave.Commit call site now threads a
ProvenanceLedger. Five new tests and one rewrite cover the rulings this
cut lands: a materialized ship's lots survive a real save and reload
with unchanged quality and Attributed provenance; RunSave.Commit keeps
only lots reachable from a save's packed entities, closing over
Produced.Facility/Inputs, while the live ledger keeps everything;
ProvenanceLedger's indexer and Reachable are loud on a missing lot;
matching hardpoints mint from the same lot; Evaluate/GetTier read a
lot's Quality and per-role fills; and Brand's first-in-key-order rule
is asserted directly instead of through the old Product field.

Two of these (MaterializedLotsSurviveSaveAndReload,
CommitKeepsOnlyReachableLots) currently fail: committing any EntityPack
into the run store and reopening it throws
`TypeAccessException: No hash-resistant equality comparer available
for type: CultMath.int2`, because EntityPack.PersistedBehaviors is a
Dictionary<int2, ...> and CultMessagePackSecurity registers a
collision-resistant comparer only for CultRecordRef<T>. This predates
this cut (PersistedBehaviors is untouched here) and is a CultLib gap,
not a defect in this schema; see the landing report.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 04:17:13 +02:00
Meta Vens
415f8e1152 Add the lot ledger and mint every crafted instance through it
Quality, Ingredients and Product leave CraftedItemInstance; a unit now
carries only a LotId into the run-scoped ProvenanceLedger. ItemManager
gains the one lot-minting path (CreateLot/CreateInstance(int)), GetLot,
and Brand(), which derives a maker and product from provenance instead
of a stored field. RunSave persists the ledger pruned to what the saved
zones' entities still reach; the live ledger is never pruned, so a
floor pickup collected after a save still resolves. CopyBuild is gone:
matching hardpoints now share the same lot instead of copying values.
PropertiesPanel shows the derived brand where the design's manufacturer
used to be. AetherDb's census flags duplicate (maker, design) products
and its save command checks every crafted instance's lot against a real
run store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 04:16:23 +02:00
Meta Vens
d8c4ec4dd8 Record provenance Cut A landed and verified
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:46:43 +02:00
Meta Vens
69801bbb2c Delete the re-mint path and the dead debug menu
Cut A of docs/item-provenance-cut.md. TradeMenuDebug.cs was dead (its
script GUID appears in no scene/prefab/asset and no other .cs names the
type). ItemManager.Instantiate and CreateInstance(SimpleCommodityData,
int) re-rolled quality and dropped provenance on every load; nothing
outside EntitySerializer called them once the instantiate parameter is
gone. EntitySerializer.Unpack/Restore no longer thread an instantiate
flag, so Temperature and Armor are restored unconditionally like every
other caller already got. The starting ship and spawnturret now keep
what the generator built instead of re-minting.

Verification: Aetheria.Shared, tools/AetherDb build green against
CultLib a0813c6; tests/Aetheria.Shared.Tests 29 passed (unchanged); the
four negative greps in the map are empty. Unity compile is still owed
(the editor is open on this project; batchmode was not run per
instructions).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:42:12 +02:00
Meta Vens
7425ff1be4 Map the item provenance schema cut
Imagination pass. Cut A deletes the re-mint path and TradeMenuDebug; Cut B
moves quality and product onto lots in a run-store ledger with a placeholder
origin and derived branding; Cut C removes ItemData.Manufacturer and rewrites
the catalog. N1 (Produced.Station type) defaults to a run-scoped integer id.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:38:04 +02:00
Meta Vens
b0df689d55 Record F4 as ruled: quality stored per lot per role
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:20:18 +02:00
Meta Vens
605d3af60a Record F1 as ruled: one run-store lot ledger
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:58:10 +02:00
Meta Vens
30c316a303 Record the placeholder origin and in-place factory construction rulings
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:54:48 +02:00
Meta Vens
ec1d961bef Map the item provenance substrate and its forks
Imagination pass. Body map of items, mint sites, stations, persistence and
quality readers; identity/lifecycle/authority table; schema-cut forks F0, F1,
F4 and future forks F2-F10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:45:58 +02:00
Meta Vens
130df11240 Put the provenance schema in Terminus scope and generation after it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:43:10 +02:00
Meta Vens
c25e8cefd3 Record synthesis down to mining, consumer goods and routes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:40:00 +02:00
Meta Vens
e875b08d31 Record that Terminus synthesizes provenance backwards from products
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:36:38 +02:00
Meta Vens
dbe1dd8319 Record the item provenance rulings as a target
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:35:37 +02:00
Meta Vens
bf822e9646 Record the Studio click-through and the dropped grouping features
The click-through passed with the AmmoType refs repointed and the schematic
underlay fixed. It also surfaced that the cutover dropped the Database Tools'
record grouping and drag-and-drop without recording them; CultLib's
studio-grouping cut map owns restoring them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:08:41 +02:00
Meta Vens
37f513e5dc Keep the schematic underlay under the shape grid
The port dropped the legacy drawer's FlexibleSpace, so the grid's group
stretched to the inspector width and the texture was fitted there instead.
Checked by the operator in Studio on LonginusX.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:08:40 +02:00
Meta Vens
515859cf24 Repoint the three dangling WeaponData.AmmoType refs in Studio
AetherDb dangling now reports 0 refs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 02:01:49 +02:00
Meta Vens
f9d21e28f6 Say npm publication is parked by choice, not held on a token
The cut map and postmortem read as if a cultcache-ts publish were blocked
and imminent. The operator parked registry publication for a later pass
(CultLib QUIC map, Q5 C, 2026-09-16); no token exists and none is planned.
Same facts, honest framing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 15:49:40 +02:00
Meta Vens
84e012a6b3 Write the CultCache migration postmortem
Covers the timeline, the structural delta against the ledger (including the
CultLib core size miss), the defects Soul caught that green tests passed
(29 of 32 passes found real defects), operator corrections with the context
each one lacked, incidents, and the pipeline changes carried into the Eureka
skill. The evidence comes from commits, the cut map and the session
transcript.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 17:59:26 +02:00
Meta Vens
98a0b977d0 Stop claiming spawners already materialize loadout presets
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 17:49:43 +02:00
Meta Vens
58b2769017 Record preset capture through its own cache in the cut map
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:33:50 +02:00
Meta Vens
20f0f3d775 Describe preset capture through its own cache in the target
The Loadouts section no longer says the editor opens the catalog writable. It
describes the read-only process cache, the short-lived capture cache, the
refusals for a missing catalog and a same name under another key, the console's
character refusal, and the need to reopen CultCache Studio after capturing,
since a Studio save overwrites captured presets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:32:53 +02:00
Meta Vens
d90a65a908 Stop describing a preset materializer that does not exist
LoadoutGenerator.IsAvailable's comment claimed a caller passes it to
Loadouts.Materialize. No game path materializes a preset yet. The comment now
says a spawner is to pass it, and that none does yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:32:53 +02:00
Meta Vens
d503f076e1 Capture presets through their own cache; keep the catalog read-only
Opening the process cache's catalog writable in the editor was the wrong cut.
It made catalog read-only only by convention, so a stray catalog write in play
succeeded and a later flush could land play-mutated instances in Aetheria.cc.

- The process cache opens the catalog read-only in every build again, so the
  missing-global check runs for it as it did before db83cd29. The writable
  empty-seed exemption from ab4ced0f stays for AetherDb and fixtures.
- Loadouts.Commit(catalogPath, loadout, replace) is the only preset writer. It
  opens its own short-lived cache over the catalog, writable, commits the one
  preset conditionally on its key and disposes it. No other cache or instance
  is touched. The running game sees the preset only after the catalog reloads.
  CultLib at a0813c6 allows this: a read-only single-file store takes no lock
  and holds no handle, and the writer's commit takes the exclusive sidecar
  <path>.lock and replaces the file atomically.
- Capture refuses, writing nothing, when Aetheria.cc is missing (it never
  creates the catalog), when a preset of that name exists under another key
  (CultCache does not reject duplicate names on write), or when the key holds a
  preset and replace is not given.
- The console refuses a command with any character outside letters, digits,
  spaces and hyphens instead of stripping it, so "Mk.II" can no longer become
  "MkII". capturepreset refuses a second argument other than replace, so an
  unquoted capturepreset My Ship refuses instead of saving "My".
- The capture log line says the session sees the preset after a reload, and
  that a Studio session opened earlier overwrites captured presets on save.
- Tests: capture while the process cache holds the catalog read-only leaves it
  unchanged; a missing catalog refuses and creates nothing; a same name under a
  Studio-minted key refuses, with or without replace; a game-shaped read-only
  open missing a global throws. The existing preset tests now commit through
  the catalog path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:32:52 +02:00
Meta Vens
11902b23cf Record loadouts as authored catalog presets in the cut map
The operator redefined loadouts as ship presets (variants) for spawners,
hidden from players in the MVP. The header and Q7 route now describe the
live design, and the older player-store Cut 10 text is marked as history.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:14:40 +02:00
Meta Vens
ab4ced0f53 Keep a missing catalog global loud for writable opens
Globals are owned by lifecycle, so the cache must never run without one,
however the catalog is opened. Before this, opening the catalog writable
skipped the check entirely. The editor now opens the catalog writable, so a
missing global went silent in play mode.

AetheriaStores.Open now skips the check only for a writable catalog that
has no records: a seed store being authored from nothing, as the test
fixtures do. A populated catalog is always checked, and so is a read-only
empty one. Nothing else relied on the old skip: the game has no catalog
globals, AetherDb opens the populated Aetheria.cc, and every writable test
reopen already holds its fixture global.

WritablePopulatedCatalogMissingGlobalIsLoud removes the global from a
populated catalog and checks that a writable reopen throws. It fails when
the old writable-skip condition is restored.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:13:22 +02:00
Meta Vens
0c44aacb5b Describe loadouts as authored ship presets in the target and README
The target's Loadouts section now describes catalog presets. They are
authored in Studio or captured by the editor command, and spawners
materialize them under availability, all-or-nothing, with no charge. It
keeps the weapon-group rules and records hardpoint-configuration variants as
future direction. The README no longer lists loadouts as player state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:09:56 +02:00
Meta Vens
db83cd290d Make loadouts authored catalog presets with an editor capture command
Loadouts are ship presets (variants) for spawners, not a player feature.

- Route Loadout to the catalog; the player store no longer holds it.
- Materialize takes no credits: affordability, the charge and Loadouts.Price
  are deleted, since only the player menu priced loadouts. Availability,
  key-order product choice, all-or-nothing failures and the weapon-group
  rules stay.
- Delete the InventoryPanel Save Loadout and Restore Loadout entries and
  RestoreLoadout, which also removes its docking-bay overwrite.
- The editor opens the catalog writable in the one process cache, and the
  editor-only console command capturepreset "<name>" [replace] captures the
  piloted ship. Loadouts.Commit keys a preset by name, refuses a same-name
  replace unless asked, and commits conditionally on that key. The single-file
  store then lands only that record onto the file as it is on disk. An
  unconditional commit would re-serialize every live catalog instance,
  including any that play has mutated.
- Tests: capture -> commit -> fresh reopen round-trip, explicit replace with
  no duplicate, and a preset commit that does not persist a mutated live
  Faction. The money-only tests are removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:09:43 +02:00
Meta Vens
e7dd62d02a Record the loadout ruling in the migration target
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:51:48 +02:00
Meta Vens
a786767bac Point the README at Aetheria.cc, CultCache Studio and AetherDb
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:51:43 +02:00
Meta Vens
0702e78cda Refuse non-weapon groups, fix the group count, and widen loadout price (Cut 10 fix)
Materialize now reports a weapon group index whose slot design has no
WeaponData, and a loadout with more groups than WeaponGroupCount. The ship
always gets exactly WeaponGroupCount groups, and a shorter loadout is padded
with empty groups. Both checks run before anything is built.

Price is summed as long, so the hull add can no longer wrap to a negative
price that pays the player. A price beyond int credits is simply unaffordable.

Deleted Capture's index >= 0 filter and its test. Every production writer of
WeaponGroups items (WeaponGroupAssignment, GenerateWeaponGroups, Unpack replay
of Pack, Materialize) groups only weapons, and TryUnequip removes weapons from
groups, so nothing produces an ungrouped index any more.

The Materialize comment now says a failed fit may already have advanced
itemManager.Random.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:51:37 +02:00
Meta Vens
bb3aae4998 Record Cut 10 landed and correct its negative greps
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:39:56 +02:00
Meta Vens
1cd6170d7a Decide loadout affordability in Materialize and test weapon-group unequip (Cut 10 fix)
Materialize, which already charges, now also owns affordability: when credits
are below Price it lists "cannot afford <price> credits" and builds nothing.
The restore menu's separate price < Credits check is deleted; the menu still
shows Loadouts.Price and lists Materialize's failures.

Tests: one credit short builds nothing, leaves credits unchanged and lists the
failure. A fixture gun with an InstantWeapon behavior proves TryUnequip removes
the weapon and its item from every weapon group.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:38:16 +02:00
Meta Vens
bc3ce8fc26 Pin loadout product order against the live cache's enumeration order (Cut 10 fix)
The key-order test wrote its products and then reopened the store, whose
snapshot already returned them in key order, so removing the explicit OrderBy
still passed. The products are now committed into the open cache in z-then-a
order, the test asserts that enumeration order first, and Materialize must
still pick lamp-a.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:35:16 +02:00
Meta Vens
890063b8bb Remove an unequipped weapon from its weapon groups (Cut 10 fix)
TryUnequip removed a weapon from _weapons but left it in WeaponGroups, so an
unequipped weapon could still be fired from its action-bar group and
EntitySerializer.Pack wrote -1 for it. The removal mirrors the group toggle in
WeaponGroupAssignment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:30:40 +02:00
Meta Vens
45f2a97862 Correct the CultCache migration target's status and save and legacy claims (Cut 10 fix)
Status is landed and awaiting the operator's play smoke and Studio
click-through. Quit and zone transition share the run save commit and death
uses RunSave.Clear. The importer was deleted in Cut 10, so the target states
that no legacy reader exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:29:58 +02:00
Meta Vens
89667ca4e7 Offer Save Loadout only for a displayed ship (Cut 10 fix)
The option was added for any displayed entity, stations included, and a null
displayed entity threw when chosen. It is now added only when the displayed
entity is a Ship, the same conditional shape as the Restore Loadout guard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:29:58 +02:00
Meta Vens
61fc863e6b Stop loadouts from saving or trusting dangling weapon-group indices (Cut 10 fix)
Entity.TryUnequip does not clear WeaponGroups, so Capture saved -1 for a
grouped item that was no longer equipped, and Materialize later threw
IndexOutOfRangeException after every other check passed. Capture now skips
group items that are not equipped. Materialize reports every weapon-group index
outside the loadout's slots as a failure before building anything, so a stale
or hand-edited record builds nothing and charges nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:28:24 +02:00
Meta Vens
5e5c304e37 Make loadout availability a port and move the charge into Materialize (Cut 10 fix)
Materialize takes isAvailable as a Predicate<FactionProductData>; the restore
menu passes LoadoutGenerator.IsAvailable for the docked station, so generation
and loadouts still share one availability rule. Candidate products are ordered
by record key, so "first available product" no longer depends on dictionary
order. Materialize charges Price through ref credits only when it returns a
ship; RestoreLoadout no longer subtracts on its own.

Tests: a slot that resolves but does not fit builds nothing, charges nothing and
is listed; Price is the sum of design prices and is charged on success; the
first available product in key order builds a slot, a later one is used when
the first is unavailable, and none available fails the slot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:27:03 +02:00
Meta Vens
453ee9fba2 Mark the CultCache migration target done (Cut 10)
docs/cultcache-migration-target.md's status names the Aetheria range: Cut 8a
(4f4beb0f) through Cut 10 (4a545469 to this commit) on
codex/cultcache-cutover. The cut map's status header is left for the root
pass that records Cuts 9 and 10.

Builds: docs only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:09:39 +02:00
Meta Vens
1951b39a95 Restore the schematic-shape drawer's texture, aspect and hardpoint tints (Cut 10)
On Studio 1.3.1, drawers are handed the owning record read-only as
CultInspector.Record. InspectableSchematicShapeDrawer reads the item from it
and restores what the Database Tools drawer did (d3db1730,
AetheriaInspectors.cs ShapeSchematicInspector):
- the item's schematic texture drawn under the toggle grid;
- the height derived from the texture's aspect when a texture exists;
- hull hardpoint cells tinted with HardpointData.TintColor.

The drawer never writes to the record. The comment saying these waited on
the Studio exposing the open record is gone.

Verified by the Unity batchmode compile (no error CS). The visual check is
in the operator's Studio click-through.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:09:38 +02:00
Meta Vens
65a007e509 Seed zones from a stable name hash instead of string.GetHashCode (Cut 10)
Closes the 8a follow-up. string.GetHashCode is stable on Mono but randomized
per process on .NET Core, so a headless sim that generates zones would get
different zones on every run.

- Extensions.StableHash folds a string's UTF-8 bytes through CultMath's pcg
  from the FNV-1a offset basis. No new CultMath API.
- ZoneGenerator seeds from `Name.StableHash() ^ pcg3d(Position).x`.
- Zone seeds from `Name.StableHash() ?? 1337u`. CultMath's Random maps
  seed 0 to its default, and the abs/Convert.ToUInt32 pair that threw on
  int.MinValue is gone.

Old runs are discarded, so a different galaxy per seed costs nothing.

Tests: StableHashIsNotProcessRandomized pins "Adrasteia" to 2427892944, the
value an independent Add-Type transcription of CultMath's pcg produced. It
fails with GetHashCode substituted back in.

Builds: headless, 15 tests pass, Unity batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:09:37 +02:00
Meta Vens
00f62acc34 Make loadouts player-store design documents built all-or-nothing (Cut 10)
Loadout.cs owns loadouts: the document, capture, save and materialization.

- Loadout ("aetheria.loadout", player store) holds a hull design ref, and
  per slot a hull cell, a rotation and an EquippableItemData design ref,
  plus weapon groups as slot indices. It names no product, manufacturer,
  unit roll, cargo, faction, position or behaviour state.
- Loadouts.Capture records the hull design and one slot per equipped item
  (gear, cargo bays, docking bays). Entity.Equipment also holds the hull's
  own unit (MapEntity adds EquippedHull); that is Loadout.Hull, not a slot.
- Loadouts.Save is the only writer: one Commit to the player store, reusing
  the existing key for the name.
- Loadouts.Materialize is the only builder of a ship from a loadout. For
  the hull and each slot in order it resolves the design and takes the
  first product in catalog order that LoadoutGenerator.IsAvailable (now
  public) accepts, with no any-manufacturer fallback. Every failing slot is
  listed; units are built only after everything resolved, and any resolve
  or fit failure returns null with no ship, no charge and no write.
- Loadouts.Price is the hull design's price plus each slot design's price.
- InventoryPanel: Save Loadout asks for a name (default: the ship's name)
  and saves the capture. Restore Loadout, shown when docked with saved
  loadouts, lists each with its price, debits credits only after
  Materialize succeeds, then docks the ship as before; a failure opens
  "Loadout cannot be built here" with one line per failing slot.

Tests: new LoadoutTests (3): LoadoutRoundTripsThroughAFreshCache,
LoadoutHoldsNoRunOrGalaxyRefs, MissingDesignReports. Each fails with its
rule mutated out. The fixture hull is 3x3, not the spec's 2x2:
HullData.InteriorCells is Shape.Shrink(), so a 2x2 hull has no interior
cell a cargo bay can occupy.

Builds: headless, 14 tests pass, Unity batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:06:06 +02:00
Meta Vens
95e164adce Land RunSave and the one-cache run and player lifecycle (Cut 10)
Owner: ActionGameManager composes the process's one cache. Its CultCache
getter attaches the catalog, GameData/run.cc and GameData/player.cc on
first access, in either scene, and nothing reopens it.

- RunSave (SavedGame.cs) replaces the SavedGame constructor:
  - Capture builds the live run as plain documents and writes nothing. Zone
    contents are `zone.Contents?.PackZone() ?? zone.PackedContents`, so a
    zone generated earlier but not loaded this session keeps its contents
    and its orbit and body records instead of being erased by the next save.
  - Commit is the only writer of SavedGame and SavedZone: one Commit with
    zone i at `savedzone-{i}`, SavedGame.Zones set to those refs, and every
    stored SavedZone outside that set removed. Orbits and bodies staged by
    zone generation land in the same single-file write.
  - Clear removes every run record in one Commit.
- Run begins: New Game's first statement is RunSave.Clear. Run saves:
  ActionGameManager.SaveRun at wormhole arrival and quit. Run ends: Die
  clears the run, then saves settings.
- Run exists only as the run store's SavedGame global: MainMenu enables
  Continue from it (and logs when the run store holds records but no
  SavedGame), and StartGame reads it once to pick the new-run or resume
  branch.
- PlayerSettings: the getter returns the player store's global and, on
  first launch, commits GetDefaultPlayerSettings; it is the only creator.
  SavePlayerSettings commits the instance.
- InputDisplayLayout reads its InputLayout from the catalog by the layout
  asset's name and throws when the catalog has none.

Tests: new RunSaveTests (5): RepeatedSavesKeepRecordCountConstant,
SaveRemovesZonesNoLongerInTheRun, SaveWritesOnlyTheRunStore,
ResumeThenSaveKeepsUnloadedZoneContents, ClearRemovesEveryRunRecord. Each
fails with its rule mutated out.

Builds: headless, 11 tests pass, Unity batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:00:27 +02:00
Meta Vens
3f9bb66346 Untrack the local PlayerSettings.msgpack the previous commit swept in
The previous commit replaced the ignore line for GameData/PlayerSettings.msgpack
with run.cc and player.cc, and `git add -A` then picked up the operator's local
settings file. Q10-2 A discards that file; it was never tracked before. This
removes it from the index only, so `git ls-files GameData` matches Cut 9 again.
The working copy is left for the operator to delete.

Builds: headless. Unity does not build yet (see the previous commit).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:53:48 +02:00
Meta Vens
5c5c3d5e19 Delete the old run, settings, layout and loadout authorities (Cut 10)
The deletion line lands before RunSave, as the spec orders. Deleted, not
demoted:
- PlayerSettings.SavedRun (Key 1 stays unclaimed) and the SavedGame
  constructor that upserted a fresh SavedZone per zone on every save.
- ActionGameManager: the PlayerSettings.msgpack getter, file path and
  writer; the .loadout format (_loadoutPath, Loadouts, SaveLoadout and its
  default-options serializer, the commented loader); OnApplicationQuit and
  SaveState; SaveZone, which had no caller.
- MainMenu's SavedRun Continue branch and both `SavedRun = null` writes.
- InventoryPanel's Save Loadout and Restore Loadout bodies.
- InputDisplayLayout's KeyboardLayouts file reader, ParseJson,
  AssociateInputKeys, SaveLayout and the usings they alone needed.
- AetherDb's Cut 9 importer (Import.cs, legacy-census, import).
- The three-gates note on loading writes; Cut 3 made loading non-writing.
- .gitignore ignores GameData/run.cc and GameData/player.cc instead of
  PlayerSettings.msgpack.

DOES NOT BUILD in Unity: ActionGameManager, MainMenu and InputDisplayLayout
still reference the deleted members until the next commit wires RunSave,
the settings getter and the catalog layout read. Headless builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:51:10 +02:00
Meta Vens
aa05a99617 Generalize clear-boss-hulls into dangling and clear DemandProfile refs (Cut 10 step 2)
AetherDb's one-off boss hull command becomes `dangling`: it walks every
catalog record's CultRecordRef members by reflection (plain refs, list and
array elements, ref-keyed dictionary keys, nested [MessagePackObject] and
[Union] values), prints each ref that resolves to nothing as
`<record> <DeclaringType.Member> -> <key>`, and with `clear <Member>` unsets
those refs or removes those dictionary keys. Dry run unless `apply`, which
alone opens the catalog writable and lands every changed record in one
Commit. Faction.BossHull stays clearable through it.

Ran `dangling clear CompoundCommodityData.DemandProfile apply` (operator
ruling, option B): 3 keys removed, 2 on Mouth Adapting Gummy Molars and 1 on
Neural Lace, pointing at the deleted Conscientiousness and Neuroticism
attributes. `dangling` now lists exactly the three WeaponData.AmmoType refs
(DeathCluster, FastBlast+-, pretty pretty bang bang), left for the operator's
Studio click-through. census, factions and hardpoint-fit are byte-identical
to the Cut 9 captures. The commit rewrote Aetheria.cc in 1.0.59's canonical
unset-ref form.

Builds: headless.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:47:40 +02:00
Meta Vens
4a5454695f Pin CultLib 1.0.59 and Studio 1.3.1 (Cut 10 step 1)
CultLibRevision moves to a0813c6, the commit tagged cultlib-unity-v1.0.59
and caching-unity-v1.3.1. The manifest and lock follow. 1.0.59 writes an
unset CultRecordRef as "" instead of a nil map key and still reads nil, so
Aetheria.cc opens unchanged.

Builds: headless Aetheria.Shared and AetherDb, 6 tests pass, Unity
6000.3.24f1 batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:43:12 +02:00
Meta Vens
9e8b5ee2ea Make loadouts design-only and settle Cut 10's open rulings
Operator rulings:
- A loadout stores item designs only, with no manufacturer or product.
- Restoring one picks the first available product of each design under the
  generation rule, charges the sum of design prices, and is all or nothing.

Cut 10 starts by pinning the CultLib 1.0.59 correction release. It then
generalizes clear-boss-hulls into one dangling-ref command that clears the
two DemandProfile refs, leaving the three AmmoType refs for the Studio
click-through.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:31:47 +02:00
Meta Vens
e3af23fa5b Record Cut 9 landed and correct its dangling-ref pass rule
Soul decoded the legacy file on its own and confirmed the six dangling refs
were authored breakage: records deleted before 285b5771. The spec's rule,
which required them to equal factions' DANGLING rows, was wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:23:20 +02:00
Meta Vens
70fbaca1ed Import the legacy catalog into GameData/Aetheria.cc (Cut 9)
AetherDb gains legacy-census and a one-shot import (tools/AetherDb/Import.cs,
deleted by Cut 10). The import rewrites each legacy [tag, payload] record by
the target type's [Key] shape: slot 0 Guid becomes the record key and nil,
CultRecordRef members and DatabaseLink wrappers become D strings, the all-zero
Guid becomes nil, StatModifierData.RequireBehavior keeps the simple type name.
All 180 records land in one Commit; a second import refuses.

InputLayout moves to the catalog (Q9-1 A), with the test fixture seeding it
while the catalog is writable. GameData/*.cc is LFS, GameData/*.lock ignored.
The legacy msgpack and ansi104.json sources are removed.

Imported: SimpleCommodityData 13, CompoundCommodityData 51, GearData 25,
HullData 3, NameFile 12, Faction 12, PersonalityAttribute 3, CargoBayData 4,
DockingBayData 1, WeaponItemData 18, FactionProductData 37, InputLayout 1.
Six refs dangled already in the legacy data and are preserved as authored.

The Key(0) precondition checks only the Guid-slotted tagged types; InputLayout
is imported bare and keeps its Key(0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:11:06 +02:00