Skip to content

FE-666: Basic Monte Carlo Simulation#8709

Open
kube wants to merge 37 commits into
mainfrom
cf/fe-666-stochastic-simulation-experiments-v1
Open

FE-666: Basic Monte Carlo Simulation#8709
kube wants to merge 37 commits into
mainfrom
cf/fe-666-stochastic-simulation-experiments-v1

Conversation

@kube
Copy link
Copy Markdown
Collaborator

@kube kube commented May 10, 2026

🌟 What is the purpose of this PR?

Reworks Petrinaut simulation internals and adds the first Monte Carlo experiment workflow. The branch separates Core/React/UI boundaries, moves frame access behind reader/binary-frame APIs, introduces seeded Monte Carlo runs with streaming token-count distributions, and exposes experiments in the Simulate tab plus CLI tooling.

flowchart LR
  UI[Simulate > Experiments] --> Context[ExperimentsContext]
  Context --> Runtime[Experiment runtime]
  Runtime <--> Worker[Monte Carlo worker protocol]
  Worker --> Simulator[Monte Carlo simulator]
  Simulator --> Metrics[Streaming token-count distributions]
  Metrics --> Context
  Context --> Timeline[uPlot experiment timeline]
Loading

🔗 Related links

🚫 Blocked by

None.

🔍 What does this change?

  • Refactors simulation Core boundaries, public APIs, frame readers, runtime modules, and worker-facing types.
  • Moves engine frames toward binary ArrayBuffer storage and keeps layout details behind SimulationFrameReader.
  • Makes simulation inputs JSON-serializable, including initial markings.
  • Simplifies deterministic simulation/playback lifecycle and reorganizes the Simulation Timeline modules.
  • Adds a seeded Monte Carlo simulator with per-run buffers, active-only token-count histograms, runtime orchestration, and worker tests.
  • Adds Simulate > Experiments UI for creating, running, cancelling, removing, and viewing Monte Carlo experiments.
  • Adds a Petrinaut Monte Carlo CLI and removes the temporary local stress-test file.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • I am unsure / need advice

⚠️ Known issues

  • The Monte Carlo metric storage is still a first implementation; windowed/binary metric persistence is left for follow-up work.

🐾 Next steps

  • Narrow the Simulation Engine around binary frame storage, metric storage, and stable worker protocols.
  • Improve Monte Carlo metric aggregation/storage before scaling the UI to very large experiments.

🛡 What tests cover this?

  • yarn workspace @hashintel/petrinaut lint:tsc
  • yarn workspace @hashintel/petrinaut lint:eslint
  • yarn workspace @hashintel/petrinaut test:unit src/core/simulation/monte-carlo/runtime/experiment.test.ts src/react/experiments/provider.test.tsx src/core/simulation/monte-carlo/monte-carlo-simulator.test.ts src/core/simulation/authoring/scenario/compile-scenario.test.ts --run

❓ How to test this?

  1. Open Petrinaut and go to Simulate > Experiments.
  2. Create an experiment with a scenario, parameters, max time, and run count.
  3. Click Run and confirm the dialog shows progress, closes on success, and opens the new experiment.
  4. Confirm the token-count distribution timeline streams p10/median/mean/p90 data per place.
  5. Cancel/remove an experiment and confirm the provider state updates correctly.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment May 15, 2026 11:49pm
petrinaut Ready Ready Preview, Comment May 15, 2026 11:49pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview May 15, 2026 11:49pm

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps area/apps > hash.design Affects the `hash.design` design site (app) labels May 10, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 6.20%. Comparing base (7b67b01) to head (d3127af).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #8709       +/-   ##
==========================================
- Coverage   62.31%   6.20%   -56.12%     
==========================================
  Files        1354     506      -848     
  Lines      137313   14817   -122496     
  Branches     5793    2994     -2799     
==========================================
- Hits        85568     919    -84649     
+ Misses      50838   13865    -36973     
+ Partials      907      33      -874     
Flag Coverage Δ
apps.hash-ai-worker-py ?
apps.hash-ai-worker-ts 1.41% <ø> (ø)
apps.hash-api 0.00% <ø> (ø)
backend-integration-tests ?
blockprotocol.type-system ?
deer ?
error-stack ?
local.claude-hooks ?
local.harpc-client 51.24% <ø> (ø)
local.hash-backend-utils 2.81% <ø> (ø)
local.hash-graph-sdk 9.63% <ø> (ø)
local.hash-isomorphic-utils 0.00% <ø> (ø)
local.hash-subgraph ?
rust.antsi ?
rust.deer ?
rust.error-stack ?
rust.harpc-codec ?
rust.harpc-net ?
rust.harpc-tower ?
rust.harpc-types ?
rust.harpc-wire-protocol ?
rust.hash-codec ?
rust.hash-graph-api ?
rust.hash-graph-authorization ?
rust.hash-graph-postgres-store ?
rust.hash-graph-store ?
rust.hash-graph-temporal-versioning ?
rust.hash-graph-types ?
rust.hash-graph-validation ?
rust.hashql-ast ?
rust.hashql-compiletest ?
rust.hashql-core ?
rust.hashql-diagnostics ?
rust.hashql-eval ?
rust.hashql-hir ?
rust.hashql-mir ?
rust.hashql-syntax-jexpr ?
rust.sarif ?
sarif ?
tests.hash-backend-integration ?
unit-tests ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 10, 2026

Merging this PR will not alter performance

✅ 80 untouched benchmarks


Comparing cf/fe-666-stochastic-simulation-experiments-v1 (a880232) with main (b922dd2)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (8452cc0) during the generation of this report, so b922dd2 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$26.5 \mathrm{ms} \pm 228 \mathrm{μs}\left({\color{gray}1.97 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.52 \mathrm{ms} \pm 19.2 \mathrm{μs}\left({\color{gray}2.99 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$12.3 \mathrm{ms} \pm 75.2 \mathrm{μs}\left({\color{gray}-1.471 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$43.3 \mathrm{ms} \pm 282 \mathrm{μs}\left({\color{gray}-0.211 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$15.1 \mathrm{ms} \pm 115 \mathrm{μs}\left({\color{gray}3.13 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$23.2 \mathrm{ms} \pm 139 \mathrm{μs}\left({\color{gray}-4.023 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$26.9 \mathrm{ms} \pm 161 \mathrm{μs}\left({\color{gray}1.67 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.87 \mathrm{ms} \pm 20.8 \mathrm{μs}\left({\color{gray}3.70 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.2 \mathrm{ms} \pm 87.9 \mathrm{μs}\left({\color{gray}-0.309 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.68 \mathrm{ms} \pm 22.4 \mathrm{μs}\left({\color{gray}-2.123 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.98 \mathrm{ms} \pm 14.4 \mathrm{μs}\left({\color{gray}-1.841 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.36 \mathrm{ms} \pm 23.8 \mathrm{μs}\left({\color{gray}0.307 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.05 \mathrm{ms} \pm 27.6 \mathrm{μs}\left({\color{gray}-0.597 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.53 \mathrm{ms} \pm 15.7 \mathrm{μs}\left({\color{gray}-0.118 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.10 \mathrm{ms} \pm 23.0 \mathrm{μs}\left({\color{gray}0.100 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.35 \mathrm{ms} \pm 26.2 \mathrm{μs}\left({\color{gray}-1.078 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.40 \mathrm{ms} \pm 13.8 \mathrm{μs}\left({\color{gray}-2.555 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.03 \mathrm{ms} \pm 25.2 \mathrm{μs}\left({\color{gray}-0.717 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.63 \mathrm{ms} \pm 18.4 \mathrm{μs}\left({\color{gray}0.495 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.55 \mathrm{ms} \pm 18.0 \mathrm{μs}\left({\color{gray}0.559 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.58 \mathrm{ms} \pm 11.2 \mathrm{μs}\left({\color{gray}-0.240 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.86 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}0.053 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.61 \mathrm{ms} \pm 10.1 \mathrm{μs}\left({\color{gray}-2.382 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.81 \mathrm{ms} \pm 10.1 \mathrm{μs}\left({\color{gray}-1.171 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.01 \mathrm{ms} \pm 14.6 \mathrm{μs}\left({\color{gray}0.163 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.74 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}-0.598 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.96 \mathrm{ms} \pm 11.1 \mathrm{μs}\left({\color{gray}0.719 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.36 \mathrm{ms} \pm 22.5 \mathrm{μs}\left({\color{gray}-1.467 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.94 \mathrm{ms} \pm 14.7 \mathrm{μs}\left({\color{gray}-1.906 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.26 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}-0.501 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.29 \mathrm{ms} \pm 18.1 \mathrm{μs}\left({\color{gray}-0.852 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.96 \mathrm{ms} \pm 11.8 \mathrm{μs}\left({\color{gray}-0.353 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.28 \mathrm{ms} \pm 17.6 \mathrm{μs}\left({\color{gray}-0.252 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$54.6 \mathrm{ms} \pm 349 \mathrm{μs}\left({\color{gray}0.491 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$46.1 \mathrm{ms} \pm 184 \mathrm{μs}\left({\color{gray}-0.314 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$51.5 \mathrm{ms} \pm 340 \mathrm{μs}\left({\color{gray}-0.440 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$45.6 \mathrm{ms} \pm 363 \mathrm{μs}\left({\color{gray}2.40 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$62.3 \mathrm{ms} \pm 313 \mathrm{μs}\left({\color{gray}-0.984 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$61.0 \mathrm{ms} \pm 334 \mathrm{μs}\left({\color{gray}-0.528 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$55.7 \mathrm{ms} \pm 311 \mathrm{μs}\left({\color{gray}-0.498 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$102 \mathrm{ms} \pm 388 \mathrm{μs}\left({\color{gray}-1.590 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$61.9 \mathrm{ms} \pm 4.26 \mathrm{ms}\left({\color{red}31.7 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$290 \mathrm{ms} \pm 763 \mathrm{μs}\left({\color{gray}-0.950 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$19.4 \mathrm{ms} \pm 108 \mathrm{μs}\left({\color{gray}-1.094 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$20.2 \mathrm{ms} \pm 103 \mathrm{μs}\left({\color{gray}0.398 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$20.3 \mathrm{ms} \pm 116 \mathrm{μs}\left({\color{gray}0.679 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$19.2 \mathrm{ms} \pm 63.1 \mathrm{μs}\left({\color{gray}-0.156 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$25.8 \mathrm{ms} \pm 173 \mathrm{μs}\left({\color{gray}3.97 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$19.2 \mathrm{ms} \pm 93.1 \mathrm{μs}\left({\color{gray}-0.220 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$19.2 \mathrm{ms} \pm 96.8 \mathrm{μs}\left({\color{gray}-2.065 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$19.7 \mathrm{ms} \pm 115 \mathrm{μs}\left({\color{gray}0.994 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$20.0 \mathrm{ms} \pm 81.4 \mathrm{μs}\left({\color{gray}-1.055 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$26.8 \mathrm{ms} \pm 200 \mathrm{μs}\left({\color{gray}-0.515 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$35.5 \mathrm{ms} \pm 213 \mathrm{μs}\left({\color{gray}-0.274 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$35.8 \mathrm{ms} \pm 282 \mathrm{μs}\left({\color{gray}1.11 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$34.8 \mathrm{ms} \pm 263 \mathrm{μs}\left({\color{gray}-1.419 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$36.4 \mathrm{ms} \pm 368 \mathrm{μs}\left({\color{red}8.15 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$35.4 \mathrm{ms} \pm 374 \mathrm{μs}\left({\color{gray}1.96 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$34.9 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}3.44 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$34.8 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{gray}2.87 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$34.9 \mathrm{ms} \pm 338 \mathrm{μs}\left({\color{gray}0.195 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$34.6 \mathrm{ms} \pm 354 \mathrm{μs}\left({\color{gray}2.00 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.57 \mathrm{ms} \pm 56.3 \mathrm{μs}\left({\color{gray}1.63 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$93.5 \mathrm{ms} \pm 551 \mathrm{μs}\left({\color{gray}2.03 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$148 \mathrm{ms} \pm 598 \mathrm{μs}\left({\color{gray}1.71 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$100 \mathrm{ms} \pm 625 \mathrm{μs}\left({\color{gray}2.48 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$111 \mathrm{ms} \pm 512 \mathrm{μs}\left({\color{gray}1.31 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$118 \mathrm{ms} \pm 552 \mathrm{μs}\left({\color{gray}1.84 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$127 \mathrm{ms} \pm 537 \mathrm{μs}\left({\color{gray}1.71 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$103 \mathrm{ms} \pm 414 \mathrm{μs}\left({\color{gray}0.367 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$133 \mathrm{ms} \pm 448 \mathrm{μs}\left({\color{gray}1.33 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$111 \mathrm{ms} \pm 665 \mathrm{μs}\left({\color{gray}1.67 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$119 \mathrm{ms} \pm 539 \mathrm{μs}\left({\color{gray}0.575 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$122 \mathrm{ms} \pm 679 \mathrm{μs}\left({\color{gray}0.956 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$121 \mathrm{ms} \pm 443 \mathrm{μs}\left({\color{gray}0.350 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$189 \mathrm{ms} \pm 533 \mathrm{μs}\left({\color{red}21.5 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$169 \mathrm{ms} \pm 2.41 \mathrm{ms}\left({\color{red}13.0 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$40.3 \mathrm{ms} \pm 178 \mathrm{μs}\left({\color{gray}0.122 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$557 \mathrm{ms} \pm 927 \mathrm{μs}\left({\color{gray}2.37 \mathrm{\%}}\right) $$ Flame Graph

@kube kube force-pushed the cf/fe-666-stochastic-simulation-experiments-v1 branch from a880232 to b182351 Compare May 11, 2026 22:12
@github-actions github-actions Bot removed area/deps Relates to third-party dependencies (area) area/apps labels May 11, 2026
const count = marking?.count ?? 0;
const dimensions = getPlaceDimensions(place, sdcpn);

placeStates[placeId] = {
// Initialize transition states
const transitionStates: EngineFrameSnapshot["transitions"] = {};
for (const transition of sdcpn.transitions) {
transitionStates[transition.id] = {
@cursor
Copy link
Copy Markdown

cursor Bot commented May 12, 2026

PR Summary

High Risk
High risk because it changes @hashintel/petrinaut core simulation/playback public types and initial-marking/scenario compilation formats, which can break consumers and alter runtime behavior.

Overview
Adds a first-pass Monte Carlo experiment workflow to @hashintel/petrinaut/core, exporting new Monte Carlo simulator/worker/experiment factories and distribution metrics.

Refactors core simulation internals and public API around SimulationFrameReader/binary frame handling, makes InitialMarking JSON-serializable, and updates scenario compilation to produce numeric counts or per-token records for colored places (with expanded validation and tests).

Tightens playback backpressure typing by separating compute modes (ComputePlayMode) from viewOnly, updates docs/architecture notes, removes the old core/react/ui split RFC docs, and includes small config updates (new spin keyframe, ignore libs/analysis, changeset).

Reviewed by Cursor Bugbot for commit 9798ca1. Bugbot is set up for automated code reviews on this repo. Configure here.

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 12, 2026

This pull request is abnormally large and would use a significant amount of tokens to review. If you still wish to review it, comment "augment review" and we will review it.

Comment thread libs/@hashintel/petrinaut/src/cli/app.tsx Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9798ca1. Configure here.

run.nextFrame = run.currentFrame;
run.currentFrame = workingFrame;
run.frameNumber++;
run.currentTime += run.simulation.dt;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Floating-point time drift in Monte Carlo simulation loop

Medium Severity

Time is accumulated via repeated += dt additions in both advanceRun (run.currentTime += run.simulation.dt) and MonteCarloSimulatorImpl.advanceAll (this.#time += dt). Over many frames, floating-point rounding errors compound. Since run.currentTime is used for the maxTime completion check, accumulated drift can cause a run to end one frame early or late. Using run.frameNumber * dt for the comparison (or for the metric context time) would avoid this drift.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9798ca1. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants