Skip to content

FE-1689: Make ad-hoc scenarios the default and remove the classic scenario forms - #9686

Merged
kube merged 11 commits into
mainfrom
claude/opt-proto-adhoc-default
Sep 13, 2026
Merged

kube merged 11 commits into
mainfrom
claude/opt-proto-adhoc-default

Conversation

@kube

@kube kube commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Important

Experimental
The Parameter sweeps and In-browser optimization feature flags keep gating sweeps and the optimizer. The scenario form ships for everyone.

Summary

Before this PR, Petrinaut carried two scenario forms. The classic one, the default, edited scenario parameters as typed rows and the initial state as a per-place spreadsheet or a code block, and the experiment drawer showed a saved scenario's parameters as rows of its own. The ad-hoc form, Variables above Parameters beside a per-place Initial state, sat behind the Ad-hoc scenarios setting and rendered only where that setting turned it on.

This PR makes the ad-hoc form the only scenario form and removes the setting. Simulation Settings shows the form whenever no scenario is selected and the run form for a saved one. The Create Experiment drawer shows the form for No scenario and the run form with its Computed state fold for a saved scenario. Creating a scenario is the form in expose mode under Name and Description, with a Scenario Parameter toggle per Variable. Editing opens any stored kind through one core converter: a scenario saved in the form's format opens as stored minus any override, place or place block the net no longer matches, a per-place scenario opens converted and is stored in the form's format only when Save is pressed, a scenario whose initial state is code keeps that code, shown read-only, with its name, description, Variables and Parameters editable. The classic form, its mapping, its defaults and its language session are deleted.

9686.mp4

Links

Changes

One scenario form

  • Simulation Settings shows the form whenever no scenario is selected

    Variables and Parameters on the left, Initial state with Clear on the right, seeded from the canvas marking. A saved scenario shows the run form: scenario parameters editable, overrides and initial state read-only.
    The numeric Parameters column and its slider rows are deleted; a draft typed with No scenario always steers the next run.

  • The Create Experiment drawer shows every scenario through the form

    No scenario renders the form with Sweep toggles under the Parameter sweeps flag. A saved scenario renders the run form and its Computed state fold.
    The classic identifier, type, value and Sweep rows are deleted. The Constraints section is untouched.

  • Creating and editing a scenario is the form in expose mode

    Name and Description sit above Variables, Parameters and Initial state; each top-level Variable carries a Scenario Parameter toggle. Create disables on an empty or duplicate name and on any form error.
    scenario-form.tsx, its mapping, its defaults, its language session and its stories are deleted.

Stored kinds

  • adHocStateFromScenario in petrinaut-core seeds the form from any stored scenario

    A form-format scenario opens as stored, minus overrides and places the net no longer has and place blocks whose kind no longer matches their place. A per-place scenario opens converted, identifiers verbatim, every uncoloured place its expression, every coloured place its rows as literal cells; unknown place ids are dropped.
    A parity test compiles every per-place core example both ways and expects the same initial state and parameter values.

  • Per-place scenarios migrate on Save only

    A note under Description says saving stores the scenario in the form's format. Close changes nothing.

  • Code scenarios keep their code

    The body shows read-only in a fixed-height code editor under a notice; Save writes name, description, scenario parameters, overrides and the code verbatim.
    Renaming, un-exposing or retyping a Variable the code reads disables Save with the reason in the footer, and so does a top-level Variable that is not exposed, since the code cannot read it.

  • Stale parameter overrides no longer block editing

    The converter drops override keys the net does not know for every stored kind, so a scenario with a stale override opens and saves in the form.

Setting removal

  • enableAdHocScenarios and its setter leave UserSettings

    The Ad-hoc scenarios row leaves the viewport settings dialog; a persisted key is dropped on the next write.
    Patch changesets for @hashintel/petrinaut and @hashintel/petrinaut-core, which gains the converter as a public export.

  • The React side of the classic scenario language session is deleted

    initializeScenarioSession, updateScenarioSession and killScenarioSession leave the language client context and the LSP actions; the form's withVariables prop goes with the classic embedding.

Review fixes

  • Form-format scenarios drop overrides for parameters the net no longer has on open

    The adhoc branch of adHocStateFromScenario returned the stored definition verbatim, so a stale override reached synthesis with no Parameters row to clear it and Save stayed disabled.
    One known-id set now filters every stored kind; the module and arch-docs wording say so.

  • Form-format scenarios drop places the net no longer has on open

    storedAdHocState spread the stored places verbatim, so a scenario naming a deleted place opened with a synthesis error the form had no place block to clear and Save stayed disabled.
    The converter filters places by the net's place ids beside the overrides; scenario-to-ad-hoc-state.test.ts pins the stale place dropped and the opened state passing synthesis.

  • Form-format scenarios drop a place block whose kind no longer matches its place on open

    storedAdHocState kept a stored block by place id alone, so a coloured block on a place that lost its colour failed synthesis with nowhere in the form to clear it and Save stayed disabled.
    matchesPlace keeps an uncoloured block only on a place without a colour and a coloured block only on a place whose colour the net knows; scenario-to-ad-hoc-state.test.ts pins both directions dropped and the opened state passing synthesis.

Known issues

  • Code scenarios lose in-app editing of their code body

    Two core examples and the website's code scenarios still load, run, sweep and optimize; the code edits through the AI assistant, the net file or the CLI. An editable code slot is a follow-up.

  • The Preview embed keeps its compact parameter inputs

    Its scenario controls never read the setting and offer no No scenario option.

  • The classic scenario language session stays in petrinaut-core

    The worker's scenario-session messages, its virtual files and the scenario document URIs are public core API no client reaches now; removing them is a follow-up.

  • A saved scenario with a stale override or place, or a coloured block whose place lost its colour, still fails to run until it is opened and saved

    The provider synthesizes the stored definition in the worker against the net, and synthesis rejects the unknown parameter, the unknown place and a coloured block on a place that lost its colour. A compile-side skip is a follow-up.

  • A lower layer's pending changeset still announces the Ad-hoc scenarios setting

    .changeset/adhoc-scenario-authoring.md opens with the setting this PR removes; one release would introduce and remove it unless that clause is trimmed in its own PR.

Test coverage

  • simulation-settings.test.tsx:

    Form titles and Clear with No scenario, the run form on the synchronous render with a per-place scenario, edits reaching the provider.

  • create-experiment-drawer.test.tsx, experiment-scenario-run.test.tsx:

    The run form for a saved scenario, Sweep only under the flag, an empty-parameters scenario, an ad-hoc submit with sweeps off.

  • scenario-to-ad-hoc-state.test.ts in petrinaut-core:

    Kinds, identifiers, defaults, coloured rows, dropped unknown places, stale overrides, places and mismatched place blocks dropped from a stored form-format definition, and compile parity over every per-place core example.

  • create-scenario-drawer.test.tsx, view-scenario-drawer.test.tsx, ad-hoc-scenario-authoring.test.tsx, validate-scenario-name.test.ts, ad-hoc-lsp-errors.test.ts:

    Creation writes the form format, per-place migrates on Save with unchanged identifiers, code stays verbatim, a renamed Variable the code reads blocks Save, a stale override opens with Save enabled and saves empty overrides, Close never saves.

  • user-settings-provider.test.tsx, viewport-settings-dialog.test.tsx:

    A stored enableAdHocScenarios key loads and is dropped on the next write; no Ad-hoc scenarios row.

How to test

Quick simulation

  • Open Petrinaut preview on Vercel
  • Viewport controls > Settings

    Expect no Ad-hoc scenarios row under General

  • Menu > Load example > SIR Epidemic Model
  • Bottom panel > Simulation Settings > Scenario > No scenario

    Expect Variables, Parameters and Initial state with Clear

  • Bottom panel > Simulation Settings > Scenario > Seasonal Flu

    Expect Scenario parameters editable, Parameters and Initial state read-only

Scenarios

  • Switch to Simulate
  • Scenarios > Seasonal Flu > pencil

    Expect the form with Scenario Parameter on population and infected_ratio, a note that saving stores the form's format

  • Change infected_ratio default, then Save

    Expect the scenario to reopen from its stored definition

  • Menu > Load example > Probabilistic Satellite Launcher
  • Scenarios > Pre-deployed Constellation > pencil

    Expect the code shown read-only under Initial state, Variables and Parameters editable

  • Scenarios > Create

    Expect Scenario name, Description and the form; Create disabled until a unique name

Experiments

  • Experiments > Create > Scenario > Seasonal Flu

    Expect the run form and a collapsed Computed state section, no classic rows

  • Experiments > Create > Scenario > No scenario

    Expect the form under the picker

@kube kube self-assigned this Sep 11, 2026
@vercel

vercel Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
hash Ready Ready Preview Sep 13, 2026 4:54pm UTC
petrinaut Ready Ready Preview Sep 13, 2026 4:54pm UTC
petrinaut-docs Ready Ready Preview Sep 13, 2026 4:54pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 13, 2026 4:54pm UTC

Request Review

@github-actions github-actions Bot added 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 type/eng > backend Owned by the @backend team area/apps > hash.design Affects the `hash.design` design site (app) labels Sep 11, 2026
@kube
kube added this pull request to stack #9549 September 11, 2026 20:59
@kube
kube marked this pull request as ready for review September 11, 2026 22:11
Copilot AI balanced review requested due to automatic review settings September 11, 2026 22:11
@cursor

cursor Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches scenario compilation, persistence, and simulation/experiment configuration for all users; migration relies on conversion logic and save-time format changes rather than automatic net migration.

Overview
Makes the ad-hoc scenario form the only way to author and run scenarios, removing the experimental Ad-hoc scenarios user setting and the classic Simulation Settings parameter rows / experiment drawer parameter tables.

Core: Adds adHocStateFromScenario in @hashintel/petrinaut-core to open any stored scenario in the form—adhoc (pruning stale overrides/places/blocks), per_place (lossless conversion; save writes adhoc), code (variables/parameters only; code body kept read-only). Exports literalExpression for conversion tests; extensive parity tests against core examples.

UI: Simulation Settings always uses the two-column form (inline when No scenario, run mode when a scenario is selected). Create/edit scenario drawers use expose-mode form only; code scenarios show read-only initial-state code with save guards for exposed scenario.* parameters. withVariables removed—the Variables section is always shown. React scenario LSP session APIs removed from the language client (adhoc session remains).

Settings/docs: Strips persisted enableAdHocScenarios on next write; docs reframed around the unified form and updated experiments/simulation flows.

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

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

vilkinsons
vilkinsons previously approved these changes Sep 12, 2026
@kube
kube added this pull request to the merge queue Sep 12, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a manual request Sep 12, 2026
@kube
kube added this pull request to the merge queue Sep 13, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue because a pull request earlier in the stack was removed Sep 13, 2026
@kube
kube added this pull request to the merge queue Sep 13, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue because a pull request earlier in the stack was removed Sep 13, 2026
@kube
kube added this pull request to the merge queue Sep 13, 2026

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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.

There are 2 total unresolved issues (including 1 from previous review).

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 ac62960. Configure here.

@hash-release hash-release Bot mentioned this pull request Sep 13, 2026

This branch was successfully deployed

3 active deployments
Preview – hash — edd867e9 Deployed Sep 13, 2026 by vercel[bot]
Preview – petrinaut-docs — edd867e9 Deployed Sep 13, 2026 by vercel[bot]
Preview – petrinaut — edd867e9 Deployed Sep 13, 2026 by vercel[bot]
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/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

4 participants