ArchitectureNetwork

--:--
warming up
Tick
15 min
96 ticks a simulated day
Seed
42
the world is a pure function of this
Runtime deps
3
next, react, react-dom
Services
0
no server, no database, no keys
Entities
11
in the domain model
Replay
exact
same seed and tick, same numbers

System map

how a live deployment would be arranged
SOURCESHistorian / SCADALIMSBatch PLCERPWMSEDIINGESTConnectorsNormalisationIdempotencyDead letterCOREWorld stateDerived modelSchedulerOVERSIGHTAgentsAudit trailApprovalsSURFACERole interfacesAPIReporting

The demonstration collapses this. Because src/sim is pure TypeScript with no dependencies, the whole world runs in the browser — which is why you can clone this and watch a plant with no database, no keys and no accounts. In a real deployment the world layer is replaced by the ingest layer and everything above it is unchanged. That substitution is the point of the boundary, not a happy accident.

Where data would live

four stores, chosen by access pattern
Relational — Postgres
HoldsMaster data, orders, stock lots and their state, mould sets, schedules, agent runs and approvals.
WhyEverything with a lifecycle, a foreign key and an audit requirement. The agent audit trail in particular has to survive a legal question years later, so it belongs somewhere with transactions and backups rather than somewhere fast.
Timeseries — Timescale or Influx
HoldsProcess tags, machine speeds, temperatures, reject counts, energy intervals.
WhyForty thousand tags at second resolution is roughly two gigabytes a day and is almost never queried by primary key — it is queried by range and downsampled. Putting it in the relational store works for a month and then does not.
Object — S3 or equivalent
HoldsRaw inbound files, EDI documents, laboratory certificates, generated reporting packs.
WhyRegulatory filings need the source document as it arrived, not a parsed version of it. Cheap, immutable, and the thing an auditor actually asks for.
Cache — Redis
HoldsCurrent plant state, available-to-promise answers, connector health.
WhyA screen refreshing every few seconds should not touch Postgres. Everything here is derivable, so losing it costs latency and nothing else.

None of this exists in the demonstration. It is stated because the honest answer to "where does the data go" is a design decision with trade-offs, not a shrug — and because getting it wrong is expensive at exactly the point when the system is becoming useful.

Configuration

what is tunable, and where it lives
Process assumptionssrc/sim/constants.ts
Physical networksrc/sim/network.ts
Article book and demandsrc/sim/demand.ts
Connector definitionssrc/integration/connectors.ts
Agent triggers and scopessrc/agents/index.ts
Seed and warm-upsrc/lib/sim-context.tsx

Every process assumption sits in one file rather than scattered through the model, so that any number the platform produces can be traced back to a stated assumption. That is the same reason a real plant keeps a standards file, and it is what made the domain review possible — a reviewer could read the assumptions without reading the code.

Where a figure is a range the simulation moves within it. Where it is a single value it is a modelling assumption and is marked as one.

The domain model

what the world is made of
EntityInstancesNotes
Site6plants, distribution centres, customer delivery points
Furnace8one colour per campaign, 10–15 years
Forehearth18one per line — the layer that couples furnace to machine
Line18IS machines, sections × gobs
Cavity566each one independently traceable via the mould number
Article22the mould exists or it does not
Customer12large food and beverage manufacturers only
Mould set0physical kits — one place at a time
Stock lot0article × site, with free / held state
Connector12designed integration points
Agent7triggered workers with scoped reads

Determinism, and why it is a feature rather than a trick

The world is a pure function of a seed and a tick. There is no Math.random() anywhere in the simulation — every random value is a hash of its own coordinates, so nothing is sequenced and nothing can drift. A stateful generator would make every draw depend on how many draws happened before it, which means adding one call anywhere silently changes every number downstream.

Three things follow, and they are the reasons it was built this way:

  • Two people opening the same screen at the same tick see identical numbers, so a conversation about what the platform is showing is possible at all.
  • Tests can assert exact values rather than tolerances, which is what makes an eval harness for the agent layer worth building.
  • Any agent run can be replayed against the exact state it saw. "Why did it do that" has an answer, and the answer is reproducible rather than reconstructed.

In a live deployment the seed is replaced by real telemetry and the determinism moves from the world to the audit trail — the same guarantee, applied to what was actually observed rather than to what was generated.