# CANON-DELTA — everything in `data/` that isn't in the codex yet LANE-DATA owns this file. `../../docs/FKTRY_LORE.md` is canon; this is the ledger of where the data has run ahead of it. The orchestrator absorbs these into the lore doc in one pass later. Until then, **this is the single place canon-drift is allowed to live**. Rule for adding an entry: the codex was silent, I invented in its voice, and I wrote down *why it is consistent with the codex* — not just what I did. If a future lore pass disagrees, the codex wins and the data changes. --- ## Canonized in round 1 (orchestrator: "CANONIZED", round 2 review) | Thing | Kind | Why it fits | |---|---|---| | `press-anchor-slab` | recipe (dct-press) | The press run backwards is an IDCT, and an IDCT *is* a complete picture. §4 already runs the field loom and the telecine puller in reverse, so reversibility is established machine behaviour. This is where I-frames come from. | | `color-plate` | item | §4 demosaicer literally outputs "a smooth colour sheet"; it needed an id. | | `v-hold-roll` | item | §1 Broadcast Shelf has "v-hold faults that make whole regions periodically roll upward". Bottling one gives the ANALOG PACK's "combing + v-hold roll + static" triptych three real ingredients. | | `artifact-bottler` | machine | §2 calls the science packs "a bottled artifact triptych" but names no bottling plant. Something has to hold the bottle. | | `lane-splitter` | machine | The contract has `kind: 'splitter'` and belts need routing, but §4 only ever calls the DEMUXER "the first splitter" — which is a refinery, not a junction. | ## Added in round 2 ### The container line (unblocks `stream-hex-splicing`) §2 names the CONTAINER PACK's contents ("moov shard + offset ribbon + sync key") and §7 names the moov brain's parts, but nothing said where they come from. The chain now mirrors what the parts actually *are* in a real container: | Thing | Kind | Why it fits | |---|---|---| | `moov-shard` | item | The index, not the payload. | | `offset-ribbon` | item | The stco map — a ribbon of byte offsets. | | `sync-key` | item | The stss table lists which frames are keyframes, i.e. I-frames. | | `demux-container` | recipe (demuxer) | The demuxer is the machine that separates index from payload. 8 ore → 2 shards: the index is a rounding error next to the mdat, which is the joke and also the truth. | | `spool-offset-ribbon` | recipe (gop-assembler) | The assembler is the only machine that knows where each frame starts, because it put them there. | | `cut-sync-key` | recipe (artifact-bottler) | Cut from an anchor slab, because stss is a list of anchors. | | `bottle-container-pack` | recipe | Assembles the §2 triptych. | Chicken-and-egg check: §4 says the hex splicer "Requires CONTAINER PACK research", so the container line deliberately does **not** route through the splicer. It is demuxer → assembler → bottler, all machines you already own. ### The bloom line §3 sells bloom "by intensity grade; grade-5 bloom visibly tries to escape its canister in one direction" — five grades, one item each, `bloom-grade-1..5`. - `bloom-concentrate` is **kept** and redefined as the raw, ungraded draw-off from a loop (`tap-bloom`). It was not deleted because LANE-SCREEN hardcodes it in `src/screen/corruptionMap.ts:54` and its test — deleting it would have broken another lane's suite mid-round. Grading now consumes it. - The recipe id `bloom-grade-3` survives from round 1 but now produces the *item* `bloom-grade-3`, so the id finally means what it says. `tap-bloom` is the renamed round-1 `bloom-grade-3` recipe. **Deprecation notice:** no recipe id was retired, but `bloom-grade-3` changed its inputs/outputs entirely. Nothing outside `data/` referenced it (checked: only my own `tech.json`). - Escalation is in delta wafers, not exotic inputs — a grade-5 canister is 2 raw bloom + 18 wafers of compounding, which is §4's "contents compound each lap" priced honestly. ## Added in round 3 ### THE MUXER and the moov brain (§7, data-first — mechanics are M4's) §7 names the parts and says each is "its own late-game production line", but never said what makes them. Each part is now made by the machine that already owns that knowledge, which is the whole joke: the container is assembled by the factory that made the mess. | Thing | Made by | Why that machine | |---|---|---| | `stsz-ledger` | gop-assembler | The sample-size table. The assembler packed the crates, so it knows how big each one was. | | `stco-map` | hex-splicer | The chunk-offset map — byte offsets are the splicer's entire domain. It nudges them for a living; here it writes them down honestly, under protest. | | `stts-metronome` | telecine-puller | Time-to-sample is a cadence, and the puller is the cadence machine. Built from judder cams, so the metronome ticks 3:2. | | `stss-keyring` | artifact-bottler | The sync-sample table is a list of I-frames, so it is literally forged from anchor slabs. | | `ftyp-seal` | artifact-bottler | §7 names the ftyp seal as part of the container; it needed a source. | | `moov-brain` | muxer | The four converge. 300 ticks. | | `megaglitch` | muxer | `mux-container`: brain + seal + 500 mdat ore + 100 melt, 900 ticks. §7's "colossal composited corruption" priced like one. | `muxer` is `kind: 'crafter'`, not `'shipper'` — it *builds* the megaglitch, and you still have to ship the thing. 5×5, the biggest footprint in the game, per "hero structure". ### ASIC COOLER (spec'd, deliberately not yet mechanical) §2 HEAT says heat is "Vented by ASIC coolers" — a machine the codex names and never specifies. Authored now so the data is ready; **the mechanic is deferred to M4**, when SIM builds auras. Gated behind `broadcast-asic-cooling` so it can't appear early. - **Intended mechanic (SIM, when auras exist):** an adjacency aura — every machine whose footprint touches the cooler's 2×2 gets the cooler's `coolPerTick` (0.02) instead of its own. That turns the software decoder from a 30%-duty throb into something you can *engineer around*: ring your decoders with coolers and pay for it in floor space and build cost. This needs a contract change (`coolRadius?`, or a `kind: 'cooler'`) — **not requesting it until SIM is ready to build it**, since a contract field nobody reads is the same decorative trap heat just fell into. - **Authored as `kind: 'power'` with `powerGen: 5`** because there is no cooler kind and a lie is worse than a stretch: it is an ASIC, ASICs decode, decoding makes bandwidth. It vents far more than it earns. If `kind: 'cooler'` ever lands, this moves. - Its own `coolPerTick: 0.02` is inert today (nothing heats it) and is there to state the intended aura strength in data rather than in prose. --- ## The numbers, and the arithmetic behind them ### The reference M1 chain (measured, not guessed) Computed from `data/*.json` against the machine list in SIM's `meltChain()` (`src/sim/sim.test.ts`), with the two recipes that test hand-dials applied: ``` idle draw (every machine's powerDraw) 57 /s + active recipe draw at full tilt 39 /s = peak draw 96 /s - compression paid back (quantize -6, 4:2:2 -4, 4:2:0 -8) 18 /s = net peak demand 78 /s ``` **Units (RULED round 3):** `gen`/`draw` are bandwidth per **second**; `stored` and `bufferCap` are bandwidth-**seconds**. My round-2 assumption held. ### Round 2's heat was decorative — what went wrong Worth writing down, because it's a trap anyone can fall into. I sized round 2's `heatPerTick: 0.0025` against *no* cooling. SIM then implemented heat with cooling shed **every tick, active or not** (`HEAT_DISSIPATION = 0.004`). So the decoder shed 0.004 and banked 0.0025: net **−0.0015/tick**. It could never warm up. The number looked like a mechanic and was a comment. The lesson is now a test (`every heat source out-heats its own cooling`), and it caught a second instance immediately: `chart-stco-map` banked 0.06 heat over 90 ticks while the splicer shed 0.09 — I'd authored a fresh decorative number in this very round. **Anything with a heat number must beat its own machine's cooling, or it isn't a mechanic.** The validator now refuses both forms (per-tick machine heat, per-craft recipe heat). ### The software decoder: `powerGen` 55 → 100, `heatPerTick` 0.0033, `coolPerTick` 0.001 Net while running = 0.0033 − 0.001 = **0.0023/tick**. Against SIM's curve (throttle 0.7, scram 1.0, restart 0.5): ``` throttle, from cold 0.7 / 0.0023 / 30 = 10.1 s (target ~10 s) scram, from cold 1.0 / 0.0023 / 30 = 14.5 s (target 13-15 s) steady cycle, up 0.5 / 0.0023 / 30 = 7.25 s (heat 0.5 -> 1.0) steady cycle, down 0.5 / 0.001 / 30 = 16.67 s (cools 1.0 -> restart 0.5) period 23.9 s (target ~25 s) duty 30.3 % ``` **Why the decoder cools slowly (0.001, vs the sim's 0.004 default):** it is an overclocked tower PC held together with zip ties and prayer (§4). It is the worst-cooled object in the factory. The ASIC has "a huge heatsink afro" and no heat source at all. **Why powerGen had to nearly double.** SIM's hysteresis (scram at 1.0, restart at 0.5) means any machine that throttles at ~10 s spends ~70% of its life cooling. At round 2's 55 gen that's an average of ~14/s — strictly worse than the ASIC's steady 20, so nobody would ever build one and "burst gen" would be a lie. Averaged properly (generation is throttled linearly 1.0 → 0.5 across the throttle window, and zero while scrammed): ``` un-throttled 0.2 / 0.0023 = 87.0 ticks at 100/s throttled 0.3 / 0.0023 = 130.4 ticks at avg 75/s energy per cycle = 100 x (87.0 + 130.4 x 0.75) = 18480 bandwidth-ticks average = 18480 / 717 ticks = 25.8 /s ``` | | peak | duty | average | failure mode | |---|---|---|---|---| | DECODE ASIC | 20 /s | 100% | **20 /s** | none, forever | | SOFTWARE DECODER | 100 /s | 30% | **25.8 /s** | total blackout, 16.7 s at a time | Five ASICs at full song, one third of the time, in one 2×2 footprint. 29% more average power for a supply that vanishes on a schedule you don't control — a real choice, and the answer to "does anyone dare run two side by side" is still *no, not naked*: identical decoders heat in lockstep and therefore black out in lockstep. ### `bufferCap: 240 → 300` Re-derived against the retuned cycle, since the order was "one tank should cover one decoder scram" and the scram window changed: ``` reference chain: peak draw 96 /s, compression pays back 18 /s -> net demand 78 /s balanced plant: 3 ASIC (60/s steady) + 1 software decoder (25.8/s avg) = 85.8 /s ✓ decoder scrams: supply = 60 + 18 = 78 /s vs draw 96 /s -> deficit 18 /s 18 /s x 16.67 s = 300 bandwidth-seconds bufferCap = 300 -> one tank rides out exactly one scram. ``` And it refills in time to do it again: while the decoder is up the plant makes 67/s more than it spends, recharging 300 in **4.5 s** of the 7.25 s up-phase. That is the M2 sentence — **a buffer tank is what makes software decoders survivable** — and it now closes. ### `heat` on the hex splicer: `coolPerTick 0.001`, 0.08 per splice Net 0.035 per craft after the 45 ticks of cooling → 28.6 crafts → **42.9 s** of continuous splicing before it scrams (`chart-stco-map`: 50 s). A lesser fever than the decoder's 14.5 s, exactly as ordered. §4: "Requires ... a steady buffer feed or it splices *itself*" — left running unattended, it stops itself. --- ## Open / deferred - **The ASIC cooler's aura is spec'd, not built** (above). Until SIM has auras, heat is survivable only by duty-cycling or by leaning on ASICs. Deliberate. - `cinema-pack`, `mosquito-swarm`, `gibbs-wraith` remain forward canon (no recipe). The validator's FORWARD_CANON allowlist is the enforcement, and it has a companion test asserting nothing sits on the list once it *is* producible. Round 3 retired `container-pack`'s slot (round 2) and added none. - Dials-as-recipes (quantizer Q, subsampler grades, GOP cadence) stays, per round-2 review. - **The heat constants in `data/validate.test.ts` are mirrored from `src/sim/index.ts`** (throttle 0.7, restart 0.5, dissipation default 0.004, 30 tps). They are not exported, so my arithmetic tests can't import them. If SIM retunes the curve, my tests go stale *silently* — they'd still pass while the feel drifts. Re-check on any heat round. A cheap fix if SIM likes: export the constants. - The muxer, moov brain and megaglitch are data-only; no lane implements a victory condition yet. The tech gate (`fortress-the-muxer`) keeps them out of reach meanwhile.