FE-778: Stop the ad-hoc form from re-rendering the editor while it is open - #9620
FE-778: Stop the ad-hoc form from re-rendering the editor while it is open#9620kube wants to merge 3 commits into
Conversation
… open The form's language session synced to the worker on every state identity change; run-mode hosts rebuild an equal state per render, and each sync republished diagnostics, which re-rendered the hosts: a loop that held the canvas at 9 fps for as long as Simulation Settings showed a scenario. The session now follows the definition's content. The simulation provider was excluded from React Compiler by a throw inside initialize's try/catch, so every render handed out new identities for all derived values; the compile-or-throw step moved to a helper. The worker reuses the net's own diagnostics across session-only syncs, and the client drops publishes that change nothing. Run-mode hosts reseed on scenario content, not object identity, so a node drag no longer remounts the form. Place totals and slot labels index the state once per render.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Semgrep found 1
RegExp() called with a View Dataflow Graphflowchart LR
classDef invis fill:white, stroke: none
classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none
subgraph File0["<b>libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts</b>"]
direction LR
%% Source
subgraph Source
direction LR
v0["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L915 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 915] count</a>"]
end
%% Intermediate
subgraph Traces0[Traces]
direction TB
v2["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L915 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 915] count</a>"]
v3["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L984 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 984] resolveCount</a>"]
v4["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L931 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 931] inline</a>"]
v5["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L885 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 885] state</a>"]
v6["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L890 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 890] withNeutralAdHocExpressions</a>"]
v7["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L789 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 789] state</a>"]
v8["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L890 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 890] normalized</a>"]
v9["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L945 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 945] placeState</a>"]
v10["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L972 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 972] placeVariableProductions</a>"]
v11["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L699 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 699] placeState</a>"]
v12["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L704 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 704] of</a>"]
v13["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L704 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 704] variable</a>"]
v14["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L725 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 725] productions</a>"]
v15["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L714 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 714] of</a>"]
v16["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L714 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 714] earlier</a>"]
v17["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L720 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 720] bareReferencePattern</a>"]
v18["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L674 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 674] name</a>"]
v19["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L676 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 676] escapeForPattern</a>"]
v20["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L670 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 670] name</a>"]
v21["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L676 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 676] `</a>"]
end
v2 --> v3
v3 --> v4
v4 --> v5
v5 --> v6
v6 --> v7
v7 --> v8
v8 --> v9
v9 --> v10
v10 --> v11
v11 --> v12
v12 --> v13
v13 --> v14
v14 --> v15
v15 --> v16
v16 --> v17
v17 --> v18
v18 --> v19
v19 --> v20
v20 --> v21
%% Sink
subgraph Sink
direction LR
v1["<a href=https://github.com/hashintel/hash/blob/dfe685f9e24c87578f036338cb8ea4c0b951e141/libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/ad-hoc/ad-hoc-scenario.ts#L675 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 675] new RegExp(<br> String.raw`(?<![.\w$])${escapeForPattern(name)}(?![A-Za-z0-9_$])`,<br> "g",<br> )</a>"]
end
end
%% Class Assignment
Source:::invis
Sink:::invis
Traces0:::invis
File0:::invis
%% Connections
Source --> Traces0
Traces0 --> Sink
|
PR SummaryLow Risk Overview Ad-hoc form & hosts: LSP: The worker caches net-level Simulation provider: Scenario compile failure handling moves to Reviewed by Cursor Bugbot for commit 46efae6. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🟡 Changes recommended
The numeric-literal fast path can resolve invalid or non-finite expressions incorrectly, and the host reseeding behavior lacks a regression test.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes ad-hoc scenario forms repeatedly re-rendering the editor by stabilizing session synchronization, diagnostics, and scenario reseeding.
Changes:
- Keys form sessions and run-mode state by serialized content.
- Caches diagnostics and indexed form lookups.
- Adds regression tests and package changesets.
- No user-guide documentation updates are included.
File summaries
| File | Description |
|---|---|
experiment-scenario-run.tsx |
Reseeds experiment forms by scenario content. |
simulation-settings.tsx |
Preserves forms across unrelated net edits. |
value-editor.tsx |
Uses indexed target labels. |
use-ad-hoc-lsp-session.ts |
Syncs sessions only on content changes. |
use-ad-hoc-lsp-session.test.tsx |
Tests session synchronization lifecycle. |
token-table.tsx |
Uses cached place totals. |
place-block.tsx |
Uses cached place totals. |
form-context.ts |
Exposes label and total resolvers. |
ad-hoc-scenario-form.tsx |
Creates shared per-render indexes. |
provider.tsx |
Restores React Compiler optimization. |
ad-hoc-scenario.ts |
Adds indexed resolvers and literal fast path. |
ad-hoc-scenario.test.ts |
Tests resolver behavior. |
language-server.worker.ts |
Caches net diagnostics. |
language-client.ts |
Suppresses unchanged diagnostic snapshots. |
language-client.test.ts |
Tests diagnostic identity and notifications. |
index.ts |
Exports the new resolver APIs. |
adhoc-form-render-performance.md |
Adds Petrinaut patch changeset. |
adhoc-form-render-performance-core.md |
Adds Petrinaut Core patch changeset. |
Review details
- Files reviewed: 18/18 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…th and pin the content reseed
Important
Experimental
Behind the Ad-hoc scenarios feature flag.
Summary
Before this PR, opening Simulation Settings with a scenario selected put the editor in a loop. The panel rebuilds the form's state object on every render, the form's language session synced to the worker on every new object, every sync republished the net's diagnostics, and the publish re-rendered the panel. The canvas sat at 9 fps while nothing was touched, and a node drag took 38 seconds and remounted the form twice.
Session syncs now follow the definition's content, the worker reuses the net's diagnostics across session-only syncs, the client drops publishes that change nothing, and the simulation provider is memoized again. Run-mode hosts reseed on scenario content rather than object identity, and the form indexes labels and place totals once per render. Measured with the
bench/run.mjsPlaywright harness on an 80-place generated net against the production website build.Playback with the panel open runs at the same 30 fps with the flag on and off: that cost is the canvas re-rendering every node per frame, and it is untouched here.
Before
9620-before.mp4
After
9620-after.mp4
Links
Changes
Ad-hoc form
Simulation provider
Language server
Next steps
Review fixes
Test coverage
use-ad-hoc-lsp-session.test.tsx:language-client.test.ts:ad-hoc-scenario.test.ts:@hashintel/petrinautand@hashintel/petrinaut-coreunit suitesad-hoc-scenario.test.ts,experiment-scenario-run.test.tsx, review fixes:How to test