FE-522: Add subnets to Petrinaut#8662
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryMedium Risk Overview Mutations and AI schemas gain subnet/component CRUD, optional Simulation runs The local-storage demo treats subnets/instances in empty-net checks and passes explicit handle capabilities. Reviewed by Cursor Bugbot for commit f5ff53b. Bugbot is set up for automated code reviews on this repo. Configure here. |
🤖 Augment PR SummarySummary: This draft PR explores “subnets” and component-based composition in Petrinaut by introducing a notion of an “active net” (root vs selected subnet) and rendering subnet instances as nodes with wiring. Changes:
Technical Notes: Graph layout and selection cleanup now operate on the active net; 🤖 Was this summary useful? React with 👍 or 👎 |
01705ea to
0e89ed3
Compare
0e89ed3 to
8c3f8d5
Compare
83281a1 to
e69d46b
Compare
…t-based-net-composition
Fix lint errors: derived state for activeSubnetId reset; merge duplicate import in local-storage-demo-app
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f617c86. Configure here.
Use InstanceName::PortName as the kernel key for componentPort arc endpoints so the generated template matches the scoped names the simulation engine produces after flattening.
…t-based-net-composition
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

What is this PR?
Adds basic subnet composition support to Petrinaut — the first step toward hierarchical net modelling. A net can now define reusable subnet definitions and place component instances of them on the canvas. Transitions connect directly to component instance ports via a typed arc endpoint model. At simulation time the entire hierarchy is recursively flattened into an equivalent flat net, leaving the simulation engine untouched.
Feature flags:
extensions.subnets(Handle capability) — enabled by default; hosts opt out viadisabledExtensions: ["subnets"]enableNetComponents(User Setting) — off by default; users enable it via Settings → Net Components, which reveals the Nets sidebar and the Add Component toolbar button. The toggle is hidden from Settings when the host has disabled subnets at the handle level.The feature is therefore available on all Petrinaut instances by default, but invisible in the UI until the user explicitly turns it on.
Serialized file format example
{ "places": [], "transitions": [ { "id": "t_send", "name": "Send", "inputArcs": [], "outputArcs": [ { "endpoint": { "kind": "componentPort", "componentInstanceId": "inst_ward1", "portPlaceId": "p_admit" }, "weight": 1 } ], "lambdaType": "stochastic", "lambdaCode": "export default Lambda(() => 1)", "transitionKernelCode": "" } ], "componentInstances": [ { "id": "inst_ward1", "name": "Ward1", "subnetId": "subnet_ward", "parameterValues": { "param_capacity": "20" }, "x": 300, "y": 100 } ], "subnets": [ { "id": "subnet_ward", "name": "Hospital Ward", "places": [ { "id": "p_admit", "name": "Admit", "isPort": true, "colorId": null, "dynamicsEnabled": false, "differentialEquationId": null, "x": 0, "y": 0 }, { "id": "p_beds", "name": "Beds", "colorId": null, "dynamicsEnabled": false, "differentialEquationId": null, "x": 200, "y": 0 } ], "transitions": [ ... ], "parameters": [ { "id": "param_capacity", "name": "Capacity", "variableName": "capacity", "type": "integer", "defaultValue": "10" } ], "types": [], "differentialEquations": [], "componentInstances": [] } ], "types": [], "parameters": [], "differentialEquations": [] }At simulation time
flatten-component-instances.tsinlines this into a flat net where the port place becomesWard1::Admitand all scoped IDs are made globally unique.Related
What changed?
Data model & core (
@hashintel/petrinaut-core)Subnet,ComponentInstance,ArcEndpointdiscriminated union (place|componentPort),Place.isPortarc-endpoints.ts— all endpoint helpers (getArcEndpoint,arcReferencesPlace,getArcEndpointKey,parseArcEndpointKey, …)addSubnet,removeSubnet,updateSubnet,addComponentInstance,removeComponentInstance,updateComponentInstance; arc actions extended to useendpointtargetSubnetIdsupport across all net-local mutations (places, transitions, arcs, types, parameters, differential equations)flatten-component-instances.ts— recursive inlining of the subnet hierarchy before the simulation engine runscomponentPortarc endpointsDEFAULT_PETRINAUT_EXTENSIONS.subnets = true(on by default at capability level);enableNetComponentsUserSetting defaults tofalse(UI hidden until user opts in)Editor UI (
@hashintel/petrinaut)ActiveNetProvider— React context tracking which net (root or subnet) is currently being edited; resets on net switch; all editor panels and canvas operations read from itComponentInstanceNode— ReactFlow node with dynamic port handles; draggable and selectable like any other nodeisPorttoggle to expose a place as a subnet portcomponentPortendpoints render as edges connecting transitions to component instance port handlestoInstanceName()derives a valid PascalCase name from the subnet display name when placing a new instanceInstanceName::PortNamekeys for component-port arcsTests
componentPortendpointsNext steps
Correctness & safety
flattenNet()recurses without a visited-set; circular subnet references will stack-overflowcomponentPortarcs in parent netsNaNin the kernelData model
::scope separator used during flattening is not guarded against in user-authored IDs; enforce UUID-format IDs to prevent collisionsisPorthave no input/output/bidirectional direction; needed for cleaner arc validation and visualisationplaceIdshorthand deprecation — old arcs use{ placeId }directly; new arcs use{ endpoint }. No migration path or lint rule yetArcEndpointReferenceallows neither/both fields at compile time; only the Zod parse boundary enforces exactly oneLSP
generateVirtualFilesonly iterates root-net transitions; lambda/kernel code inside subnets has no type errors or autocompletionSimulation
Copy-paste & selection
External nets
AI assistant integration
addSubnet,addComponentInstance,updateComponentInstance,removeComponentInstanceare not yet surfaced as AI tool actions; the assistant cannot author or restructure subnet hierarchiessubnets.mddoc page exists yet; the AI cannot answer questions about how the subnet UI works or guide users through the workflowVisualiser
ANALYSIS.md— working notes file committed tolibs/@hashintel/petrinaut/; should be removed