Review: 5/5 lanes pass. 160/160 tests, tsc clean, M1 COMPLETE — verified live: reference factory ships melt, commission queue advances with standing orders, SCREEN's new artifact passes respond item-specifically (block 0.46 from bricks). Contracts v3 (granted): EntityState.scrammed, SimSnapshot.commissionQueue, MachineDef.coolPerTick, setRecipeAt command, Sim.save/load, ScreenFX.frame(t, snap), BeltItem.id hardened required, MachineDef.color re-ruled as chassis/body. main.ts: passes snapshot to screen.frame; dev __fktryDemo() builds reference factory. happy-dom ACTUALLY installed this time (round-2 grant never landed; UI caught it). Rulings: bandwidth units are per-second (SIM converts); heat retune ordered (nothing can currently overheat - heatPerTick < ambient cooling); validator test moves to data/; RENDER's color deviation approved as the ruling; scram wipe 3 frames; REMOVE button approved. Round 3 orders in all lane docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
13 KiB
LANE-DATA — content, recipes, balance, and canon-keeping
You are an Opus 4.8 executor on the DATA lane of FKTRY. Read ../MASTERPLAN.md and
../CONTRACTS.md first. Your bible is ../../docs/FKTRY_LORE.md — you are its
transcriber into machine-readable canon. When the codex and convenience disagree, the
codex wins; when the codex is silent, invent IN ITS VOICE and note what you invented.
Mission: every item, machine, recipe, tech, and commission as clean JSON, plus the validator that keeps five parallel lanes from drowning in dangling ids. Content should light up in-game with zero code changes from other lanes.
Owned paths: data/** (the validator now lives at data/validate.test.ts;
the old src/sim/data-validate.test.ts exception is closed — round 3 moves it).
Never touch: contracts, main.ts, other lanes' code. Schema changes are CONTRACT
REQUESTs.
Standing rules (all rounds):
- Ids: kebab-case matching codex names (
chroma-slurry,mosh-reactor).codexfield points at the lore doc section ("3:melt"= §3, MELT entry). - Balance philosophy: absurd flavor, honest math. Ratios should create real routing pressure (byproducts you must deal with, not vent). Steal shamelessly from the doc's real numbers (era efficiency multipliers, 4:2:0 = half the chroma, GOP cadences).
- Never delete an id other lanes may reference mid-round — deprecate in NOTES first.
CURRENT ORDERS — Round 3 (goal: heat that matters, deeper economy)
Round 2 review: the bloom-concentrate grep-before-delete and the fault-injection
discipline are exactly the standard. Both your cross-lane asks are RULED:
(1) Units: per-second. gen/draw are per second, stored is
bandwidth-seconds; SIM converts their integration this round — your bufferCap: 240
= 8 seconds of a 30 deficit, as you intended. (2) Cooling: coolPerTick? granted
in v3 (sim default 0.004); SIM wires it. Your SIM's-test-is-red flag was correct
mid-round and self-resolved at HEAD (their landing fixed it) — the stash-and-rerun
diagnostic was the right move. Ownership RULING: data-validate.test.ts moves to
data/validate.test.ts (git mv, yours — vitest picks it up there; src/sim/**
returns fully to SIM).
- The validator move above, first, so the tree is clean.
- Heat retune, the headline: today NOTHING can overheat — every
heatPerTickyou authored is below the 0.004 ambient cooling, so heat is decorative. WithcoolPerTickyours to set per machine: hit SIM's suggested feel — software decoder throttles after ~10s of continuous load, scrams ~13-15s, full duty cycle ~25s; ASIC stays incapable of heat. Show the arithmetic in CANON-DELTA (per-tick vs per-second — mind the units ruling). Give the hex-splicer a lesser fever. Coordinate with SIM's reference-factory v3 via NOTES — your numbers decide whether their layout survives. - Buffer economy check under the units ruling: is 240 (8s) still your intent now that it's true? One tank should cover one decoder scram — verify against your retuned cycle, adjust, show working.
- ASIC COOLER spec'd in CANON-DELTA (the codex names it, §2 "vented by ASIC
coolers"): item/machine entry + intended adjacency mechanic, data authored but
recipes gated behind a
broadcast-era tech node — the MECHANIC stays deferred until SIM builds auras (M4); the data existing first is fine and the validator's FORWARD_CANON pattern covers it. - Reel + broadcast era tech nodes: research costs in analog packs; unlocks field-loom/telecine recipe families you already authored.
- Muxer + moov brain sub-lines (§7):
stsz-ledger,stco-map,stts-metronome,stss-keyringitems + assembly recipes converging on amoov-brain→mux-containerendgame recipe on the muxer. This is M4's rocket — data lands first, mechanics later. Muxer machine entry if you don't have one.
Definition of done: validator green from its new home; a software decoder demonstrably overheats in SIM's tests using YOUR numbers (coordinate — their DoD depends on your retune); CANON-DELTA carries the arithmetic; FORWARD_CANON pruned of anything that gained a recipe.
NOTES (append-only log, newest at bottom)
### Round N — YYYY-MM-DD — [your model]
SHIPPED: / DECISIONS: / INVENTED: / BLOCKED/BROKEN: / CONTRACT REQUEST: / NEXT:
Round 1 — 2026-07-17 — Opus 4.8
SHIPPED:
- Validator
src/sim/data-validate.test.ts, 28 tests. Fault-injected a recipe with a dangling item + a machine that doesn't list it — both caught by id and named. It is not a test that only knows how to pass. - items 9 → 36, machines 7 → 21, recipes 4 → 35, tech 0 → 17, commissions 1 → 10.
- Verified:
tscclean,vitest run52/52 green (LANE-SCREEN's 24 included), and the live dev build boots with no console errors. All 21 machines appear in LANE-UI's build bar with zero code changes from them.
DECISIONS:
- All four seed recipe ids kept alive (
extract-mdat,demux-ore,quantize,mosh) so nothing dangles for a lane mid-round.moshkeeps its id but is rewired to canon:gop-crate 1 → melt 3 + anchor-slab 1. The winched-out I-frame is recovered (§4 mosh reactor: "recoverable — sell it!"), so slabs circulate and delta wafers are what actually burns. Net economy: 6 wafers → 3 melt. quantizeleft at the seed's exact ratio so the M1 chain stays easy to build.- M1 chain is longer than the masterplan says — please rule on this. My orders
spell out
slab + wafers → gop-crateandgop-crate → mosh, but MASTERPLAN M1 describes extractor → belts → demuxer → quantizer → mosh → shipper (seven machines). Those can't both be true: reaching a crate needs dct-press (slab), p-caster (wafers) and gop-assembler in between. I followed the orders since they're the more specific and more recent instruction, and all three run fine as generic crafters. If M1 must stay at seven machines, say so and I'll add a shortcutmosh-rawrecipe next round rather than weaken the canon path. - Machine params that the codex describes as dials (quantizer Q, subsampler grade taps, GOP cadence templates) are modelled as separate recipes per setting, not as a per-entity parameter. Cheapest thing that works against the current contract; if SIM ever wants a real dial, that's a contract change, not a data change.
- Two absurd-but-honest ratios, as ordered:
assemble-gop-i-onlyburns 8 premium slabs for 1 crate (I-only genuinely is the worst cadence — the joke balances itself, nobody sane builds it), andpan-speckletakes 40 HF DUST for 1 speckle (§3 says "panned like gold", so it's priced like gold panning). Both give hf-dust real sinks.
INVENTED (codex is silent; written in its voice — kill any of these if you disagree):
press-anchor-slabon the DCT PRESS — the press run in reverse is an IDCT, i.e. a complete picture. Consistent with the field loom and telecine puller, which the codex explicitly runs backwards. This is where I-frames come from.- Items
color-plate(the demosaicer's "full-color sheet", §4) andv-hold-roll(bottled from the §1 Broadcast Shelf v-hold faults, so the ANALOG PACK's "combing + v-hold roll + static" triptych maps to three real items). - Machines
artifact-bottler(§2 calls the packs "a bottled artifact triptych" but names no bottling plant) andlane-splitter(contract haskind: 'splitter'and belts need routing; the codex only ever calls the DEMUXER "the first splitter").
BLOCKED/BROKEN: nothing blocked. Known-incomplete, deliberately:
- Bloom is one grade, not the graded 1-5 line §3 sells by intensity.
container-pack/cinema-pack/mosquito-swarm/gibbs-wraithexist as items with no recipe — forward canon, per orders. The validator's reachability test has an explicit FORWARD_CANON allowlist so these four can't hide a real dangling id; delete entries from it as recipes land.stream-hex-splicingcosts container-packs nothing currently produces. Intentional dead-end until the moov/container line exists (§6 heists).
CONTRACT REQUEST: MachineDef.heatPerTick?: number — the SOFTWARE DECODER is
kind: 'power', and power machines carry no recipes, but RecipeDef.heat is the only
heat hook in the contract. So the one machine the codex defines by its heat (§4:
"decodes ANYTHING, at any temperature") has no way to declare it. It's shipped as a
plain 45-gen power machine and is currently strictly better than the ASIC, which is
backwards. Alternative if you prefer no contract churn: let power machines run a
recipe with empty outputs — but I'd rather not put outputs: {} in the data, and my
validator rejects it today.
NEXT (Round 2 candidates, not self-assigned): bloom grades 1-5 as real items; the
container line (moov shard / offset ribbon / sync key → CONTAINER PACK) which unblocks
the hex splicer; mosquito traps so vaporwave-sunset becomes shippable; buffer-tank
and muxer data; reel + broadcast era tech nodes.
Round 2 — 2026-07-17 — Opus 4.8
SHIPPED: all 7 orders. data/CANON-DELTA.md; colour + flavor on all 21 machines;
heat economy; bufferCap; commission queue with 3 standing orders; container line;
bloom grades 1-5. items 36 → 44, machines 21, recipes 35 → 44, tech 17 → 19,
commissions 10 → 14. Validator 28 → 36 tests.
- Verified: my 36 pass; every other lane's suite is green (140/141 total — the one
failure is SIM's, see BLOCKED). Live build: 21/21 machines art-directed with zero
gaps, my hexes confirmed on the real DOM swatches (ASIC
rgb(185,190,196), software decoderrgb(110,58,52)), no console errors, fax opens on FIRST TASTE with DUST ALLOWANCE next in tray. - Fault-injected all six new checks (missing colour, absurd heatPerTick, buffer with no cap, non-buffer with a cap, wrong queue head, standing order wanting live mosquitoes) — all six failed by name, then restored. Same standard as round 1.
DECISIONS:
bloom-concentratekept, not replaced. It is now the raw ungraded draw-off that feeds grading. I was about to retire it for the grade-1..5 line until I grepped: LANE-SCREEN hardcodes it insrc/screen/corruptionMap.ts:54and its test. Deleting it would have broken their suite mid-round. The standing rule earned its keep.- The round-1 recipe id
bloom-grade-3survives but now produces the itembloom-grade-3— the id finally means what it says. The old recipe body moved totap-bloom. Nothing outsidedata/referenced it (checked). - Container line routes demuxer → gop-assembler → bottler, deliberately not through the hex splicer, since §4 gates the splicer behind CONTAINER PACK research. Otherwise the tech tree eats its own tail.
- Machine colours are all desaturated industrial per §8 ("ALL saturation belongs to media/artifacts"). The items carry the colour; the factory is grime. Two eras get a tint where the codex insists: field loom phosphor-green, telecine brass, ASIC stream-era white, software decoder hot-red.
INVENTED: 3 items (moov-shard, offset-ribbon, sync-key), 6 recipes, 2 tech nodes,
2 commissions. All logged with rationale in data/CANON-DELTA.md rather than here.
BLOCKED/BROKEN:
- SIM's M1 chain test is red, and it is not mine.
sim.test.ts:456assertsactiveCommission === 'first-taste'after 4000 ticks, but SIM's new queue advances on completion, so it readsdust-allowance. I confirmed this by stashing my entire round 2 diff and re-running: identical failure. Their assertion needs updating to their own new behaviour — I didn't touch their file. My validator now pinscommissions[0]asfirst-tasteso the queue head stays load-bearing for them. npx tsc --noEmitreports 2 errors insrc/render/index.ts(94, 96) from RENDER's uncommitted work. Also not mine — a JSON file cannot cause "Expected 3 arguments".
CROSS-LANE — SIM, two things I need from you:
- Units. I read
gen/drawas bandwidth per second (codex §2 meters read kbps).bufferCap: 240is built on that. If you integrate per tick, my buffer number is 30× too small — say so and I'll retune. Arithmetic is in CANON-DELTA. - Cooling is yours and it doesn't exist yet.
heatPerTick: 0.0025makes a software decoder throttle at 9.3s and scram at 13.3s of continuous running, which is the codex ("burst gen ... throttles theatrically"). That only becomes a mechanic if something cools it; with no cooling it's a one-shot fuse. I assumed ~0.0025/tick while scrammed/idle (~50% duty → effective 27/s vs the ASIC's steady 20/s, in the same 2×2 footprint). Tell me your rate and I'll retune to hit "throttle ~10s, full cycle ~25s". Heads up: yourmeltChain()reference factory runs on 3 software decoders and no ASIC. Once scram lands they will heat in lockstep and black out together every ~13s. That's the honest answer to "does anyone dare run two side by side" — but it will slow your reference factory, so consider an ASIC base + one decoder for burst, or a buffer tank (which is exactly whatbufferCap: 240is sized to cover: one scram).
CONTRACT REQUEST: none this round.
NEXT (candidates): a cooler machine — §2 says heat is "Vented by ASIC coolers", a
machine the codex names but never specifies, and without it heat has no counterplay;
mosquito traps (unblocks vaporwave-sunset); reel + broadcast era tech; the muxer and
the moov brain's four sub-lines (§7); cinema-pack when the Fortress exists.