Docs: align CLAUDE.md + vault to scene-split / Automation / Saves / UITK

CLAUDE.md: rewrite Bootstrap&worlds (scene split + on-demand frontend), add M7 Automation + disk-persistence + UITK HUD bullets, new build-gotchas, note new folders fit existing asmdefs. Vault: Milestones (M6 + polish pass -> Done; HUD + cleanup rows), Backlog (ConnectionUI done + cleanup notes), Home/Systems_Index dates. Add the 3 prior session logs + DR-019/020/021 + the 2026-06-06 cleanup log + screenshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 15:06:26 -07:00
parent adf78570f8
commit 8aed336340
24 changed files with 1144 additions and 17 deletions
@@ -0,0 +1,49 @@
---
date: 2026-06-05
type: session
tags: [session, m7, automation, production-chains, conveyor, persistence, netcode, determinism]
---
# Session 2026-06-05 — M7 Automation: self-running production chains (Harvester → Conveyor → Fabricator)
## Goal
Operator: *"Let us start the automation milestone."***M7 — Automation**: self-running, tick-based production chains with deterministic offline catch-up, building on the DR-014 locked structure model.
Intake decisions (AskUserQuestion):
- **Scope:** the FULL chain (Harvester → Conveyor → Fabricator), not a reduced harvester-only slice.
- **What it makes:** AUTO-GATHER EXISTING resources (no new resource ids) — the chain refines existing resources (default 2 Ore → 1 Aether) into the global ledger so setup compounds.
- **Persistence:** FOLDED IN now (SaveData → v2; player-built structures survive quit→Continue).
- (Informed re-confirm after the adversarial review:) **keep the full chain** with a deterministic conveyor; **"offline catch-up" = within-session tick math + preserved stockpile** across quit (NO wall-clock minting — honors the determinism pillar).
## Process (ultracode: workflows + adversarial verification)
- **Phases 14 (research + design):** code-graph scan + context7 API verification (NetworkTick/NetworkTime accessors, ECB singleton, server-only `IBufferElementData` stays off the wire); a 3-lens design swarm — code architect · persistence/authoring architect · **adversarial netcode/determinism/reuse critic**. The critic earned its keep: flagged the conveyor as the dominant complexity/risk, a catch-up `period=0` div-by-zero + per-tick/catch-up **double-count** footgun, the restore **tick-rebase** blocker, and the `StorageEntry` singleton-collision; all folded into the plan.
- **Phase 5:** plan approved; the two informed forks resolved (keep full chain; within-session catch-up + preserved stockpile).
- **Phase 6 (source workflow → controlled MCP apply):** a draft→critique Workflow produced the source bundle. **Incident:** the Workflow's general-purpose draft agents ignored the "return source only" instruction and raw-`Write`-wrote the 3 systems + 5 tests into `Assets/` — which **compile but get no `.meta`/test-discovery until `refresh_unity scope=all mode=force`** (logged as native memory [[raw-written-cs-needs-full-refresh]]). Recovered: kept the (high-quality, internally-consistent) agent systems + tests, authored the foundation to satisfy them, and applied everything via MCP with reconciliations — the key one: **`CyclesDue` lower-bound 0, not 1** (prevents a premature mint on a restored `remaining==0` machine), and `BuildPlaceSystem` stamps `LastProcessedTick=0` so runtime-placed machines hit `NeedsInit`.
## Done — code (compiles clean; EditMode 187→**190**)
- **Components** (`Simulation/Automation/AutomationComponents.cs`): `Harvester{byte ResourceId;int Yield;int PeriodTicks}`, `Fabricator{byte In/OutResourceId;int In/OutAmount;int PeriodTicks}`, `Conveyor{byte Direction;int PeriodTicks}`, server-only buffers `MachineInput`/`MachineOutput`, `ConveyorItem` (enableable, baked DISABLED), `RuntimePlacedTag`. The DR-014 "recipe column on `StructureCatalogEntry`" was **deliberately dropped** — dead weight; the recipe is baked on each machine component (server-only, not needed client-side).
- **Pure math** (unit-tested, byte-only): `ProductionMath` (`NeedsInit`/`CyclesDue`/`RemainingTicks`/`RestoreNextTick` — the single gated catch-up path), `ConveyorMath` (`DirOffset`/`CellKey`/**`ResolveMoves`** — deterministic + order-independent: snapshot → stable-sort by CellKey → at-most-one destination claim → stall losers no-loss), `MachineSlotMath` (byte-id deposit/withdraw/total, the non-replicated twin of `StorageMath`).
- **Systems** (`Server/Automation/`, server-only, ordered `[UpdateAfter(PredictedSimulationSystemGroup)]` chain Harvester→Conveyor→Fabricator): `HarvesterProductionSystem` (fixed-yield → its `MachineOutput`), `ConveyorTransportSystem` (pull from adjacent upstream `MachineOutput``ResolveMoves` → settle `ConveyorItem` enable-bit / deposit to sink `MachineInput`), `FabricatorProductionSystem` (input-limited recipe → GLOBAL ledger). `Tuning.MaxProductionCatchup = 600`.
- **Persistence (SaveData v2):** `StructureSave[]` + flat `StructureIoRow[]` (cooldown as epoch-independent REMAINING ticks; in-flight conveyor item inline); `SaveComponents` `PendingStructure`/`PendingStructureIo` staging buffers; **shared `SaveStructureScan.Collect`** (both autosave + quit-save scan ONLY `RuntimePlacedTag` structures → kills the two-path drift the critic flagged); `SaveWriteSystem` + `WorldLauncher` (StagePendingSave + TrySaveFromServer) extended; new **one-shot `BaseRestoreSystem`** (gates on `StructureCatalog`+`BaseAnchor`+`NetworkTime`, replays each saved structure CHARGE-FREE, refills buffers + conveyor item, re-tags, self-destructs).
- **Build wiring:** `BuildPlaceRequest` +`byte Direction` (additive scalar; RPC wire-hash shifts → single-build); `BuildPlaceSystem` stamps conveyor `Direction` (via a `ComponentLookup<Conveyor>` on the prefab) + `RuntimePlacedTag` + `LastProcessedTick=0`; `BuildSendSystem` H/F/C keys + `[`/`]` conveyor-rotate + editor statics `PlaceHarvester/Fabricator/Conveyor`.
- **Authoring + prefabs:** 3 MonoBehaviours + bakers; `StructureCatalogAuthoring` +3 rows (Harvester 20 / Fabricator 30 / Conveyor 2 Ore); `Harvester/Fabricator/Conveyor.prefab` (duplicated from `Turret.prefab` → swapped authoring; ownerless-interpolated `GhostAuthoringComponent` + mesh free) wired into the catalog in the Gameplay subscene.
## Validation
- **EditMode 190/190** (35 new automation tests): catch-up gating/clamp/no-mint/period-0-guard; conveyor Y-junction tie-break + 4-cell line + shuffle-invariance + blocked-stall; fabricator input-limit (no mint-from-nothing); SaveData v2 round-trip + epoch-independent cooldown.
- **Runtime (real netcode ServerWorld+ClientWorld, focused editor, via `execute_code`):** catalog bakes all 6 entries (T1/T5/T6 + **T2/T3/T4 machine prefabs valid**); placed a live H(18,18)→C(19,18 +X)→F(20,18) chain (RPC → cost Ore 200→148); the chain **ran end-to-end** (Harvester output flowed → Conveyor transported → Fabricator `2 Ore → 1 Aether` → ledger), **SERVER Aether == CLIENT Aether** (22, then 52 — replicated). **Quit autosaved** v2 (3 structures + rebased `RemainingTicks`); **Continue restored** all 3 at the exact cells, **charge-free** (Ore unchanged at 148), born-correct ledger, and the **restored chain resumed producing**. Console clean of errors throughout.
## Decisions
[[DR-020_M7_Automation_Production_Chains]]. Resolves the open [[Backlog]] "production replication (predicted vs server-only)" question: **server-only** — production runs in the plain server `SimulationSystemGroup`; results replicate via the existing global ledger + `PlacedStructure` ghosts, never predicted.
## Next-session intent
- **Throughput visuals** (item-on-belt): server-only machine buffers don't reach the client (clients see only `PlacedStructure.Type`); add ONE small replicated byte if live belt visuals are wanted.
- **Build-palette HUD + ghost preview** + a conveyor-facing indicator (dev `[`/`]` rotate + H/F/C keys only today).
- **Relevancy ceiling:** `RegionRelevancySystem`'s O(structures×connections)/tick scan becomes load-bearing at higher conveyor counts (DR-014 ceiling note) — batch it when counts grow.
- **Recipe depth:** multi-input fabricator recipes; fabricator→conveyor output chaining (additive — give the fabricator a `MachineOutput`); per-machine distinct meshes (machines reuse the Turret mesh as a placeholder).
- **Operator live play-through** + a real 2-build LAN run to exercise the chain under latency (single-client validated).