From 3e45ee265213b59d9c2c6f7fb127df2cd376a860 Mon Sep 17 00:00:00 2001 From: LANE-SIM Date: Fri, 17 Jul 2026 20:20:47 +1000 Subject: [PATCH] [sim] round 4 NOTES Research provable end-to-end on DATA's real tree (realtech.test.ts), not just a fixture. Cooler aura ~triples a hot generator's run. Constants exported. Reference factory ships slabs. For the orchestrator: - the demo needs one line from you: the reference build uses two gated ids so it is a post-research save now. Dispatched cold it comes up 100 draw vs 80 gen and browns out -- I watched it. referenceFactoryTech(data) names the techs; testkit.grantResearch() opens them. Proposing a dev-only {kind:'grantResearch'} command instead of importing test helpers - DATA fixed the tech bootstrap mid-round and was right to: it was circular and 0 of 24 techs were affordable at start - asic-cooler still has no coolRadius, so its aura is inert in the game - cooling cap 0.05/tick is my call; reasoning in NOTES Co-Authored-By: Claude Opus 4.8 --- fktry/lanes/LANE-SIM.md | 104 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/fktry/lanes/LANE-SIM.md b/fktry/lanes/LANE-SIM.md index 6138eae..82a9671 100644 --- a/fktry/lanes/LANE-SIM.md +++ b/fktry/lanes/LANE-SIM.md @@ -388,3 +388,107 @@ NEXT (round 4 if asked) - The Correction / parity mites (M3's enemy). - Spatial heat + `coolRadius`, if the ASIC cooler is meant to mean something. - A self-upgrading bloom recipe, if you want the codex's literal loop. + +### Round 4 — 2026-07-17 — Opus 4.8 + +SHIPPED +- **Research v1 + the v4 gating rule.** `kind:'lab'`, `setResearch`, `snapshot.research`, + the `researched` event, and gating: any id a tech's `unlocks` names is refused by + `place`/`setRecipe`/`setRecipeAt` until that tech lands; anything no tech mentions is free + forever (so data with no tech gates nothing). Labs take only packs the active tech still + needs, several labs feed one total, and research rides through save/load — as a *rule*, + not just a list, so a restored save can still build what it unlocked. +- **A real research run on DATA's own tree** (`realtech.test.ts`): ore → demuxer → quantizer + → {crime → bricks, ringing → halos} + slurry → artifact bottler → SPATIAL PACK → + archaeology lab → tech complete → a recipe that was silently refused is now accepted. + Cold start, nothing granted. That's the DoD's unlock path on real data, not a fixture. +- **Spatial cooling** (`coolRadius`): chebyshev from the footprint, auras stack by sum, + total capped at `HEAT_COOL_MAX`. Proven by measuring the actual shed rate, and a cooler in + range roughly triples a hot generator's run before it scrams (2.5× the ticks). +- **`src/sim/constants.ts`** — 12 constants exported; DATA can import truth instead of + hand-copying numbers that go stale silently. +- **Reference factory v4**: anchor-slab overflow tap → the demo now ships slabs (18 over 20k), + melt still first at tick 1248, still shipping at 20k, still **zero brownout ticks**. + `referenceFactoryTech(data)` derives which techs the layout needs, from the commands. +- Also wired: `bandwidth.capacity`, `EntityState.scrammed`, `commissionQueue` in the snapshot + literal (v5-ready). +- Verified in the browser as well as Node — identical ticks (1248 / scram 435), gating live + (`mv-extractor` refused while locked), `capacity: 900`, 23 techs unlockable, no console + errors. 65 sim tests; 318 across the repo. +- Perf: **64.7× realtime** at 3,500 entities / 6,820 belt items (0.515 ms/tick, best of 3 on + a fresh page). Round 3 measured 74.9×. Nothing I added is meaningfully per-tick — `drainLabs` + early-outs when nothing is being researched, and cooling only touches machines that can + heat — so I can't attribute the gap, and I'm not going to pretend I can. It's either + environment noise or something small I haven't found; the headless benchmark I proposed last + round would settle it. + +DECISIONS +- **Cooling cap = 0.05/tick, and the number is arbitrary but the reasoning isn't.** At 0.05 a + machine sheds a full 1.0 of heat in 20 ticks, which is already effectively instant. Past + that, more coolers buy nothing but still cost bandwidth and floor space — a stack that does + nothing reads as broken rather than generous. Retune freely; it's one constant now. +- A cooler's aura excludes itself (its own `coolPerTick` is already counted once), and the + cache is invalidated on place/remove/rotate but *not* setRecipe — auras are geometry. +- **A lab's appetite is whatever the active tech costs**, so switching targets re-ranks every + lane feeding it, and `setResearch` drops the route cache. Labs take only what the tech still + needs — a lab is not a warehouse, and packs hoarded for a tech nobody picked would strand + where no other lab could reach them. +- Switching research targets **abandons** delivered packs rather than banking them per-tech. + Packs are the cost of indecision. Say the word if you'd rather bank them. +- Completing a tech clears `active` rather than guessing a next target. +- A machine placed while some of its recipes are locked defaults to its **first unlocked** + recipe, not `recipes[0]`. +- `testkit.ts` (new, tree-shaken, imported by nothing in the app) grants research via a + save/load round-trip — the public API, not a back door. It's how a test says "this is a + late-game save" honestly. + +BLOCKED/BROKEN +- **The demo browns out, and it needs one line from you.** The reference factory uses two + gated ids (`software-decoder` ← stream-software-decoding, `assemble-gop-i-only` ← + disc-i-only-cadence), so it is a post-research save by definition now. Dispatched cold + through `__fktryBus` it comes up **100 draw against 80 gen — BROWNOUT** with no decoder, + which I watched happen on screen. `__fktryDemo` must open those techs first; + `referenceFactoryTech(data)` tells you exactly which, and `testkit.grantResearch(sim, ids)` + will do it. The alternative is a dev-only `{kind:'grantResearch'}` command — your call, + since shipping testkit into main.ts is a bit grubby. A test pins both halves of this. +- **DATA fixed the tech tree underneath me mid-round, twice, and it was the right call both + times.** When I started: no `kind:'lab'` machine existed at all, and every science pack was + made on the artifact-bottler which was itself locked behind a tech costing 10 analog-packs + — a hard circular dependency, **0 of 24 techs affordable at start**, the tree literally + unenterable. It now has `archaeology-lab`, spatial-packs craftable with zero research, and + 6 techs affordable cold. `realtech.test.ts` is the tripwire if that bootstrap ever closes + over again — it's worth keeping for exactly that reason. + - Casualty of the churn: my first pass hard-coded `mosh-reactor` as "a gated machine" and + broke when DATA un-gated it an hour later. Round 1's lesson, relearned. The real-tree + tests now *derive* a gated and an ungated machine from the data. +- `asic-cooler` has `coolPerTick: 0.02` but still no `coolRadius`, so its aura is inert in the + real game — it cools only itself, and it has no heat to shed. The mechanic is live and + tested on a fixture; DATA just needs the number. (This was my round-3 note; the field now + exists for them.) +- Vitest caches JSON imports: I spent a while chasing a "gating is broken" ghost that was a + stale `tech.json` in `node_modules/.vite` while DATA edited underneath. Worth knowing if + anyone else sees data that doesn't match disk. + +CONTRACT REQUEST +- None. v4 had everything. + +PROPOSAL +- **A dev-only `{kind:'grantResearch'; tech: string[]}` command** would let `__fktryDemo` set + up a late-game board without importing test helpers into the app, and would give UI a way to + build a "sandbox" mode later. It's the cleanest fix for the brownout above. +- The mosh reactor now needs **two** melt lanes in the reference layout, and that's a smell + worth knowing about rather than a bug: a machine pushes one item per output type per tick, + so a 3-melt craft trickles out over several ticks, and while its own lane is busy melt is + free to take any *other* rank-1 lane. Nothing is lost — it still reaches an uplink — but it + can wander into a lane meant for something else. If that ever bites somewhere it matters, + the fix is a per-item lane affinity, not more belts. +- `Sim.save/load` are hardened in v4 and `testkit` depends on the blob shape (`.research`). + If the save format ever versions past 3, testkit moves with it. + +NEXT (round 5 if asked) +- HF dust piles + mosquito swarms — the RNG is still unrolled and save/load already carries + its state, so wildlife lands without touching persistence. +- The Correction / parity mites. +- A headless perf benchmark, so the numbers above stop being anecdotes. +- Research *time* (a lab currently counts a pack the tick it lands) if you want the tech tree + to feel like an investment rather than a purchase.