Commit graph Aetheria/tools/AetherDb/Program.cs
Author SHA1 Message Date
Meta Vens
54cfe9d4ba Cut 1 fix batch: delete fix-loco1 now that its records have landed
Same pattern as restore-hulls itself: the one-shot command's carrying cost is
zero once it has run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:40:08 +02:00
Meta Vens
dd4375801c Cut 1 fix batch: Soul's catalog findings (Djinni asset refs, thruster curves, ThermalResilience, legacy keys)
Landed via `dotnet run --project tools/AetherDb -- fix-loco1 apply`, then deleted the command in
the same batch (Cut 9/Cut 1 precedent). Fixes, each against the decoded 2021-04-14 legacy record
or a named catalog precedent:

- Djinni.Prefab was a fabricated/truncated GUID; corrected to Djinni.prefab.meta's own GUID.
- All five restored thrusters' ParticlesPrefab (null) -> Thruster 1.prefab's GUID, the same one
  Large Drive uses (legacy record names the same prefab path for all of them).
- All five thrusters' invented OptimalTemperature/PlateauWidth (300/100) -> Large Drive's own
  200-400 precedent, 251/24 (docs/stats-power-cut1-migration.md).
- ThermalResilience: Medium Drive/Small Drive -> 10, Victoire/Talaria/RevvITup 2.0 -> 15 (legacy
  record). Victoire's Durability 100 -> 30 (legacy). Victoire and Medium Drive's legacy
  descriptions restored (Talaria/RevvITup 2.0's legacy descriptions are the literal placeholder
  "[TODO]" and are not).
- Djinni.Schematic (null) -> djinni_schematic_transparent.png's GUID, already in the tree, unused.
- Djinni's OptimalTemperature 250 -> 251, correcting a rounding slip in restore-hulls's own
  "apply LonginusX's optimal-fraction to Djinni's band" derivation ((275.15-173.15)/400 = .255 of
  band applied to Djinni's 200-unit band rounds to 251, not 250).
- All seven restored records (Longinus, Djinni, five thrusters) re-keyed from freshly minted GUIDs
  to their own legacy GUIDs, decoded directly from GameData/Legacy/AetherDB.2021-04-14.msgpack,
  matching the Cut 9 import precedent (tools/AetherDb/Import.cs, git history). Each record's own
  FactionProductData.Design ref repointed at the new key.

Verified: dry run then apply, second apply refused (Longinus already carries its legacy key),
`dangling` reports 0, `census` still names both hulls, `loadout` generates every hull cleanly
across seeds 1-5.

Re-keying changed GetAll<GearData> enumeration order, which
RestoredHullMovesAndTurnsUnderMovementAndLookDirection's design-selection (thrusterDesigns.First())
depended on implicitly: it started landing every Djinni thruster hardpoint on Victoire, the one
restored thruster with a real EnergyUsage draw, and the fixture ship carries no reactor. Fixed by
equipping the fixture ship's own Reactor hardpoint, which every restored hull actually has, instead
of relying on incidental unpowered-item ordering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:38:44 +02:00
Meta Vens
7ca2f64f43 Cut 1 fix batch: revert stray blank-line deletion in Program.cs
The Cut 1 restore-hulls command deletion also dropped a blank line separating
FitCommand from the dangling-refs command block. Restore it so the file is
byte-identical to base (git diff against pre-Cut-1 now empty).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:15:19 +02:00
Meta Vens
819bd6b8b9 Cut 1: delete restore-hulls now that its records have landed
Same contract Cut 10 applied to the Cut 9 importer: a one-shot restore
carries zero ongoing cost once its records are in the catalog. The
authored-choices review list this command printed lives in the cut's
report, not in source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 16:36:28 +02:00
Meta Vens
3cb6b1546e Cut 1: add the restore-hulls command (docs/locomotion-cut.md)
One-shot restore of Longinus, Djinni and their five thruster designs from
the decoded 2021-04-14 legacy record, in the shape of the existing
*-migrate [apply] commands: dry run by default, writes every record in one
Commit, refuses a second apply. Longinus's scalar fields and ReflectorData
come from LonginusX (confirmed byte-identical against the decoded legacy
record); its hardpoint layout is authored directly from the legacy decode,
since LonginusX's own interior was rearranged to fit its AetherDrive.
Djinni is authored entirely from the decode (no live twin exists).

Every legacy PerformanceStat's [Min, Max, HeatExp, DurabilityExp,
QualityExp] is translated into today's Min/Max/Terms shape, never copied.
Authored post-breach fields (roles, FactionProductData, PowerSupply terms,
FiringArc) are covered in the command's own header comment for operator
review. Deleted in a later commit of this same cut once landed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 16:33:24 +02:00
Meta Vens
bf4744448f Add targeting-catalog-6d migration command to AetherDb tool 2026-09-19 22:20:22 +02:00
Meta Vens
dcc38af6fd Fire control Cut 6c tooling: targeting-catalog-6c migration, loadout exclude-sellers, mutation harness
AetherDb targeting-catalog-6c (dry run unless "apply"): re-authors Targeting
Computer/Fire Control Array's Resolution onto the reciprocal-reading scale
(.3->2, .75->4, matching Cut 6c.1's operator ruling) and adds a Finch
Cybernetics and a Lucent Media product for each design, alongside the
existing NiteLife ones, so a galaxy missing any one seller still has two more
chances to sell a targeting system (Cut 6c.2).

AetherDb loadout gains "exclude-sellers:Short1,Short2,..." -- the only way to
actually exercise Galaxy.ContainsFaction from this command, since the default
null-Galaxy run treats every product as available and can never reproduce the
single point of failure 6c.2 fixed. Builds a minimal one-zone Galaxy via the
same SavedGame/Galaxy round trip as FireControlCut6cTests, backed by a scratch
run store under the OS temp directory so GameData/run.cc is never touched.

Adds tests/mutation_tests_fire_control_cut6c.sh, modelled on Cut 5's harness:
no-op control, byte-exact I/O, sha256-verified restore after every mutation,
explicit tree-clean verdict.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 18:50:11 +02:00
Meta Vens
365c20d82e Fire control Cut 6a: add the targeting-catalog authoring command
Cut 2 shipped TargetingSystemData and its FireControl/LoadoutGenerator
plumbing but never authored the catalog data it needs: no targeting-system
design exists, so tools/AetherDb loadout throws InvalidLoadoutException for
the player's own hull. This adds targeting-catalog, in the shape of the
existing *-migrate commands (dry run unless "apply"), which authors:

- Two GearData designs, "Targeting Computer" (1-cell) and "Fire Control
  Array" (2-cell), each with EnergyDrawData/HeatData behaviours alongside
  TargetingSystemData (the behaviour supplies no power machinery of its own),
  argued from the capacitor (the catalog's only other bare Tool gadget).
- One product per design from NiteLife Energy, the one manufacturer that
  already sells the capacitor, so IsAvailable finds one without falling back
  to "any manufacturer".
- One product each for the four designs nothing currently sells (plight,
  pswarm, Core Power, Large Drive), matched to the manufacturer the brief
  and the corporate roster already imply.

Not yet run against the catalog; the next commit lands its output.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 16:36:00 +02:00
Meta Vens
81dbc89489 Add firing-arc-migrate: report Turret hardpoints needing FiringArc: 360
A Hands scratch console upsert, same shape as ShieldMigrate/BrownoutMigrate
(dry run unless "apply" is passed) -- follows the Cut C precedent named in
docs/fire-control-cut.md's Cut 1. Scoped to the Turret hull's own Ballistic
hardpoints, the only ones the cut names (Q1: turrets author FiringArc: 360).

Not applied here: GameData/Aetheria.cc is left untouched. Dry run against
the live catalog reports two hardpoints to migrate:

  hull             hardpoint  position     was   now
  Turret           Ballistic  (1,2)          0   360
  Turret           Ballistic  (5,2)          0   360

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 07:38:16 +02:00
Meta Vens
8bbf280756 Resolve request/brownout conflict: evaluate power requests nominally
A power request may not depend on power supply (Cut 6/F6), and continuous
consumers brown out through a power term on their own performance stats
(Cut 7). For Radiator (PumpedHeat) and AetherDrive (Torque) those were the
same stat, making six shipped catalog records illegal and leaving six
BrownoutTests cases skipped.

Resolved per the operator's ruling: a power request is evaluated
nominally -- what the item wants at full supply, not what it is currently
managing. EquippedItem.EvaluateNominalPower (mirroring ConditionRatio's
own NominalContext) pins only PowerSupplyFactor to 1; Heat/Durability
stay live, since they are not the term a request would be circular
through. Every PowerRequest/RefreshReserve/RefreshInputCapacitor
implementation now reads a StatValidation.PowerRequestFields stat through
it, so the same stat can carry a brownout curve and be a request field
without the request depending on its own answer.

StatValidation.ValidateNoPowerSupplyOnRequest (F6's static half of the
rule, forbidding the term outright) is deleted -- nominal evaluation
removes the circularity at the root instead. Only the dynamic
modifier-chain half (StatModifier.ValidateNoPowerSupplyChain) still
refuses anything, since EvaluateNominalPower forwards ScaleModifier/
ConstantModifier unchanged (real, not nominal).

Un-skips BrownoutTests' six Radiator/AetherDrive cases and adds two new
regression tests (a direct EvaluateNominalPower probe, and a two-tick
Radiator demand check) backed by a new mutation harness. Updates the four
PowerCurveTests/AetheriaStoresTests cases that pinned the now-superseded
static refusal to instead assert acceptance. GameData/Aetheria.cc is
unchanged and still validates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 06:58:57 +02:00
Meta Vens
cd47eefe9e Merge the power fixes: multiplier, active gating, honest tiers, shield repair
F1 power supply multiplies the resolved value (operator ruling), so zero
supply means zero and a flat stat still responds. F2 the bus agrees with
Active in both directions. F3 an empty tier reports no demand instead of
full supply, and sub-epsilon demand is rationed and subtracted. F4/F5 the
shield restores while inactive and CanTakeHit no longer mutates. F6/F7 the
validator names every stat a request reads and the tools validate before
writing. F8 re-anchors two dead mutation harnesses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 06:04:12 +02:00
Meta Vens
e3e228e036 F7: route AetherDb's identity-preserving repairs through the same validation
CultRecordRefs.Upsert is the one function every catalog write is supposed to
go through, but tools/AetherDb/Program.cs's Dangling, ShieldMigrate and
BrownoutMigrate commands each repair an existing record in place and must
preserve its key -- Upsert's own cache.UpsertAsync(document) cannot take a
caller-supplied key, so all three wrote raw and unvalidated through
`db.Cache.Commit(batch => batch.Upsert(document.GetType(), document, key))`.
`brownout-migrate apply` is how the shipped catalog's PowerSupply terms were
actually authored, unvalidated, the whole time.

Extracted Upsert's validation body into CultRecordRefs.Validate(object), and
call it directly from all three tool commands immediately before their own
identity-preserving commit -- the same rules, invoked where Upsert itself
cannot reach. The comment above StatValidation naming the write-bypass holes
(landed with F6) now names all four instead of two: CultCache Studio's
generic editor (still open -- not this repository's to patch) plus the three
tool commands above (closed).

Pinned in tests/Aetheria.Shared.Tests/AetheriaStoresTests.cs:
ValidateRefusesAnEquippableItemWithAZeroSpanHeatRangeTheSameWayUpsertWould and
ValidateRefusesAPowerRequestCarryingAPowerSupplyTermTheSameWayUpsertWould pin
that the extracted method actually refuses what Upsert would (fail under a
reverted Validate that is a no-op); ValidateIsANoOpForADocumentTypeItDoesNotGovern
pins that a document type it has no opinion about doesn't crash it.

Verified tools/AetherDb/AetherDb.csproj still builds clean against the pinned
CultLib worktree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 05:47:31 +02:00
Meta Vens
6d2b6e939d Cut 7: roles-migrate command and a census role-coverage check
roles-migrate declares roles on designs, points each design's own
StatTerm.Role at the role that governs it, and authors matching ProductRole
quality on every product selling a now-role-bearing design -- all through
AetherDb's own CultCache-backed types, one commit, nothing written if any
record fails to derive (same all-or-nothing contract as shield-migrate and
brownout-migrate). Field->role maps are per item kind (Weapon/Ballistic,
Weapon/Energy, Weapon/Launcher, Radiator, Reactor, Sensors, Thruster,
AetherDrive, Hull/Ship); Tool is keyed by design name since it is not a
shared kind. A stat only gets a role when it carries an unrouted
StatSource.Quality term AND still varies (Min != Max) -- Cut 1's flat
placeholder stats carry no observable role-vs-workmanship difference, so
routing one would be authoring fiction.

Product role means are deterministic generic placeholders (stable FNV hash
of product+role, not System.String.GetHashCode, which is randomized per
process and would make a dry run and the later apply disagree) flagged
"needs operator review" in the printed table, except Arctica/Alakrita's
`fins`, which item-provenance-target.md already gives a real brand identity
(heat efficiency).

census gains a role-coverage check: every sold, role-bearing design's
product must author a matching ProductRole spread, reported as "(product,
role) pairs where ... authors no matching spread" -- the gap the ruling
names directly (a newly minted lot from a product with no spread rolls the
default mean .5, silently pulling every maker toward average).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 05:01:30 +02:00
Meta Vens
e42299858c Author a PowerSupply term on the four shipped continuous-performance stats
Cut 7's gate removal (previous commit) only has anything to curve if some
shipped stat actually declares a PowerSupply term. Checked: none did --
removing the gates would have made brownout invisible (still full
performance at any nonzero grant) instead of graceful.

Added tools/AetherDb's "brownout-migrate [apply]" command (ShieldMigrate's
own dry-run/apply/report shape) and ran it against GameData/Aetheria.cc,
authoring exponent-1 (linear, the gentle default) PowerSupply terms on:

  design                behaviour        stat        before  after
  Arctica               RadiatorData     pumpedHeat    3   ->   4
  Iapyx                 RadiatorData     pumpedHeat    1   ->   2
  Large Drive           ThrusterData     thrust        2   ->   3
  OK Disperser          RadiatorData     pumpedHeat    3   ->   4
  Skiron                RadiatorData     pumpedHeat    1   ->   2
  Traction              AetherDriveData  torque        3   ->   4
  cold like my heart    RadiatorData     pumpedHeat    3   ->   4
  deep space burnout    ThrusterData     thrust        3   ->   4

No shipped ConstantWeaponData record exists yet, so ConstantWeaponData.Damage
has nothing to author against; the tool still targets it for whenever one
ships. None of the four targeted fields is a power-request field
(StatValidation.PowerRequestFields), so this does not trip
ValidateNoPowerSupplyOnRequest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 04:10:39 +02:00
Meta Vens
7d60405f32 Add shield-migrate: authors Capacity/RefillDuration/RestoreDuration for catalog shields
Catalog migration for the shield reserve ruling (docs/stats-and-power-cut.md). Scans
every GearData- and ConsumableItemData-hosted ShieldData, derives Capacity from
EnergyUsage (a per-damage-point multiplier, not an energy quantity -- capacity =
10 raw damage points x max(1, EnergyUsage) x cell count) and flat starting durations
(2s refill, 12s restore), and prints a derivation table. Dry run unless passed
"apply"; writes nothing if commit fails partway (single Cache.Commit batch).

GameData/Aetheria.cc is unchanged by this commit: the shipped catalog holds zero
ShieldData records (the pre-Cut-4 probe's 348-instance PerformanceStat table never
lists ShieldData among its owners either -- consistent with GameData/Aetheria.cc
being the post-breach bare-minimum rebuild, not the full pre-breach consumer set).
shield-migrate reports "0 shield designs" against it today and will migrate real
designs as soon as any are authored.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 02:46:38 +02:00
Meta Vens
fc1c0526fe Census: list every distinct maker, don't invent a single one
MakerOf picked the first product for a design from any maker, the same
tie-break Brand() uses to resolve a runtime item's actual attribution.
That made census silently agree with an attribution it has no business
asserting on its own. Census's job is to report what the catalog says,
including when a design has more than one seller.

MakerOf now lists every distinct maker that sells a design (via its
products, manufacturer set), in record-key order, or "(none)" when no
product sells it. The existing duplicate (maker, design) detector is
unchanged. Verified byte-identical `census` output before and after,
since today's catalog has no design with two makers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:42:37 +02:00
Meta Vens
333a73709a Cut C: delete ItemData.Manufacturer, derive census makers from products
The manufacturer does not belong to a design (operator ruling); it lives on
FactionProductData and branding is derived, never stored on the design.

- Delete ItemData.cs key 3 (Manufacturer), with a retired-key comment.
- AetherDb census now attributes a design's maker to the first product (in
  record-key order) that sells it, matching ItemManager.Brand's rule; a
  design no product sells shows "(none)".
- AetheriaStoresTests' catalog fixture moves its Manufacturer reference onto
  a FactionProductData selling the design, and FactionIsASingletonInstance
  reads it from there.
- mutation_tests.py gets a paired mutation for that fixture wiring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:03:15 +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
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
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
Meta Vens
1d15c6780d Rewrite AetherDb over AetheriaStores and CultRecordRef
Cut 8b. AetherDb.Open composes GameData/Aetheria.cc through
AetheriaStores.Open, read-only unless clear-boss-hulls runs with apply;
save attaches GameData/run.cc when present and reads the SavedGame global.

- census, factions, station-fit, hardpoint-fit, loadout, settings,
  settings-dump and clear-boss-hulls read references through the null-safe
  Get(ref) and compare identity by record key (RefOf, from TryGetHandle).
  Their output formats are unchanged so Cut 9 can compare them with the
  Cut 0 captures.
- clear-boss-hulls lands every cleared faction in one Commit.
- The help line lists every command.
- Deleted: doctor, migrate-products, AetherDb.Save(), and
  OpenWithNameFiles. The last was Cut 9's delete, but it needs the removed
  multi-file store, and NameFile now routes to the catalog.
- FindRoot looks for Aetheria.Shared.csproj; AetherDB.msgpack leaves in
  Cut 9.

It compiles. It cannot run until Cut 9 writes Aetheria.cc, so the pre-cut
captures do not apply to this cut.

Builds: Aetheria.Shared, AetherDb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:05:14 +02:00
Meta Vens
6140a06a0a Swap Unity.Mathematics usings for CultMath
Every Unity.Mathematics using, alias and qualified name under Assets\Scripts
and tools now names CultMath. The nine `using static ...noise;` lines are
gone: snoise lives on CultMath's math. UnityExtensions loses float4.ToColor
and Color.ToFloat4, which duplicate the bridge's ToColor and ToCultMath; the
float3 colour pair stays because the bridge has none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:39:12 +02:00
Meta Vens
a63aa38f00 Read authored settings from the Unity asset
A fixture that invents curve and tier values measures a game nobody plays,
so the tool reads Assets/Resources/Settings.asset, whose GameSettings holds
plain ServerShared classes, and fills them by field name. The settings
command asserts counts rather than non-null: an empty array reads as
populated, and that lie cost two rounds of parsing bugs in sequences.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 02:09:34 +02:00
Meta Vens
285b57713f Clear dangling boss hull links, and stop the tool writing on read
Eight factions pointed at one boss hull GUID that no longer resolves,
shared wreckage from the database loss. PlaceFactionsMain gives a boss zone
to every faction carrying a BossHull, so each dangling link claimed a
chokepoint that could never spawn a boss.

AetherDb.Open no longer registers the name file store. CultCache subscribes
Add to a store EntryAdded, MultiFileBackingStore.PullAll re-emits what it
loads, and Add pushes to that type store, whose Push writes a file: opening
the cache rewrote all twelve name files, 4.4 MB, on every command. They were
byte identical, and it only surfaced as an error because Unity had one of
them memory mapped. Name files now load only on request, and the scope doc
records the underlying smell.

Adds commands: factions, clear-boss-hulls, save, loadout (runs the real
LoadoutGenerator against every hull), hardpoint-fit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 02:05:33 +02:00
Meta Vens
9f9149bd2f Replace AetherDb scripts with one console project
Running loose script files caches a build per script and does not rebuild
when the referenced project changes, so scripts silently ran against stale
schemas: item-census held a binary predating FactionProductData and failed
with a TypeLoadException surfacing as a NullReferenceException elsewhere,
and station-fit last ran on a pre-role build. One project with commands
(doctor, census, station-fit, migrate-products) rebuilds through the normal
project graph, and shares one Open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 01:27:18 +02:00