glytch/fktry/CONTRACTS.md
type-two 83e3ad2107 [orchestrator] round 3 review + contracts v4 + composite seam codex + round 4 orders
Review: 5/5 lanes pass, 238/238, tsc clean. Verified live: scram duty-cycling with
tanks covering (zero brownout), shipment stamps, strain fever 0.824. Found 1 real bug
in review: UI BROWNOUT banner fires on covered deficit (topstrip.ts:66) - ordered.

Contracts v4: research (lab kind, setResearch, ResearchState, researched event),
SelectionState protocol (kills __remove sentinel, main.ts owns remove dispatch),
accent?, coolRadius? (spatial cooling), bandwidth.capacity?, save/load hardened,
heat ruled GROSS (net = heat - cool). tsconfig now typechecks data/ (DATA's proof).
Orchestrator patched lab entries into exhaustive kind maps (my breakage, my fix).

Rulings: pathspec-commit rule after 3 shared-index collisions (worktrees = named
escalation); bloom escalator reading accepted; UI ?uidemo + SCREEN boredom approved.

Codex: docs/FKTRY_LORE.md grew §10 THE COMPOSITE SEAM - keying/transparency artifact
family from the Corridor Crew compositing history + our corridorkey-mrp-mlx (which
doubles as a PYXLFK ground-truth artifact factory). DATA transcribes it round 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:43:48 +10:00

71 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CONTRACTS — how the lanes fit together (ORCHESTRATOR-OWNED)
The binding type definitions live in [`src/contracts.ts`](src/contracts.ts) — that file
is the law. This doc explains the shape of the machine in prose.
## Data flow
```
data/*.json ──▶ main.ts loads GameData
┌───────────┼─────────────────────────┐
▼ ▼ ▼
sim.init() renderer.init() ui.init() / screen.init()
30 tps fixed timestep: sim.tick()
├─▶ sim.snapshot() ──▶ renderer.render(snap, alpha) (every rAF)
│ ──▶ ui.update(snap, events)
└─▶ sim.drainEvents() ─▶ screen.onEvents(events)
user input: UI builds Commands ─▶ bus.dispatch ─▶ sim.enqueue
renderer supplies pickTile + ghost preview
```
## Ownership map
| Path | Owner | Everyone else |
|---|---|---|
| `src/contracts.ts`, `src/main.ts`, root config, this doc, `MASTERPLAN.md` | orchestrator | read-only |
| `src/sim/**` | LANE-SIM | read-only |
| `src/render/**`, `public/assets/**` (consumption) | LANE-RENDER | read-only |
| `src/ui/**` | LANE-UI | read-only |
| `src/screen/**` | LANE-SCREEN | read-only |
| `data/**` | LANE-DATA | read-only |
| `lanes/LANE-X.md` NOTES section | lane X | orchestrator writes ORDERS section |
| `../docs/FKTRY_LORE.md` | canon | read-only for all lanes |
## Key invariants
- **Snapshot is read-only.** Renderer/UI/Screen never mutate it. Sim may reuse
internal buffers between snapshots; consumers must not hold references across frames.
- **All mutation goes through Commands.** No lane reaches into sim internals.
- **Events are drained once per frame by main.ts** and fanned out; consumers get the
same array — treat it as immutable.
- **IDs are data-driven.** Renderer/UI/Screen never hard-code item/machine ids; they
key off `GameData` and the `asset` field. New content should light up with zero code.
- **`alpha`** in `renderer.render(snap, alpha)` is the 0..1 fraction between the last
sim tick and the next — use it to interpolate belt item positions for smooth motion.
- **Belt visual speed** derives from `MachineDef.beltSpeed` and `BeltItem.t`; sim owns
the truth, renderer owns the smoothness.
- **Coordinates**: tile grid, origin at world center, +x east, +y south. `Dir` 0..3 =
N,E,S,W clockwise. Machine `pos` = origin corner (min x, min y of footprint).
## Contract-change requests
Written in your lane NOTES as `CONTRACT REQUEST: <what> — <why>`. The orchestrator
batches them between rounds. Until granted, work around locally inside your lane.
## v4 notes
- `snapshot.commissionQueue` may alias a live sim array — read-only, never retain
across frames (same rule as the snapshot itself, stated here because it looks like
a plain array).
- Selection protocol: UI writes `bus.setSelection(...)`; main.ts derives ghost mode
and dispatches `place`/`remove` on click. UI must NOT dispatch `remove` itself.
The `'__remove'` def string is a deprecated bridge, deleted in v5.
- Heat: `heatPerTick` is GROSS; net climb = `heatPerTick coolPerTick`. A machine
whose heatPerTick ≤ its coolPerTick can never overheat — the validator enforces it.
- Research gating: ids appearing in any `TechDef.unlocks` are locked until researched;
ids referenced by no tech are always available.