FE-1262: Unbreak array methods in scenario code, add a range() helper, and surface scenario compile errors - #9092
FE-1262: Unbreak array methods in scenario code, add a range() helper, and surface scenario compile errors#9092kube wants to merge 4 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
…surface compile errors The scenario sandbox masked `.constructor` on built-in prototypes with a throwing getter, which broke `Array.prototype.map`/`filter`/`slice`/ `concat`/`flatMap` in user-authored scenario code (ArraySpeciesCreate reads the array's constructor). The getter now returns `undefined` instead — the spec falls back to the default Array while the constructor-walk escape still dead-ends. Adds a Python-style `range(end)` / `range(start, end, step?)` helper to scenario expressions and initial-state code, typed in the Monaco editors via the scenario session virtual files, with a length cap so oversized ranges fail fast instead of freezing render-time compilation. SimulationProvider previously discarded scenario compilation errors, making failures invisible; they are now exposed on SimulationContext and rendered as an error callout in Simulation Settings.
An empty "Define as code" editor produced a cryptic TS2355 ("A function
whose declared type is neither 'undefined', 'void', nor 'any' must
return a value.") the moment the mode was toggled on, because the empty
body was wrapped in `function __check(): InitialState {}`. The runtime
compiler explicitly ignores empty code, so the virtual file is now
skipped for blank content — the same treatment empty parameter-override
and per-place expressions already get.
Also adds language-service regression coverage asserting that the
satellites-style initial-state code (range + scenario + parameters)
type-checks cleanly end-to-end.
…ample A fifth bundled scenario for the Probabilistic Satellite Launcher whose initial state is authored in code mode: range(...).map(...) builds an evenly-spaced ring of satellites from two scenario parameters (number_of_satellites, initial_altitude), on top of the net's planet_radius. Doubles as an in-product showcase of the range() helper and code-mode initial state introduced in this branch. Covered by an example-level test compiling the scenario end-to-end with default and user-supplied parameter values.
1cec691 to
d0d473d
Compare
PR SummaryMedium Risk Overview Authors get a Python-style The Probabilistic Satellite Launcher example adds a Pre-deployed Constellation scenario that builds a ring of satellites with Reviewed by Cursor Bugbot for commit d0d473d. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
Adds safer scenario authoring, a typed range() helper, visible compilation errors, and a bundled constellation example.
Changes:
- Restores built-in array methods and adds validated
range()support. - Exposes scenario compilation failures in Simulation Settings.
- Updates LSP behavior, tests, documentation, and examples.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
simulation-settings.tsx |
Displays scenario compilation errors. |
playback-settings-menu.stories.tsx |
Updates mocked simulation context. |
simulation/provider.tsx |
Exposes compilation errors. |
simulation/context.ts |
Adds compilation errors to context. |
playback/provider.test.tsx |
Updates test context fixture. |
use-petrinaut-mutations.test.tsx |
Updates test context fixture. |
use-petrinaut-commands.test.tsx |
Updates test context fixture. |
docs/scenarios.md |
Documents helpers and errors. |
docs/examples.md |
Documents constellation example. |
scenario/helpers.ts |
Implements range(). |
scenario/helpers.test.ts |
Tests helper behavior. |
compile-scenario.ts |
Injects scenario helpers. |
compile-scenario.test.ts |
Tests arrays, helpers, and errors. |
sandbox.ts |
Makes constructor masking array-compatible. |
scenario-session.test.ts |
Tests LSP scenario diagnostics. |
generate-virtual-files.ts |
Declares helpers and skips empty code. |
satellites-launcher.ts |
Adds constellation scenario. |
satellites-launcher.test.ts |
Tests constellation compilation. |
satellites-pre-deployed-constellation.md |
Adds example changeset. |
fe-1262-scenario-range-helper.md |
Adds feature changeset. |
| const values: number[] = []; | ||
| for (let i = 0; i < length; i++) { | ||
| values.push(from + i * by); | ||
| } | ||
| return values; |
| if ( | ||
| session.initialStateAsCode && | ||
| session.initialStateCode !== undefined && | ||
| session.initialStateCode.trim() !== "" | ||
| ) { |
| direction: angle, | ||
| velocity: 0, |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d0d473d. Configure here.
| y: Math.sin(angle) * distanceToCenter, | ||
| direction: angle, | ||
| velocity: 0, | ||
| }; |
There was a problem hiding this comment.
Constellation starts with zero velocity
Medium Severity
The new Pre-deployed Constellation scenario seeds Space tokens with velocity: 0. Space runs the satellite orbit ODE, which divides by velocity when updating direction, so pressing Play immediately produces non-finite token state and the showcase constellation falls apart instead of orbiting.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d0d473d. Configure here.
|
@kube the copilot comments look sensible. Would you like to address them before me or Ciaran review? |


🌟 What is the purpose of this PR?
Scenario "Initial State as code" silently did nothing for everyday code: the evaluation sandbox masked
.constructoron built-in prototypes with a throwing getter, which brokeArray.prototype.map/filter/slice/concat/flatMap(they read the array'sconstructorvia the spec'sArraySpeciesCreate) — and the resulting compile errors were then discarded bySimulationProvider, so nothing appeared in the UI.This PR unbreaks those array methods, adds a Python-style
range()helper for scenario code, and makes scenario compile errors visible in Simulation Settings.What scenario authors can now write:
And when a scenario fails to compile, a red callout below the Scenario dropdown now lists each error instead of silently falling back to the manual marking.
🔗 Related links
🔍 What does this change?
runSandboxed(petrinaut-core): the.constructormask on built-in prototypes returnsundefinedinstead of throwing. Spec-internal species lookups fall back to the defaultArray, so array methods work; the({}).constructor.constructor(...)escape still dead-ends (undefined.constructoris a TypeError). All pre-existing escape tests pass unchanged.range(end)/range(start, end, step?)helper injected into scenario parameter-override expressions, per-place expressions, and initial-state code. Frozen, validated (finite args, non-zero step), and capped at 1,000,000 elements so oversized ranges fail fast instead of freezing render-time compilation.SimulationProviderno longer discardscompileScenarioerrors: they are exposed asscenarioCompilationErrorsonSimulationContextand rendered as an error callout in Simulation Settings.function __check(): InitialState {}, surfacing a cryptic TS2355 ("A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.") the moment the mode was toggled on. Empty code is a runtime no-op, so the virtual file is now skipped — same treatment as empty parameter-override and per-place expressions. Regression-tested end-to-end through the language service, including the satellites-stylerange(...).map(...)code checking clean.range(scenario.number_of_satellites).map(...)atplanet_radius + scenario.initial_altitude. Serves as an in-product showcase of the new helper; covered by an example-level compile test and verified live (8 satellites at frame 0, scaling with the scenario parameters).docs/scenarios.md) updated:rangedocumented in both authoring modes, error callout documented under "Running a scenario".Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 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:
SimulationProvider); behaviour is covered by the corecompileScenariotests plus the rendering being a simple conditional.🛡 What tests cover this?
helpers.test.ts:rangesemantics (arities, negative/non-integer steps, empty ranges, validation errors, length cap, works underrunSandboxed).compile-scenario.test.ts: regression test for the exactArray.from({ length }).map(...)shape that used to fail;rangein code mode, override expressions, and per-place expressions; cap/zero-step error reporting; helper escape-safety (range.constructor === undefined); all 8 pre-existing sandbox escape tests unchanged and passing.❓ How to test this?
yarn devinlibs/@hashintel/petrinaut).nand "Define as code" initial state returning{ SomePlace: range(n).map((i) => ({ ... })) }.n— the compiled initial state updates and the simulation uses it.range(0, 5, 0)) and confirm a red callout appears below the Scenario dropdown listing the error.🤖 Generated with Claude Code