Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e72d691
Keep ad-hoc value errors visible while editing
kube Sep 15, 2026
a862003
Polish scenario forms, keyboard navigation and computed values
kube Sep 15, 2026
5b31b3c
Migrate bundled examples to ad-hoc scenarios
kube Sep 16, 2026
221577c
Align scenario controls and place token totals
kube Sep 16, 2026
ed90a2c
Explain invalid sweep intervals beside experiment submission
kube Sep 15, 2026
ab9415b
Simplify experiment metrics, objectives and constraint editors
kube Sep 15, 2026
d64c197
Preserve native objective selection inside form focus groups
kube Sep 15, 2026
bc94e66
Correct experiment guide heading levels
kube Sep 15, 2026
4f4fd91
Fix metric selection and compact objective controls
kube Sep 16, 2026
fd92ba3
Show saved metric names as read-only text
kube Sep 16, 2026
06cf82d
Order sensitivity parameters by descending share
kube Sep 15, 2026
5c165ab
Simplify experiment result headers and summaries
kube Sep 15, 2026
c213e0d
Simplify experiment parameter sliders
kube Sep 16, 2026
e0a2e54
Show bounds below experiment sliders
kube Sep 16, 2026
b25f338
Make sweep optimization an explicit choice
kube Sep 16, 2026
8764fe4
Make experiment capabilities available without feature flags
kube Sep 16, 2026
4413c08
Group experiment constraints by what they check
kube Sep 16, 2026
e1a78fc
Accept expressions in state constraints
kube Sep 16, 2026
a1d449e
Regenerate state constraint schema documentation
kube Sep 16, 2026
b6a5a8a
Restore best parameters in experiment results
kube Sep 16, 2026
acc4116
Accept trailing semicolons in state constraints
kube Sep 16, 2026
e77dec1
Classify separate state conditions as a code body
kube Sep 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ad-hoc-value-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

Improve scenario and experiment forms with keyboard navigation, stacked section headers, overlay scrollbars, default starting-place filtering with a compact toggle beside the section title, and source expressions over selected computed values. Align the Time Step label and info icon, align token totals with place headers, keep select chevrons inside spreadsheet cells, and keep validation errors visible while editing ad-hoc values.
5 changes: 5 additions & 0 deletions .changeset/editable-example-scenarios.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut-core": patch
---

Make bundled example scenarios editable in the ad-hoc scenario form while preserving their parameters and initial states.
5 changes: 5 additions & 0 deletions .changeset/experiment-interval-feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

Offer GPU compute, parameter sweeps, and in-browser optimization without feature flags, with automatic metric names, grouped constraints that accept state expressions, keyboard controls, and explicit optimizer startup. Simplify results with manual optimizer controls, compact details, single-value parameter sliders, sensitivity estimates ordered by importance, and best parameters that remain available after optimization with a View best action.
5 changes: 5 additions & 0 deletions .changeset/experiment-settings-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut-core": patch
---

Accept state constraint expressions with optional trailing semicolons and no explicit return while preserving existing code bodies. Report a missing return when a state constraint contains separate statements. Update the assistant's guide summaries for experiment controls and settings available without simulation feature flags.
4 changes: 1 addition & 3 deletions apps/petrinaut-website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,7 @@ use provider-pattern discovery instead.
The demo at [http://localhost:5173](http://localhost:5173) runs the optimizer
in the browser: the Optuna study runs in a Pyodide web worker and each
optimization step runs on Petrinaut's own experiments backend, so no Python
service is involved. With the experimental **Parameter sweeps** and
**In-browser optimization** settings on, under **Viewport controls > Settings >
Simulation**, a sweep's Parameters card in the Experiments tab offers
service is involved. A sweep's Parameters card in the Experiments tab offers
**Optimize**. The first optimization in a browser downloads the Python runtime
from jsDelivr and Optuna from PyPI; later runs use the browser cache.

Expand Down
9 changes: 6 additions & 3 deletions apps/petrinaut-website/scripts/generate-example-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ const generateRuntime = async (entry: ExampleCatalogEntry) => {
null,
) as Record<string, ScenarioHir>;
for (const scenario of definition.scenarios ?? []) {
const hir = lowerScenarioToHir({
parameterOverrides: scenario.parameterOverrides,
initialState: scenario.initialState,
const hir = lowerScenarioToHir(scenario, {
adHocContext: {
places: definition.places,
types: definition.types,
netParameters: definition.parameters,
},
});
const outcome = compileScenario(
scenario,
Expand Down
11 changes: 11 additions & 0 deletions apps/petrinaut-website/src/examples/catalog.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { describe, expect, it } from "vitest";

import { compileScenario } from "@hashintel/petrinaut-core";

import {
exampleCatalog,
exampleSlugs,
Expand Down Expand Up @@ -34,7 +36,16 @@ describe("example catalog", () => {
expect(example.catalog).toBe(entry);

for (const scenario of example.definition.scenarios ?? []) {
expect(scenario.initialState.type).toBe("adhoc");
expect(runtime.scenarioHirById).toHaveProperty(scenario.id);
const compiled = compileScenario(
scenario,
runtime.scenarioHirById[scenario.id]!,
example.definition.parameters,
example.definition.places,
example.definition.types,
);
expect(compiled.ok, JSON.stringify(compiled)).toBe(true);

for (const parameter of scenario.scenarioParameters) {
const bounds = entry.parameterBounds[parameter.identifier];
Expand Down
6 changes: 6 additions & 0 deletions apps/petrinaut-website/src/examples/example-search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ describe("example search contract", () => {
settings: "unknown",
}).settings,
).toBeUndefined();
expect(
validateSharedExampleSearch({
overlay: "user-settings",
settings: "simulation",
}),
).toMatchObject({ overlay: "user-settings", settings: undefined });
expect(
validateSharedExampleSearch({
overlay: "create-experiment",
Expand Down
7 changes: 1 addition & 6 deletions apps/petrinaut-website/src/examples/example-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ export const sharedOverlays = [
"create-experiment",
] as const;

export const sharedSettingsSections = [
"general",
"viewport",
"simulation",
"labs",
] as const;
export const sharedSettingsSections = ["general", "viewport", "labs"] as const;

export const sharedResourceTypes = [
"scenario",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,125 @@
"param__draw_enabled": "scenario.draw_enabled"
},
"initialState": {
"type": "code",
"content": "return {\n IdleTankers: 1,\n LoadsDelivered: 0,\n SteadyNitrogenOrderPlaced: 0,\n SteadyNitrogenOrderPermits: 2,\n SteadyNitrogenOnRoute: 0,\n SteadyNitrogenVented: 0,\n SteadyNitrogenLineRunning: 1,\n SteadyNitrogenLineStopped: 0,\n SteadyNitrogenStockouts: 0,\n SteadyNitrogenConsumed: 0,\n SteadyNitrogenEvaporated: 0,\n SteadyNitrogenContents: 42,\n SteadyNitrogenUllage: 12,\n SteadyNitrogenUnitsDrawnSinceOrder: 0,\n};"
"type": "adhoc",
"content": {
"variables": [
{
"name": "draw_enabled",
"type": "real",
"expression": "1",
"exposed": true,
"optimize": null
}
],
"netParameters": [
{
"parameterId": "param__draw_enabled",
"expression": "scenario.draw_enabled",
"optimize": null
}
],
"places": {
"place__idle_tankers": {
"kind": "uncoloured",
"count": {
"expression": "1",
"optimize": null
}
},
"place__loads_delivered": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_order_placed": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_order_permits": {
"kind": "uncoloured",
"count": {
"expression": "2",
"optimize": null
}
},
"place__s1_on_route": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_vented": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_line_running": {
"kind": "uncoloured",
"count": {
"expression": "1",
"optimize": null
}
},
"place__s1_line_stopped": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_stockouts": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_consumed": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_evaporated": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_contents": {
"kind": "uncoloured",
"count": {
"expression": "42",
"optimize": null
}
},
"place__s1_ullage": {
"kind": "uncoloured",
"count": {
"expression": "12",
"optimize": null
}
},
"place__s1_units_drawn_since_order": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
}
}
}
}
},
{
Expand All @@ -449,8 +566,125 @@
"param__draw_enabled": "scenario.draw_enabled"
},
"initialState": {
"type": "code",
"content": "return {\n IdleTankers: 1,\n LoadsDelivered: 0,\n SteadyNitrogenOrderPlaced: 0,\n SteadyNitrogenOrderPermits: 2,\n SteadyNitrogenOnRoute: 0,\n SteadyNitrogenVented: 0,\n SteadyNitrogenLineRunning: 1,\n SteadyNitrogenLineStopped: 0,\n SteadyNitrogenStockouts: 0,\n SteadyNitrogenConsumed: 0,\n SteadyNitrogenEvaporated: 0,\n SteadyNitrogenContents: 42,\n SteadyNitrogenUllage: 12,\n SteadyNitrogenUnitsDrawnSinceOrder: 0,\n};"
"type": "adhoc",
"content": {
"variables": [
{
"name": "draw_enabled",
"type": "real",
"expression": "0",
"exposed": true,
"optimize": null
}
],
"netParameters": [
{
"parameterId": "param__draw_enabled",
"expression": "scenario.draw_enabled",
"optimize": null
}
],
"places": {
"place__idle_tankers": {
"kind": "uncoloured",
"count": {
"expression": "1",
"optimize": null
}
},
"place__loads_delivered": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_order_placed": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_order_permits": {
"kind": "uncoloured",
"count": {
"expression": "2",
"optimize": null
}
},
"place__s1_on_route": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_vented": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_line_running": {
"kind": "uncoloured",
"count": {
"expression": "1",
"optimize": null
}
},
"place__s1_line_stopped": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_stockouts": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_consumed": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_evaporated": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
},
"place__s1_contents": {
"kind": "uncoloured",
"count": {
"expression": "42",
"optimize": null
}
},
"place__s1_ullage": {
"kind": "uncoloured",
"count": {
"expression": "12",
"optimize": null
}
},
"place__s1_units_drawn_since_order": {
"kind": "uncoloured",
"count": {
"expression": "0",
"optimize": null
}
}
}
}
}
}
],
Expand Down
Loading
Loading