FE-1139: Simulation architecture documentation#8951
Conversation
Self-contained HTML pages (no build step) under petrinaut-core/docs/architecture/: overview (execution paths, memory map, protocols), engine (EngineFrame v2 binary format with byte-exact memory-map diagram), authoring (user-code compilation), worker (protocol sequence diagram, backpressure, lifecycle), and monte-carlo (run model, double-buffer memory, metric pipeline). The core pages are React-free — consumers are described as "the host application" via the public API. The React integration (providers, playback ack policy, experiments UI) is documented in a separate ARCHITECTURE.md in @hashintel/petrinaut, outside docs/ which is the end-user guide. Existing simulation READMEs cross-link the HTML set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryLow Risk Overview The set covers overview (quick sim vs experiments, memory ownership, protocols), engine, authoring/compilation, worker/protocol, and Monte Carlo — framed host-agnostically for the headless core, with explicit refactoring seams (e.g. triple frame retention). React-specific integration is split into new Reviewed by Cursor Bugbot for commit e858cee. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
Adds internal engineering architecture documentation for the Petrinaut simulation subsystem, centered on a set of self-contained HTML pages in @hashintel/petrinaut-core (plus a separate React-integration boundary doc in @hashintel/petrinaut) so contributors can reason about frame formats, worker protocols, lifecycle, and Monte Carlo execution without a docs build pipeline.
Changes:
- Introduces five standalone HTML architecture pages + shared CSS under
libs/@hashintel/petrinaut-core/docs/architecture/(overview, engine, compilation, worker/protocol, Monte Carlo). - Adds a new
libs/@hashintel/petrinaut/ARCHITECTURE.mddocumenting how the React layer consumes the headless core. - Cross-links the new HTML docs from existing
petrinaut-core/src/simulation/*markdown entrypoints.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/@hashintel/petrinaut/ARCHITECTURE.md | New internal doc describing React integration points and responsibilities (providers, playback/ack policy, experiments rendering). |
| libs/@hashintel/petrinaut-core/src/simulation/README.md | Adds a prominent link to the new illustrated HTML architecture docs. |
| libs/@hashintel/petrinaut-core/src/simulation/ARCHITECTURE.md | Adds a prominent link to the new illustrated HTML architecture docs. |
| libs/@hashintel/petrinaut-core/docs/architecture/index.html | New overview page: execution paths, memory ownership map, protocol summary, and module map. |
| libs/@hashintel/petrinaut-core/docs/architecture/engine.html | New engine page: stepping lifecycle and EngineFrame v2 binary format overview with diagrams. |
| libs/@hashintel/petrinaut-core/docs/architecture/authoring.html | New compilation/authoring page: user-code compilation pipeline, surfaces, execution locations, sandboxing notes. |
| libs/@hashintel/petrinaut-core/docs/architecture/worker.html | New worker/protocol page: message tables, sequence diagram, backpressure/ack contract, lifecycle diagram. |
| libs/@hashintel/petrinaut-core/docs/architecture/monte-carlo.html | New Monte Carlo page: run model, bounded buffering strategy, metrics pipeline, protocol summary. |
| libs/@hashintel/petrinaut-core/docs/architecture/architecture.css | Shared styling for the HTML architecture docs and their diagram primitives. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <td><a href="./engine.html">architecture-engine.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--authoring)">Compilation</strong></td> | ||
| <td><code>authoring/</code></td> | ||
| <td>User code → JS functions (lambda, kernel, dynamics, metric, scenario), sandbox hardening</td> | ||
| <td><a href="./authoring.html">architecture-authoring.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--worker)">Worker + runtime</strong></td> | ||
| <td><code>worker/</code>, <code>runtime/</code></td> | ||
| <td>Transport protocol, backpressure, lifecycle stores, frame retention</td> | ||
| <td><a href="./worker.html">architecture-worker.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--mc)">Monte Carlo</strong></td> | ||
| <td><code>monte-carlo/</code></td> | ||
| <td>Batch runs, bounded buffers, metric pipeline, experiment handle</td> | ||
| <td><a href="./monte-carlo.html">architecture-monte-carlo.html</a></td> |
| <td>Runs <code>buildSimulation()</code> (compiles user code, packs frame 0), | ||
| replies <code>frame(0)</code> then <code>ready</code>. Resets | ||
| <code>lastAckedFrame = −1</code>.</td></tr> |
| <pre><code>// worker compute loop (simplified from simulation.worker.ts) | ||
| while (isRunning) { | ||
| if (lastAckedFrame < 0 || currentFrame − lastAckedFrame ≥ maxFramesAhead) { | ||
| await delay(10); continue; // wait for the consumer | ||
| } | ||
| batch = compute up to batchSize frames (stop on complete/error) | ||
| post "frame" | "frames" | ||
| await delay(0); // let pause/stop/ack messages in | ||
| }</code></pre> |
| <small>If <code>currentTime ≥ maxTime</code>, return | ||
| <code>"maxTime"</code> without computing.</small></div> |
| <small>Evaluated with <code>parameters</code> and <code>scenario</code> in | ||
| scope; result rounded and clamped ≥ 0 (a token count).</small></div> |
48deb41 to
087cef8
Compare
| <td><a href="./engine.html">architecture-engine.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--authoring)">Compilation</strong></td> | ||
| <td><code>authoring/</code></td> | ||
| <td>User code → JS functions (lambda, kernel, dynamics, metric, scenario), sandbox hardening</td> | ||
| <td><a href="./authoring.html">architecture-authoring.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--worker)">Worker + runtime</strong></td> | ||
| <td><code>worker/</code>, <code>runtime/</code></td> | ||
| <td>Transport protocol, backpressure, lifecycle stores, frame retention</td> | ||
| <td><a href="./worker.html">architecture-worker.html</a></td> | ||
| </tr> | ||
| <tr> | ||
| <td><strong style="color:var(--mc)">Monte Carlo</strong></td> | ||
| <td><code>monte-carlo/</code></td> | ||
| <td>Batch runs, bounded buffers, metric pipeline, experiment handle</td> | ||
| <td><a href="./monte-carlo.html">architecture-monte-carlo.html</a></td> |
| <td><code>sdcpn, extensions?, initialMarking, parameterValues, seed, dt, maxTime, maxFramesAhead?, batchSize?</code></td> | ||
| <td>Runs <code>buildSimulation()</code> (compiles user code, packs frame 0), | ||
| replies <code>frame(0)</code> then <code>ready</code>. Resets | ||
| <code>lastAckedFrame = −1</code>.</td></tr> |
|
|
||
| <pre><code>// worker compute loop (simplified from simulation.worker.ts) | ||
| while (isRunning) { | ||
| if (lastAckedFrame < 0 || currentFrame − lastAckedFrame ≥ maxFramesAhead) { |
| - Owns the run configuration as React state: `initialMarking` (name-keyed | ||
| `TokenRecord[]` / counts per place), parameter values, seed, `dt`, | ||
| `maxTime`. When a scenario is compiled, its marking and parameter overrides | ||
| take effect over the base state. |
| <td><strong style="color:var(--engine)">Engine</strong></td> | ||
| <td><code>engine/</code>, <code>frames/</code></td> | ||
| <td>Build + stepping, EngineFrame binary format, frame readers</td> | ||
| <td><a href="./engine.html">architecture-engine.html</a></td> |
| <td><strong style="color:var(--authoring)">Compilation</strong></td> | ||
| <td><code>authoring/</code></td> | ||
| <td>User code → JS functions (lambda, kernel, dynamics, metric, scenario), sandbox hardening</td> | ||
| <td><a href="./authoring.html">architecture-authoring.html</a></td> |
| <td><strong style="color:var(--worker)">Worker + runtime</strong></td> | ||
| <td><code>worker/</code>, <code>runtime/</code></td> | ||
| <td>Transport protocol, backpressure, lifecycle stores, frame retention</td> | ||
| <td><a href="./worker.html">architecture-worker.html</a></td> |
| <td><strong style="color:var(--mc)">Monte Carlo</strong></td> | ||
| <td><code>monte-carlo/</code></td> | ||
| <td>Batch runs, bounded buffers, metric pipeline, experiment handle</td> | ||
| <td><a href="./monte-carlo.html">architecture-monte-carlo.html</a></td> |
| (1) Frames could be posted with a transfer list (worker never re-reads sent | ||
| frames) to halve copies. |
🌟 What is the purpose of this PR?
Adds engineering architecture documentation for the Petrinaut simulation subsystem: five self-contained HTML pages (zero build step — open
index.htmlin any browser) with hand-built diagrams that markdown can't express — a byte-exactEngineFramememory map, a worker-protocol sequence diagram, lifecycle state machines, and per-module data-flow pipelines. Goal: make the architecture legible enough to refactor against, with explicit answers to "where does the memory actually live" and "what are the protocols".🔗 Related links
🚫 Blocked by
🔍 What does this change?
libs/@hashintel/petrinaut-core/docs/architecture/:index.html— overview: the two execution paths (Quick Simulation vs Experiments), the "where the memory actually lives" table, protocols at a glance, module map, design invariants, refactoring seams (e.g. triple frame retention).engine.html— build/step lifecycle,EngineFramev2 binary format with a byte-exact memory-map SVG (header fields, section offsets, packed token structs, alignment padding), token typing, determinism.authoring.html— the user-code compilation pipeline, which surface compiles where and runs on which thread, sandboxing posture, deferred distribution sampling.worker.html— full message protocol tables, an SVG sequence diagram of one simulation run, the ack/backpressure contract with play-mode profiles, lifecycle state machine.monte-carlo.html— run model, double-buffer memory with byte-capacity growth, the in-worker metrics pipeline, experiment protocol.Simulationhandle,SimulationFrameReader, experiment stores). The React integration (providers, playback ack policy, experiments rendering, uPlot timeline) moved to a newlibs/@hashintel/petrinaut/ARCHITECTURE.md— deliberately not in that package'sdocs/folder, which is the end-user guide read by the in-app assistant.src/simulation/ARCHITECTURE.mdandsrc/simulation/README.mdcross-link the HTML set; the HTML pages link the source files they document (e.g.frames/internal-frame.ts).Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
docs/is outside the npmfileswhitelist; the only code-adjacent changes are markdown cross-links)📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
🐾 Next steps
docs/architecture/via GitHub Pages.🛡 What tests cover this?
❓ How to test this?
open libs/@hashintel/petrinaut-core/docs/architecture/index.htmllibs/@hashintel/petrinaut/ARCHITECTURE.md.📹 Demo
Open
index.html— the pages are the demo.