Merge pull request 'Docs: the pre-scenarios new-run path brought true to the code' (#30) from eureka/aetheria-release-docs-scenarios-sweep-1 into master

This commit is contained in:
Nibu 2026-11-13 14:53:00 +00:00
commit cda870b19d
6 changed files with 84 additions and 73 deletions

View file

@ -95,7 +95,7 @@ recorded, none blocking:
`WeaponData.AmmoType` refs.
- One cache holds all three stores for the process.
- `RunSave` commits a save atomically with stable zone keys and clears the run
on New Game or death.
on death or victory (`RunSave.Replace` drops the old run once a new one has staged).
- `SavedRun`, the msgpack settings and layout I/O, `.loadout`, `SaveState`,
`SaveZone` and the importer are deleted.
- **Loadouts are authored ship presets in the catalog.** This was reworked
@ -138,9 +138,6 @@ The first Soul pass found untested all-or-nothing, availability and price
rules, weapon-group corruption, dictionary-ordered product choice, and a
premature "done". All are fixed.
Recorded, not fixed: New Game clears the previous run before generation, as the
spec says, so a generation fault loses that run.
`GameData/PlayerSettings.msgpack` entered history through `5c5c3d5e`. It holds
defaults and the username, and about 65 earlier versions are already in LFS
history, so history is left alone.
@ -651,7 +648,9 @@ After Cut 10, every runtime write is a single-store `Commit` on one cache that
holds catalog, run and player stores from first access:
- `RunSave.Commit` saves the run at wormhole arrival and quit, with stable
`SavedZone` keys.
- `RunSave.Clear` deletes every run record at New Game and at death.
- `RunSave.Clear` deletes every run record at death and victory (`ActionGameManager.EndRun`).
- `RunSave.Replace` swaps the saved run for a new one only after the new run has
staged; a start that fails leaves the saved run in place.
- The settings getter creates `PlayerSettings` on first launch, and
`SavePlayerSettings` commits it.
- `Loadouts.Save` writes loadouts to the player store, and
@ -849,7 +848,7 @@ reads a global back (Q4).
| Global | Store | Read by | Existence owned by | Missing at main menu | Missing at resume | Missing at new game |
|---|---|---|---|---|---|---|
| `PlayerSettings` | Player | `MainMenu` (name, tutorial flag), `ActionGameManager` (credits) | boot: `ActionGameManager.Awake` after `AetheriaStores.Open`, when `GetGlobal<PlayerSettings>()` is null, upserts one and flushes (Cut 10) | cannot happen after boot | same | same |
| `SavedGame` | Run | `MainMenu` (resume), `Galaxy(CultCache, SavedGame, ...)` | new game: `ActionGameManager.BeginRun()` creates the run store and writes it; `Die()` deletes the run store (Cut 10) | no run file: Resume hidden; run file without `SavedGame`: refuse to resume, log the key, New Game only | as main menu | new game deletes any run store first |
| `SavedGame` | Run | `MainMenu` (resume), `Galaxy(CultCache, SavedGame, ...)` | new run: `RunSave.Replace` writes the new run's records and removes the old run's once the scenario has staged; `EndRun` calls `RunSave.Clear` at death and victory | no run file: Continue disabled; run file without `SavedGame`: Continue disabled, log the key | as main menu | a new run keeps the saved run until it has staged |
| catalog globals | Catalog | none exist | authored data; catalog is read-only | `AetheriaStores.Open` throws naming every `[CultGlobal]` type routed to the catalog with no record | same | same |
**CultLib's role.** `[CultGlobal]` means exactly: at most one record of the
@ -1772,8 +1771,8 @@ Probes behind 8a (scratch copies; nothing committed):
Math audit:
- **Not used:** `float4x4`, `transpose`, `determinant`, `_11` names. The
`determinant` hits (`AetheriaMath.cs:98-112`, `NIH\MIConvexHull`) are locals
and comments; the `half` hits are locals. `float2x2`/`float3x3`, `int3`/`int4`,
`determinant` hits were locals and comments (in `AetheriaMath.cs` and the
vendored `NIH\MIConvexHull`, both since deleted); the `half` hits are locals. `float2x2`/`float3x3`, `int3`/`int4`,
`double2`/`double3`, `quaternion.LookRotation`, `Random` and `snoise` all
compile against CultMath.
- **Accepted by Cut 6b:** `hash`, `normalize`, `Random`, `snoise` and NaN
@ -2596,28 +2595,31 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`).
- `SavedGame` global and `savedzone-{i}` records in `run.cc`.
- `PlayerSettings` global in `player.cc`.
- Orbit and body records in `run.cc`, written by zone generation and landed by the next save.
- **Run begins:** New Game calls `RunSave.Clear(CultCache)` as its first
statement (the `MainMenu.cs:110` handler), before the `Task.Run` at `:127`
or `:154`.
- Galaxy generation writes nothing.
- Zone generation (`PopulateLevel` `:615`, then `ZoneGenerator.cs:99, 108,
200-201, 239, 253`) upserts orbits and bodies into the attached run store.
They stay staged until the next `RunSave.Commit`.
- **Run begins:** a scenario launch (`MainMenu.Launch`) generates the galaxy on a
background task and writes nothing to the run store. `StartGame` then calls
`StartScenario`, which runs arena generation, `PopulateLevel` and staging
inside `RunSave.Replace(CultCache, ...)`. The saved run's records are removed
only when staging succeeds; on failure the records the start wrote are removed
and the saved run stays.
- Zone generation (`PopulateLevel`, then `ZoneGenerator`) upserts orbits and
bodies into the attached run store. They stay staged until the next
`RunSave.Commit`, or are removed by `Replace` on a failed start.
- **Run saves:** `ActionGameManager.SaveRun()`:
- It is `if (CurrentGalaxy != null) { var (game, zones) = RunSave.Capture(CultCache, CurrentGalaxy, Zone, DockedEntity ?? CurrentEntity, IsTutorial, _actionBarSlots.Select(s => s.Save()).ToArray()); RunSave.Commit(CultCache, game, zones); }`.
- It captures the live run (`RunSave.Capture`, which writes `SavedGame.IsTutorial` from `galaxy.IsPrelude`) and commits it with `RunSave.Commit` (`ActionGameManager.SaveRun`, `:284`).
- Callers: wormhole arrival (`:605`) and `OnApplicationQuit() { SaveRun(); SavePlayerSettings(); }`.
- **Run ends:** `Die` replaces `SavePlayerSettings()` at `:1059` with
`RunSave.Clear(CultCache); SavePlayerSettings();`.
- `CurrentGalaxy` is already null (`:1058`), so a quit afterwards does not save a run.
- **Run ends:** `EndRun` (death and victory) nulls `CurrentGalaxy`, then calls
`RunSave.Clear(CultCache); SavePlayerSettings();` (`ActionGameManager.cs:1224-1232`).
- `CurrentGalaxy` is already null, so a quit afterwards does not save a run.
- **Run exists:** derived only as `CultCache.GetGlobal<SavedGame>() != null`.
- `MainMenu.ShowMain` enables Continue from it. Continue sets
`IsTutorial = saved.IsTutorial` and
`CurrentGalaxy = new Galaxy(CultCache, saved, Debug.Log)`.
- `StartGame` (`:695-741`) reads it once at the top: `null` takes the
new-run branch; otherwise it resumes from `CurrentZone`,
`CurrentZoneEntity` and `ActionBarBindings` (`:722, 723, 737`).
`CurrentGalaxy = new Galaxy(CultCache, saved, Debug.Log)`, whose `IsPrelude`
comes from `saved.IsTutorial`.
- `StartGame` (`ActionGameManager.cs:820`) branches on `PendingScenario`: set
means a new run (`StartScenario`); otherwise it resumes from `CurrentZone`,
`CurrentZoneEntity` and `ActionBarBindings` of the saved run.
- A run store that holds records but no `SavedGame` logs
`run store has no SavedGame; Continue disabled`. New Game clears it.
`run store has no SavedGame; Continue disabled`. The next scenario launch
replaces those records once it has staged.
- **Player settings:**
- The `ActionGameManager.PlayerSettings` getter returns `CultCache.GetGlobal<PlayerSettings>()`.
- When that is absent (first launch), the getter commits
@ -2651,7 +2653,7 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`).
- The cache never creates either. `AetheriaStores.Open` keeps its missing-global check catalog-only (`AetheriaStores.cs:24-29`).
- **Derived state:**
- "Run exists" is derived from the `SavedGame` global.
- `IsTutorial` is set from it on Continue and written back by `Capture`.
- `Galaxy.IsPrelude` is set from `SavedGame.IsTutorial` on Continue; `Capture` writes it back from `galaxy.IsPrelude`. No static copy exists.
- `PlayerSettings.SavedRun` is deleted, not demoted.
- **Forbidden writers:**
- `File.*` I/O for game state anywhere in `Assets\Scripts`.
@ -2660,10 +2662,10 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`).
- A second `AetheriaStores.Open` in `Assets\Scripts`.
- Any upsert of `SavedGame` or `SavedZone` outside `RunSave.Commit`.
- **Shared paths:**
- Normal and tutorial New Game both call `Clear`.
- Every scenario launch goes through `RunSave.Replace`.
- Continue and a new run's `StartGame` read the same global.
- Wormhole and quit call `SaveRun`.
- Death calls `Clear`.
- Death and victory call `Clear` through `EndRun`.
- **Deletion line:** `SavedRun`, `SaveState`, the msgpack settings and layout
I/O, `SaveLoadout`, `SaveZone` and the `SavedGame` constructor go before
`RunSave` lands.

View file

@ -10,6 +10,13 @@ probe was built with `--artifacts-path` in scratch, so this tree got no `bin`/`o
writes. CultLib was a temporary detached worktree at `a0813c6`, since removed. The probe
source is not kept; §2.8 records what it did.
Since this map, the new-run path moved: `MainMenu.Launch` starts a `Scenario` and
`ActionGameManager.StartScenario` replaces the saved run through `RunSave.Replace`
after `RunStart` stages it (`docs/scenarios-cut.md` R.9); the `IsTutorial` static is
gone (`Galaxy.IsPrelude` is the one owner) and `ItemManager` takes its seed in its
constructor. Passages below that name the old `MainMenu` new-game anchors or those
statics are rewritten to that path; the `Run` owner itself is still unbuilt.
## 0. Target
Operator, 2026-09-17: player inputs "map directly to the same entity inputs the AI
@ -107,11 +114,11 @@ All of this is Unity code:
| Concern | Anchor | Unity dependencies |
|---|---|---|
| Store composition | `ActionGameManager.cs:43-63` (static, `Application.dataPath`) | path only |
| Handoff across scene load | statics `CurrentGalaxy`, `IsTutorial` (`:96-97`), written by `MainMenu.cs:104-105,126,138,152,166`, read by `SectorMap.cs:114-310` | `SceneManager.LoadScene` (`MainMenu.cs:106,139,167`) |
| New game: clear | `MainMenu.cs:112` | none |
| New game: galaxy | `MainMenu.cs:125,148` (`UnityEngine.Random.value` background noise), `:127-141,153-169` (`Task.Run`, then `Observable.NextFrame`) | Random, UniRx main-thread scheduler |
| ItemManager | `ActionGameManager.cs:264`; RNG clock-seeded at `ItemManager.cs:20` | `Debug.Log` |
| Start / Continue | `StartGame` `:725-770`: spawn player ship `:733-744`; Continue resolves the docked child `:751-762`; action bar restore `:764-767` | renderer binding, `SectorMap` reveal |
| Handoff across scene load | statics `CurrentGalaxy` and `PendingScenario` (`ActionGameManager.cs:108,113`), written by `MainMenu.Launch` and Continue, read by `SectorMap` | `SceneManager.LoadScene` (`MainMenu.EnterGame`, `MainMenu.cs:287`) |
| New game: replace | `ActionGameManager.StartScenario` (`:855-876`): `RunSave.Replace` drops the saved run only after the scenario stages; `MainMenu` clears nothing | none |
| New game: galaxy | `MainMenu.Launch` builds a `GalaxyStage` and runs `Task.Run(() => RunStart.Generate(scenario, stage))`, then `Observable.NextFrame`; background noise and galaxy draw from `GalaxyStage.Seed`, not `UnityEngine.Random` | UniRx main-thread scheduler |
| ItemManager | `ActionGameManager.cs:309`; seed is a constructor argument, `RunStart.ItemSeed(galaxy, step)` (`RunStart.cs:99`), reseeded by `RunStart.SeedItems` | `Debug.Log` |
| Start / Continue | `StartGame` (`:820`): `PendingScenario` set runs `StartScenario` (new run, player staged by `RunStart.Stage`); otherwise Continue resolves the saved zone and docked child and restores the action bar | renderer binding, `SectorMap` reveal |
| Zone entry | `PopulateLevel` `:639-675`: generate/unpack `:643-654`; move pilot `:659-666` | `ZoneRenderer.LoadZone`, `Debug.Log` |
| Wormhole placement (a game rule) | `ZoneRenderer.cs:222-231` (`dir * Pack.Radius * GameSettings.WormholeDistanceRatio`) | lives in a MonoBehaviour |
| Warp | detect `ActionGameManager.cs:312-316`; `EnterWormhole` `:615-637`, which saves on arrival (`:635`) | `ZoneRenderer.WormholeInstances` as the wormhole list |
@ -146,7 +153,7 @@ All of this is Unity code:
(`GameSettings.cs:17`, authored `LonginusX`) and `WormholeDistanceRatio` (`:23`,
authored 0.75).
- Randomness:
- `ItemManager.Random` is clock-seeded (`ItemManager.cs:20`).
- `ItemManager.Random` is seeded by the constructor argument (`ItemManager.cs:35`); a new run's seed is `RunStart.ItemSeed(galaxy, step)`, from `Galaxy.Seed`.
- `Galaxy` is clock-seeded only when `seed == 0` (`Galaxy.cs:108,158`).
- `Zone` seeds from the zone name (`Zone.cs:54`).
- `Zone.Update` runs belt updates on `Task.Run` (`Zone.cs:144`). It is still
@ -243,7 +250,7 @@ Continue and death. There is one instance per run. It holds no Unity type.
- `GameplaySettings`, `ZoneGenerationSettings`, `PlanetSettings`;
- a `uint seed` for `ItemManager`;
- `Action<string> log`;
- for a new run, a caller-built `Galaxy` and `isTutorial`;
- for a new run, a caller-built `Galaxy` (`Galaxy.IsPrelude` says whether it is the prelude) and the staged start (`RunStart.Stage`);
- `dt` per step;
- commands from either lowering;
- `SavedActionBarBinding[]` at save, owned by the Unity action bar (the playground
@ -305,10 +312,8 @@ Continue and death. There is one instance per run. It holds no Unity type.
- `ActionGameManager`: bodies of `SaveRun`, `EnterWormhole`, `PopulateLevel`'s
simulation half, `StartGame`, `Dock`, `DoDock`'s state half, `Undock`'s checks,
`TowShip`, `Die`'s clear, and `IntroCutscene` (entirely);
- statics `CurrentGalaxy` and `IsTutorial`;
- `MainMenu.cs:104-105,112`;
- `ZoneRenderer.cs:222-231`'s wormhole construction;
- `ItemManager.cs:20`'s clock seed.
- statics `CurrentGalaxy` and `PendingScenario`;
- `ZoneRenderer.cs:222-231`'s wormhole construction.
All of these go in the same cut that adds `Run`. None survives as a fallback.
@ -318,12 +323,12 @@ Unity dependencies, each injected or cut:
|---|---|---|
| `Time.deltaTime` | `:1218` | injected: `Run.Step(float dt)` |
| `Time.time` | `IntroCutscene`, `Die` post-fx | cutscene deleted; post-fx stays in Unity, on `Died` |
| `UnityEngine.Random` | `MainMenu.cs:125,148` (background noise), `EntityInstance.cs:413-428` (loot) | noise stays in the menu as a galaxy-generation input; loot roll moves to `Zone` on `ItemManager.Random` (Cut 2); effect spread jitter (`ProjectileManager.cs:20-26`) stays visual |
| Clock RNG | `ItemManager.cs:20` | cut; the seed is a constructor argument, and Unity passes a clock-derived one |
| `UnityEngine.Random` | `EntityInstance.cs:413-428` (loot) | galaxy noise already draws from `GalaxyStage.Seed`; loot roll moves to `Zone` on `ItemManager.Random` (Cut 2); effect spread jitter (`ProjectileManager.cs:20-26`) stays visual |
| Clock RNG | `Scenario.Seed` of 0 (`GalaxyStage.SeedFrom`) | the clock seeds only the galaxy seed; every item stream derives from it through `RunStart.ItemSeed` |
| Coroutines | `IntroCutscene` | deleted (dead) |
| UniRx | `Observable.NextFrame` in the menu, `EveryUpdate` in `Die` | stay in Unity; `Run` uses C# events, and `Entity.Death` (UniRx, headless-compiled) is what `Run` subscribes to |
| `Debug.Log` | `:264`, `:657`, `MainMenu` | injected `Action<string>` |
| Scene load | `MainMenu` | stays; the handoff static becomes `ActionGameManager.NewRun : (Galaxy, bool)?`, command-only, consumed once in `Start`; null means Continue |
| Scene load | `MainMenu` | stays; the handoff static is `ActionGameManager.PendingScenario`, command-only, consumed once by `StartGame`; null means Continue |
| MonoBehaviour state | `_currentEntity`, `DockedEntity`, `DockingBay`, `TowingStation`, `Zone`, `ItemManager` | projections of `Run` |
| Barrel transforms | `EntityInstance.cs:516` -> `HardpointTransforms` | `HardpointTransforms` deleted (Cut 2); the arc is item rotation plus `FiringArc` (fork A); barrels and `ArticulationPoint` are presentation only, `GetBarrel` |
| `Physics.*` hit queries | `Projectile`, `GuidedProjectile`, `Laser`, `Lightning`, `HullCollider` subjects | deleted from damage paths; `FireControl` rolls (Cut 2) |
@ -374,7 +379,7 @@ This is subtraction first, then one new file.
- Deletes and moves:
- `ActionGameManager.cs`:
- `IntroCutscene` `:772-799` (dead).
- Statics `CurrentGalaxy` and `IsTutorial` (`:96-97`).
- Statics `CurrentGalaxy` and `PendingScenario` (`:108,113`).
- `SaveRun` body `:243-248` becomes `Run?.Save(actionBar)`. Quit (`:236`) calls it.
- `EnterWormhole` `:615-637` and the detect loop `:312-316` become
`Run.TryEnterWormhole()`. `WarpArrived` drives `SectorMap.QueueZoneReveal`.
@ -393,14 +398,13 @@ This is subtraction first, then one new file.
`Run.Died`.
- `:264` constructs no `ItemManager`.
- `Update` `:1218` becomes `Run.Step(Time.deltaTime)`.
- `MainMenu.cs`:
- Continue (`:102-107`) sets `ActionGameManager.NewRun = null` and loads the scene.
- New Game drops `:112` and sets `NewRun = (sector, tutorial)` at `:138,166`.
- `MainMenu`: already built. Continue (`ShowMain`) loads the scene with no
`PendingScenario`; `MainMenu.Launch` sets `PendingScenario` and clears nothing.
- `SectorMap.cs:114-310` reads `ActionGameManager.Instance.Run.Galaxy`.
- `InventoryPanel.cs:117-118` becomes `GameManager.Run.Board(ship)`.
- `ZoneRenderer.cs:222-231` iterates `zone.Wormholes`.
- `ItemManager.cs:20`: the seed becomes a constructor argument. Call sites: 11 in
tests, 1 in `AetherDb`, and `Run`.
- `ItemManager`: the seed is already a constructor argument (`ItemManager.cs:35`);
`Run` supplies `RunStart.ItemSeed(galaxy, step)`.
- Settings (fork S (a)):
- `StartingHullName` and `WormholeDistanceRatio` move from `GameSettings.cs:17,23` to
`GameplaySettings` (`Settings.cs:155`).
@ -412,8 +416,8 @@ This is subtraction first, then one new file.
`GalaxyZone.AdjacentZones` with the rule from `ZoneRenderer.cs:226-230`. Null galaxy
zone gives an empty array.
- New `Run.cs`: types and rules, no bodies here.
- `static Run New(CultCache, GameplaySettings, ZoneGenerationSettings, PlanetSettings, Galaxy, bool isTutorial, uint seed, Action<string> log)`
1. `RunSave.Clear`.
- `static Run New(CultCache, GameplaySettings, ZoneGenerationSettings, PlanetSettings, Galaxy, Scenario, Action<string> log)`
1. `RunSave.Replace` around steps 2-5 (the saved run goes only once the scenario has staged).
2. `ItemManager` over `RunSave.Lots`, seeded.
3. `EnterZone(Entrance)`.
4. Spawn the player ship per `:734-743`.
@ -446,7 +450,7 @@ This is subtraction first, then one new file.
child; updates `Bay.DockedShip`.
- `void Tow()`: the rule from `:891-911`.
- `void Save(SavedActionBarBinding[] actionBar)`
- `RunSave.Capture(cache, Galaxy, Zone, Station ?? Pilot, isTutorial, actionBar)`,
- `RunSave.Capture(cache, Galaxy, Zone, Station ?? Pilot, actionBar, credits)`,
then `Commit(…, ItemManager.Lots)`.
- No-op when `Ended`.
- Remembers `actionBar` for warp saves.
@ -461,7 +465,7 @@ This is subtraction first, then one new file.
| Test | Asserts | Mutation that must kill it |
|---|---|---|
| `NewRunSpawnsPilotInEntrance` | pilot is a `Ship` with `IsPlayerShip`, in `Zone.Entities`, `Zone.GalaxyZone == Galaxy.Entrance`; the run store is cleared of a prior `SavedGame` | `New` skips `RunSave.Clear`; spawn omits `Zones.Entities.Add` |
| `NewRunSpawnsPilotInEntrance` | pilot is a `Ship` with `IsPlayerShip`, in `Zone.Entities`, `Zone.GalaxyZone == Galaxy.Entrance`; the run store holds no prior `SavedGame` once the run has staged | `New` skips `RunSave.Replace`; spawn omits `Zones.Entities.Add` |
| `WarpMovesPilotAndSaves` | stepping after `TryEnterWormhole` lands the pilot in the target zone, out of the old zone's entities, with `SavedGame.CurrentZone` equal to the target index after reopen | arrival skips `Save`; `EnterZone` leaves the pilot in the old zone |
| `ContinueLandsDocked` | save while docked, reopen, `Continue`: `Station` is the saved orbital, `Pilot` is its player child | `Land` binds to the orbital itself |
| `DeathEndsAndClears` | hull death clears every run record; `Step` throws; `Save` writes nothing | `Died` handler omits `Clear`; `Ended` not set |
@ -473,7 +477,7 @@ This is subtraction first, then one new file.
- Unity batchmode has no `error CS`.
- Negative greps:
- `rg -n "RunSave\.(Clear|Commit|Capture)" Assets/Scripts --glob '!ServerShared/**'` is empty.
- `rg -n "CurrentGalaxy|IsTutorial\s*=" Assets/Scripts` is empty.
- `rg -n "CurrentGalaxy|PendingScenario" Assets/Scripts` matches only the `Run` lowering in `ActionGameManager` and `MainMenu`.
- `rg -n "new Wormhole" Assets/Scripts` matches only `Zone.cs`.
- `rg -n "new ItemManager\(" Assets/Scripts` matches only `Run.cs`.
- `rg -n "ZoneGenerator\.GenerateZone|new Zone\(" Assets/Scripts --glob '!ServerShared/**'` is empty.
@ -1161,7 +1165,7 @@ Options as mapped before the ruling:
- **Recommend (a).**
**N. Is the scene handoff static acceptable?** Low-blocking.
- (a) `ActionGameManager.NewRun : (Galaxy, bool)?`, consumed once by `Start`.
- (a) `ActionGameManager.PendingScenario : Scenario`, consumed once by `StartGame` (built this way).
- (b) `MainMenu` builds the whole `Run` on its generation thread. That moves zone
generation's run-store upserts off the main thread, and the `CultCache` threading
contract is not checked here.

View file

@ -166,9 +166,9 @@ Contradictions and corrections found in the Body:
`LoadoutTests` fixture is not: `FirstAvailableProductInKeyOrderBuildsTheSlot`
(`LoadoutTests.cs:289-312`) adds two same-maker Lamp products and reads `.Product`.
6. **`ItemManager` lives one scene load, and every run starts with a scene load.** It is
constructed in `ActionGameManager.Start` (`:264`). There is one scene, `ARPG`. New Game
and Continue both end in `SceneManager.LoadScene("ARPG")` (`MainMenu.cs:106,139,167`), and
no `DontDestroyOnLoad` exists. So a ledger held by `ItemManager` spans exactly one run.
constructed in `ActionGameManager.Start` (`:309`). There is one scene, `ARPG`. A scenario
launch and Continue both end in `SceneManager.LoadScene("ARPG")` (`MainMenu.EnterGame`,
`:287`), and no `DontDestroyOnLoad` guards the `ItemManager`. So a ledger held by `ItemManager` spans exactly one run.
7. **Aside, not this cut:** `CreateInstance(CraftedItemData, float)` mints a
`CompoundCommodity` for a `ConsumableItemData` design (`ItemManager.cs:136-141`), while
`TryActivateConsumable` casts to `ConsumableItem` (`Entity.cs:336`). This map keeps
@ -252,9 +252,11 @@ Not probed: CultCache Studio's rendering of the ledger (operator check); Unity c
`ZoneGenerator`'s staged-upsert pattern (`ZoneGenerator.cs:99-108`) is not used for
lots: the ledger is live simulation state, captured at commit like entities.
- Lifecycle: the run begins with a scene load (§1.6), whose `Start` reads
`RunSave.Lots(CultCache)`. New Game has already cleared the run store (`MainMenu.cs:112`),
so it gets an empty ledger. Continue gets the stored one. Death clears the run store
(`ActionGameManager.cs:1090`); the next run reloads the scene.
`RunSave.Lots(CultCache)`. A scenario launch has `PendingScenario` set, so `Start` builds an
empty `ProvenanceLedger` instead (`ActionGameManager.cs:312`); the saved run's records stay
in the store until `RunSave.Replace` drops them once the new run has staged
(`SavedGame.cs:247`). Continue reads the stored ledger. Death and victory end in `EndRun`,
which calls `RunSave.Clear` (`ActionGameManager.cs:1224-1231`); the next run reloads the scene.
**Branding.**
- Owner: `ItemManager.Brand(CraftedItemInstance)` -> `(Faction Maker, FactionProductData Product)`.
@ -526,7 +528,7 @@ Subtraction, plus a data rewrite.
worktrees.
Operator-only checks after Cut C:
- New Game and fly through one zone. The starting ship's items show tier colour, and the
- New Game, pick a scenario, and fly through one zone. The starting ship's items show tier colour, and the
properties panel shows Manufacturer, product name and flavour text for branded gear.
- Dock and buy an item: its brand still shows in your cargo.
- Kill an NPC and pick up loot: brand shown.

View file

@ -68,8 +68,7 @@ catalog, built a 196-zone sector galaxy from the authored `Settings.asset`, and
`47189c8a`). The commented `HaulingControllerData` union (`Behaviors.cs:179`) is
the same kind of residue.
- **No recipe, blueprint or ingredient model exists.** "Factory", "fabricat",
"assembler", "blueprint", "recipe" and "refiner" appear in no live C# outside
`NIH/MIConvexHull`.
"assembler", "blueprint", "recipe" and "refiner" appear in no live C#.
`ItemData.Manufacturer` readers: `PropertiesPanel.cs:371-372` (shows "Manufacturer",
falling back to "GameCult"), `tools/AetherDb/Program.cs:54` (census), and the
@ -83,7 +82,7 @@ All crafted instances come from three `ItemManager` overloads:
- `CreateInstance(CraftedItemData, float quality)` (`ItemManager.cs:126-142`) sets
Quality and Durability, with no product and no ingredients.
- `CreateInstance(CraftedItemData)` (`:144-160`) rolls a rarity tier with the
**time-seeded** `ItemManager.Random` (`:20`) and stores the tier's *discrete*
`ItemManager.Random` (`:22`; seeded per run from the galaxy seed by `RunStart.ItemSeed`) and stores the tier's *discrete*
Quality.
- `CreateInstance(FactionProductData)` (`:164-187`) calls the previous overload, sets
`Product`, and draws a gaussian `RoleFill` per design role. Since no role is
@ -130,9 +129,12 @@ unexecuted stubs.
`TradeMenu.Inventory = entity.CargoBays.First()` (`ActionGameManager.cs:827-829`).
- **Zones generate lazily on first entry** (`ActionGameManager.cs:643-652`,
`PackedContents ??=`) from a deterministic zone seed
(`ZoneGenerator.cs:47`: name hash xor position hash). Item *selection* follows that
seed, but item *quality* comes from the time-seeded `ItemManager.Random`. A zone is
never regenerated within a run. New Game clears the run store (`MainMenu.cs:111`).
(`ZoneGenerator.cs:52`: name hash xor position hash). Item *selection* follows that
seed, but item *quality* comes from `ItemManager.Random`, a stream seeded per run from
the galaxy seed (`RunStart.SeedItems`, steps `ArenaStep`, `StageStep`, `ContinueStep`)
and drawn in the order zones are entered. A zone is never regenerated within a run. A
new run does not clear the run store up front: `RunSave.Replace` drops the old run's
records once the new run has staged (`SavedGame.cs:247`).
- Each station carries hull, hardpoint gear, one docking bay, cargo bay, capacitor and
stock, all embedded by value. No station equips a factory; none can, because factory
designs have no product (§1).
@ -150,8 +152,9 @@ unexecuted stubs.
`FactionProductData`, `PersonalityAttribute`, `NameFile`, `InputLayout`, `Loadout`.
- Run (`:10`): `OrbitData`, `BodyData`, `SavedZone`, `SavedGame`. Written only by
`RunSave.Commit`, which does one commit, keys zones `savedzone-{i}` and removes stale
zones (`SavedGame.cs:96-111`). `RunSave.Clear` removes every run-typed record
(`:114-124`). The single-file store writes its whole view on commit.
zones (`SavedGame.cs:216`). `RunSave.Clear` removes every run-typed
record (`:242`); `RunSave.Replace` (`:247`) does the same for a new run, but only once
the new run has staged. The single-file store writes its whole view on commit.
- Player (`:11`): `PlayerSettings`.
- **Every item instance is a value** embedded in `EntityPack` (hull, equipment, bays,
cargo contents; `EntitySerializer.cs:179-196`), inside `SavedZone.Contents`. No
@ -237,7 +240,7 @@ Every stat and wear reader goes through the instance:
"F" marks a fork (§9). "D" marks a recorded default.
| Kind | Named by | Mint | Transfer / loot / sell | Consume | Zone unload / save | New Game / death | Decides |
| Kind | Named by | Mint | Transfer / loot / sell | Consume | Zone unload / save | New run / death | Decides |
|---|---|---|---|---|---|---|---|
| **Lot** (provenance node) | run-scoped `LotId` (F1) | synthesis, at the mint site's call (F3) | never moves; instances point at it (D) | synthesized inputs are consumed at synthesis and have no instance (D) | kept while reachable from any instance, route or station; GC on `RunSave.Commit` (D, from the orphan-SavedZone scar) | cleared with the run store (D) | the synthesizer, one function in `ServerShared` |
| **Lot properties** (mocked quality per role) | on the lot (F4) | rolled once at synthesis from factory quality and input qualities, seeded by lot id (F4) | immutable | n/a | with the lot | with the lot | synthesizer; stat readers only read |
@ -301,7 +304,7 @@ synthesized?** Blocks station identity, routes, stock and loot provenance.
pirated freighter's cargo should come from a station the player can fly to. The
skeleton is about 200 stations, small next to 16k instances. It demotes
`ZoneGenerator`'s station count and faction choice to reading the roster. It also
moves item quality from the time-seeded `ItemManager.Random` to seeded synthesis,
moves item quality from the per-run `ItemManager.Random` stream, which depends on the order zones are entered, to lot-seeded synthesis,
which makes the chain regenerable.
- Sub-default: stations keep no identity outside a run. Zones never regenerate within
one.

View file

@ -33,7 +33,7 @@ Compiled 2026-09-29 by Eyes from the maps on the branch. Pointers are `doc:line`
### 2b. Fresh launch (no `run.cc`, no `player.cc`)
3. **Launch to main menu.** Expect no Addressables errors, and the Groups window shows `Assets/Content` under `Default Local Group` (`addressables-cut.md:301`). `player.cc` appears and Continue is disabled (`cultcache-migration-cut.md:2746`). Proves: Addressables Cut 1, CultCache cutover. The 09-17 smoke covered the last two on the old tree; this is a cheap recheck on the new schema.
4. **New Game (tutorial).** Expect the galaxy generates and the start ship is the Longinus (`settings-globals-cut.md:498`, an expectation, not a recorded check for this stack). Expect a Zenith station with a docking bay in the entrance zone every time (`locomotion-cut.md:375`). Proves: locomotion Cut 1 station rule.
4. **New Game, then a scenario.** New Game opens the scenario picker (`MainMenu.ShowScenarios`); a development build lists modes (Terminus (Demo)), development (Tutorial Galaxy, Main Galaxy) and test arenas, a release build lists only the modes. Pick Tutorial Galaxy or Terminus (Demo). Expect the galaxy generates and the start ship is the Longinus (`settings-globals-cut.md:498`, an expectation, not a recorded check for this stack). Expect a Zenith station with a docking bay in the entrance zone every time (`locomotion-cut.md:375`). Proves: locomotion Cut 1 station rule.
5. **Addressables, "Use Asset Database".** Ships, turret and Zenith spawn; thruster and aether-drive particles show; fire an instant weapon (Autocannon) and a charged one (ChargeBlast SG); action bar icons show (`addressables-cut.md:362-366`). Proves: Addressables Cut 2.
### 2c. Flight, power and economy

View file

@ -16,7 +16,7 @@ Status: sketch for the operator to react to. Nothing here is built or canon.
## Shape
One contained tutorial run in a small prelude galaxy (`IsTutorial`,
One contained tutorial run in a small prelude galaxy (`Galaxy.IsPrelude`,
`TutorialGenerationSettings`). The player is a newly incorporated subsidiary of the
protagonist faction. Threefra, a debt-born assessor with opinions, walks them through a
"qualification module" whose checklist is theatre. The real test is how the player