glytch/fktry/src/sim/constants.ts
LANE-SIM 039eff15fa [sim] research + gating, spatial cooling, exported constants, reference v4
Round 4 per lanes/LANE-SIM.md.

- research v1: kind:'lab', setResearch, snapshot.research, 'researched'.
  Gating: any id a tech unlocks is refused until that tech lands; ids no
  tech names are free forever. Labs take only what the active tech still
  needs; several labs feed one total; research survives save/load as a
  RULE, so a restored save can still build what it unlocked
- realtech.test.ts: a cold-start research run on DATA's own tree -- ore ->
  packs -> archaeology lab -> tech -> a refused recipe now accepted. Also
  the tripwire if the tech bootstrap ever closes over again; it was
  circular and unenterable at the start of this round
- spatial cooling: coolRadius, chebyshev from the footprint, auras sum,
  total capped at HEAT_COOL_MAX (0.05 -- past that a stack buys nothing
  but still costs bandwidth and floor). Proven by measuring shed rate
- src/sim/constants.ts: 12 constants so DATA imports truth instead of
  hand-copying numbers that go stale in silence
- reference v4: anchor-slab overflow tap, so the demo ships slabs (18 per
  20k). Needed TWO melt lanes: with one, melt spills onto the slab lane
  and the splitter phase-locks with the reactor's push order -- slab to
  the assembler, melt to the uplink, forever, and no slab ever sold. It
  passed 20k ticks looking perfect. referenceFactoryTech() derives the
  techs the layout needs, from the commands
- also wired: bandwidth.capacity, EntityState.scrammed, commissionQueue

65 sim tests, 318 across the repo. Melt still tick 1248, zero brownouts
over 20k.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:20:32 +10:00

58 lines
2.6 KiB
TypeScript

/**
* LANE-SIM's tuning constants — the single source of truth.
*
* These were private to index.ts until round 4. They're exported because other lanes'
* tests were hand-copying the numbers and going stale in silence: a copy of 0.7 doesn't
* fail when the sim moves to 0.65, it just quietly asserts the wrong thing forever.
* Import these rather than retyping them.
*
* Anything DATA can already set per-machine (heatPerTick, coolPerTick, bufferCap,
* beltSpeed, coolRadius) lives in data/machines.json, not here. These are the sim-wide
* rules that no machine overrides.
*/
// ------------------------------------------------------------------ belts
/** Minimum gap between two items, in belt-tiles. Enforced across the tile seam too. */
export const BELT_SPACING = 0.45;
/** Items a single belt tile may hold. */
export const BELT_CAPACITY = 2;
/** Items a splitter holds while it waits for an output to open. */
export const SPLITTER_CAPACITY = 2;
// -------------------------------------------------------------- machines
/** A machine stalls ('output full') once any output piles to this multiple of its yield. */
export const OUTPUT_STALL_FACTOR = 4;
/** A machine accepts an input up to this multiple of the recipe requirement. */
export const INPUT_BUFFER_FACTOR = 2;
// ------------------------------------------------------------------ heat
//
// heatPerTick is GROSS (contracts v4): net climb = heatPerTick - coolPerTick, so a
// machine whose heatPerTick never clears its cooling can never overheat.
/** Below this heat, throttling is purely cosmetic. */
export const HEAT_THROTTLE_START = 0.7;
/** Speed multiplier at heat 1.0 — the codex's "tick rate visibly halves". */
export const HEAT_THROTTLE_FLOOR = 0.5;
/** Heat at which a machine scrams. */
export const HEAT_SCRAM = 1;
/** Cool back below this and a scrammed machine restarts. */
export const HEAT_RESTART = 0.5;
/** Per-tick cooling when a machine's def doesn't specify `coolPerTick`. */
export const HEAT_COOL_DEFAULT = 0.004;
/**
* Ceiling on a machine's total cooling once auras stack (own rate + every cooler in
* range). At 0.05 a machine sheds a full 1.0 of heat in 20 ticks (~0.67s), which is
* already effectively instant — past this, extra coolers would buy nothing but would
* still cost bandwidth and floor space, and stacking them would look broken rather than
* generous. See NOTES round 4.
*/
export const HEAT_COOL_MAX = 0.05;
// ---------------------------------------------------------------- tracing
/** Belt graphs bigger than this are treated as unterminated (cheap loop guard). */
export const MAX_TRACE = 512;