diff --git a/fktry/lanes/LANE-SIM.md b/fktry/lanes/LANE-SIM.md index ffac40f..9d24acd 100644 --- a/fktry/lanes/LANE-SIM.md +++ b/fktry/lanes/LANE-SIM.md @@ -492,3 +492,115 @@ NEXT (round 5 if asked) - 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. + +### Round 5 — 2026-07-18 — Opus 4.8 + +SHIPPED +- **`grantResearch`** — idempotent, ignores unknown ids, completes the active target out from + under the labs, save/load safe. Verified through the live bus, so `__fktryDemo` can drop + `testkit` whenever you like. +- **Research takes time** — `RESEARCH_TICKS_PER_PACK = 60` (exported). Stepped: a lab spends + the full 60 ticks on a pack, then consumes it and ticks progress by exactly 1, so + `research.progress` stays integer and determinism stays trivial. Labs really do parallelise + — measured 200 ticks with two vs 260 with one on the same supply. A lab mid-pack reports + `progress` 0..1, so RENDER/UI can show it working. +- **Wildlife v1** — piles grow from dust a machine is sitting on, hatch swarms at 1.0, swarms + drift to production machinery and slow it while attached, traps can them. Deterministic, + save/load carries the lot, spawn/clear events on both. 12 tests including the design point. +- **Seams** — extractors run only while their footprint overlaps an authored seam rect; + off-seam they idle with `'no seam'`, edge-triggered like every other jam. Consumes DATA's + real `seams.json` shape (and a bare rect list), defensively — see BLOCKED. +- **THE RELIC** — one optical fossil per world, position a pure function of the seed, 18–28 + tiles out, never on a seam, never under the demo. `excavate` within a tile uncovers it and + emits `relicFound`; it stays found through save/load and 20,000 further ticks. When DATA's + seam map supplies a `relicReserve` the roll folds into that corner — verified in-browser + landing at (21,15), inside the reserve, and digging up first try. +- **Reference factory v5** — a second works on DATA's eastern seam: ore → demuxer → quantizer + → {crime → BRICKS, ringing → HALOS} + slurry → artifact bottler → SPATIAL PACK → + archaeology lab. **It researches `broadcast-phosphor-seams` at tick 1235.** Melt still first + at 1247, still shipping at 20k, **zero brownout ticks**, 179/179 placements legal, and with + seams wired **zero extractors off-seam** — both works sit on real ore. +- Verified: 99 sim tests (446 across the repo), tsc clean in my lane, and the browser agrees + with Node tick-for-tick (melt 1247, scram 434, research 1235). Perf **63× realtime** at + 3,500 entities / 6,820 belt items (0.529 ms/tick) — Round 4 was 64.7×, so all of this round + cost ~3%. (An earlier probe "timed out" and looked like a regression; it was the 30s tool + limit on a 16k-tick warmup, not the sim. Staged it and re-measured.) + +DECISIONS +- **Dust breeds from BACKED-UP dust, not from dust existing.** First cut grew piles from + whatever a machine held, and the tidy factory — dust belted straight to an uplink — still + hatched 56 swarms, because buffers are never empty between pushes. Growth is now + proportional to what sits *beyond one craft's worth* (`DUST_SPILL_GRACE`). Plumbed lines + never cross the threshold; neglected ones hit the stall cap and hatch in ~400 ticks. The + asymmetry is the mechanic — without it the hazard is just weather. + - Related, and worth knowing: my first "tidy" fixture still bred, and the mechanic was + innocent. A crusher making 4 dust per craft out-produces a single belt lane (~0.15 + items/tick) and backs up no matter how you plumb it. That's a true fact about belts. +- **`SWARM_MAX = 8`.** A permanently jammed machine breeds forever — measured 29 swarms in one + 20k demo run, which is a plague, not a hazard. At the cap, full piles just sit there. +- **Swarms only settle on production machinery**, preferring machines actually mid-craft and + falling back to jammed ones. Power plants read as permanently "running" and hoovered up + every swarm in the world to no effect — it looked exactly as silly as it sounds. The + fallback matters because the dust that bred them came from a machine that seized: without + it, a swarm evaporates at the moment it should bite. +- **Swarms slow crafting, not generation.** `swarmThrottle` is not applied to `powerGen`, so + an infestation never causes a brownout. That's my call, not the contract's — flag it if you + want mosquitoes on the grid; it would make them far nastier and would end the zero-brownout + regression. +- Traps are identified by **recipe shape** — empty inputs, outputs the canned swarm — not by a + machine id, so DATA's real trap lights up with zero code changes. A trap only progresses + while a swarm is in `TRAP_RADIUS`, and holds at full progress rather than canning air if its + prey drifts off or a neighbour beats it to the catch. +- Switching research target **forfeits the part-processed pack** in every lab, matching the + existing rule that switching abandons delivered packs. Lab intake now counts what *all* + labs are holding, so a bank of them can't collectively hoard more than the tech costs. +- **The annex is a separate works, not a tap off the melt line.** Every column between the + quantizers and the press is spoken for; threading bricks, halos and slurry through that + floorplan would have made the melt regression hostage to the science. DATA's second mdat + seam is empty ground, so the annex mines its own ore and shares only the bandwidth bus. +- Save format **v3 → v4** (wildlife, relics, lab timers). `testkit` follows it. + +BLOCKED/BROKEN +- **`GameData.seams` is not wired, so seams are inert in the actual game.** DATA shipped + `data/seams.json` mid-round (good schema, and they reserved a relic corner for me), but + `GameData` has no `seams` field and `main.ts` doesn't import the file, so nothing reaches + `sim.init`. I consume it defensively and my tests inject it. **This is the one contract + change the round needs** — see CONTRACT REQUEST. I verified in-browser what happens once + it's wired: 0 extractors off-seam, relic in DATA's reserve. Until then extractors mine + anywhere, exactly as before. +- **There is still no trap machine in the data,** so swarms cannot be cleared in the real + game. The mechanic is complete and tested against a fixture trap; DATA needs a machine + whose recipe has no inputs and outputs `mosquito-swarm`. The demo currently hatches its 8 + and keeps them. (Suggested shape in PROPOSAL.) +- The demo researches **one** tech and then idles: completing clears `active` and nothing + auto-picks a successor. That's a player/UI decision rather than a sim one, but it means + the annex jams shortly after 1235 — the bottler starves of halos (skim-ringing wants 3 + coefficient packs per craft against crime's 1, and the splitter is a blind 1:1), packs back + up, and the line seizes. Harmless and honest, but it's why the demo grows piles. +- My round-1 lesson bit me again from the other side: DATA reworked the commission ladder + mid-round (`first-taste` → `raw-payload`, 20 ore), which broke a sim test that assumed + shipping melt closes the first commission. Rewritten to assert the *rule* — shipping what + the active order wants credits it, capped at the cost — rather than which order is first + this week. + +CONTRACT REQUEST +- **`GameData.seams?: SeamMap`**, and `main.ts` importing `../data/seams.json` into the data + object. The shape is DATA's file verbatim; I've mirrored it as `SeamDef`/`SeamMap`, exported + from `src/sim/index.ts`, so the contract can lift it as-is. Nothing else in my lane is + blocked. + +PROPOSAL +- **A trap for DATA**, matching what the sim already recognises: + `{ id: 'mosquito-trap', kind: 'crafter', footprint: {x:2,y:2}, recipes: ['catch-swarm'], powerDraw: 3 }` + plus `{ id: 'catch-swarm', machine: 'mosquito-trap', inputs: {}, outputs: {'mosquito-swarm': 1}, ticks: 30, bandwidth: 2 }`. + The canned swarm is already an item and commissions already ask for live ones, so it ships. +- Should swarms bite `powerGen` as well as craft speed? Currently no, deliberately. +- `snapshot.wildlife` and `snapshot.relics` are always present (found or not) as the v6 note + requires. They alias live arrays like `commissionQueue` — same read-only rule. + +NEXT (round 6 if asked) +- The Correction / parity mites — the enemy proper. +- A headless perf benchmark, so these numbers stop being browser anecdotes (proposed round 3; + the 30s-timeout scare this round is the third time it would have paid for itself). +- Per-seam `richness` driving extraction rate, once DATA wants it — the field is already there. +- Swarm behaviour beyond "sit and bite": drifting between targets, or fleeing a trap.