Skip to content

FE-522: Add subnets to Petrinaut#8662

Open
kube wants to merge 26 commits into
mainfrom
cf/fe-522-basic-support-for-subnets-component-based-net-composition
Open

FE-522: Add subnets to Petrinaut#8662
kube wants to merge 26 commits into
mainfrom
cf/fe-522-basic-support-for-subnets-component-based-net-composition

Conversation

@kube

@kube kube commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

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 via disabledExtensions: ["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.ts inlines this into a flat net where the port place becomes Ward1::Admit and all scoped IDs are made globally unique.

Related

What changed?

Data model & core (@hashintel/petrinaut-core)

  • New types: Subnet, ComponentInstance, ArcEndpoint discriminated union (place | componentPort), Place.isPort
  • New utility module arc-endpoints.ts — all endpoint helpers (getArcEndpoint, arcReferencesPlace, getArcEndpointKey, parseArcEndpointKey, …)
  • Mutation actions: addSubnet, removeSubnet, updateSubnet, addComponentInstance, removeComponentInstance, updateComponentInstance; arc actions extended to use endpoint
  • targetSubnetId support across all net-local mutations (places, transitions, arcs, types, parameters, differential equations)
  • Simulation: flatten-component-instances.ts — recursive inlining of the subnet hierarchy before the simulation engine runs
  • File format: Zod schemas and parser updated for subnets, component instances, and componentPort arc endpoints
  • Layout, clipboard, LSP, and file export updated for subnet-local entities and component port arcs
  • Two-flag feature gate: DEFAULT_PETRINAUT_EXTENSIONS.subnets = true (on by default at capability level); enableNetComponents UserSetting defaults to false (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 it
  • Nets List sidebar — navigate between root net and subnet definitions; subnets are renameable (double-click) and deletable from the list
  • ComponentInstanceNode — ReactFlow node with dynamic port handles; draggable and selectable like any other node
  • Component instance properties panel — rename (PascalCase enforced), parameter value overrides, delete button
  • Place properties: isPort toggle to expose a place as a subnet port
  • Arc rendering: componentPort endpoints render as edges connecting transitions to component instance port handles
  • Add-component toolbar mode + cursor tooltip for placing instances on the canvas
  • Settings → Net Components experimental toggle (ViewportSettings dialog); hidden when host disables subnets
  • PascalCase name validation on component instances, matching the place name rule; toInstanceName() derives a valid PascalCase name from the subnet display name when placing a new instance
  • Default TransitionKernel template uses scoped InstanceName::PortName keys for component-port arcs

Tests

  • Core action tests: subnet-targeted mutations, component instance lifecycle, arc endpoint cascade cleanup
  • Flattening tests: single-level subnet with port arcs
  • File-format tests: subnets, component instances, componentPort endpoints
  • LSP checker tests: subnet port type inference
  • Existing clipboard, command/mutation hook, typecheck, and build coverage

Next steps

Correctness & safety

  • FE-1060 Cycle detectionflattenNet() recurses without a visited-set; circular subnet references will stack-overflow
  • FE-1061 Silent flattening failures — broken references (missing subnet, missing port) are silently dropped; simulation produces wrong results with no user error
  • FE-1062 Bulk delete cascade — deleting a port place inside a subnet does not clean up componentPort arcs in parent nets
  • FE-1063 Parameter value validation — non-numeric strings are accepted and silently become NaN in the kernel

Data model

  • FE-1064 Enforce node IDs to UUIDs — the :: scope separator used during flattening is not guarded against in user-authored IDs; enforce UUID-format IDs to prevent collisions
  • FE-1065 Unique component instance names — no enforcement that two instances in the same net cannot share a name
  • FE-1066 Port direction — places marked isPort have no input/output/bidirectional direction; needed for cleaner arc validation and visualisation
  • FE-1067 Legacy placeId shorthand deprecation — old arcs use { placeId } directly; new arcs use { endpoint }. No migration path or lint rule yet
  • FE-1068 TypeScript type vs Zod schema alignmentArcEndpointReference allows neither/both fields at compile time; only the Zod parse boundary enforces exactly one

LSP

  • FE-1069 Subnet transitions not type-checkedgenerateVirtualFiles only iterates root-net transitions; lambda/kernel code inside subnets has no type errors or autocompletion

Simulation

  • FE-1070 Allow to run/simulate subnets — simulation is currently root-net-only; subnet hierarchy flattening works but end-to-end simulation with subnet instances needs validation and UI

Copy-paste & selection

  • FE-1071 Copy-paste for subnets — clipboard paste ignores component instances; pasting a selection that includes one silently drops it
  • FE-1072 Create component from selection — select a group of places/transitions and extract them into a new subnet instance

External nets

  • FE-1073 External net resolution — discover, fetch, and import nets from external sources as subnets (copy-once; update by re-fetching)

AI assistant integration

  • FE-1075 Expose subnet mutations to the AIaddSubnet, addComponentInstance, updateComponentInstance, removeComponentInstance are not yet surfaced as AI tool actions; the assistant cannot author or restructure subnet hierarchies
  • FE-1076 AI context for the active net — the assistant prompt currently describes the root net; when a subnet is active it should describe the subnet's local elements instead
  • FE-1077 User guide page for subnets — no subnets.md doc page exists yet; the AI cannot answer questions about how the subnet UI works or guide users through the workflow
  • FE-1078 Subnet-aware diagnostics — AI diagnostics and the schema context sent to the model do not account for component port arcs or cross-net references

Visualiser

  • FE-1079 Better rendering of subnets and ports — component instance node visual polish (port labels, direction indicators, overflow for many ports)
  • FE-1080 Expand subnet in place — inline expand a component instance to show its internals on the root canvas
  • FE-1081 ANALYSIS.md — working notes file committed to libs/@hashintel/petrinaut/; should be removed

@vercel

vercel Bot commented Apr 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jun 24, 2026 5:36pm
petrinaut Ready Ready Preview, Comment Jun 24, 2026 5:36pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jun 24, 2026 5:36pm

@cursor

cursor Bot commented Apr 28, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Large changes to the SDCPN document model, mutation validation, and simulation build path; incorrect flattening or reference cleanup could yield silent wrong simulations, though coverage is broad.

Overview
Introduces hierarchical net composition in @hashintel/petrinaut-core: subnet definitions, component instances, and Place.isPort ports, plus a discriminated ArcEndpoint model (place | componentPort) with arc-endpoints helpers while keeping legacy placeId on arcs.

Mutations and AI schemas gain subnet/component CRUD, optional targetSubnetId on net-local edits, arc actions that accept endpoint or placeId, cascade cleanup when ports/instances/subnets are removed, and default transition-kernel stubs for typed outputs (including component ports). A new subnets extension gates sanitization, selection, and port-aware lambda/kernel availability.

Simulation runs flattenComponentInstancesForSimulation before buildSimulation, inlining instances and rewriting port arcs to scoped place IDs/names. Import/export, clipboard, auto-layout, connections, and LSP virtual files are updated for subnets, instances, and Instance::Port naming.

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.

@github-actions github-actions Bot added area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team labels Apr 28, 2026
@kube kube marked this pull request as draft April 28, 2026 10:16
@kube kube changed the title Cf/fe 522 basic support for subnets component based net composition Subnets/Components and Composition Apr 28, 2026
@augmentcode

augmentcode Bot commented Apr 28, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: 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:

  • Extends the SDCPN type model with Subnet, ComponentInstance, Wire, and a Place.isPort flag.
  • Updates the file format schema and import/export helpers to include subnets/component instances and to fill/strip their visual positioning data.
  • Adds ActiveNetContext/ActiveNetProvider and migrates multiple UI panels/hooks to operate on the active net’s places/transitions/types/etc.
  • Introduces a “Nets” sidebar subview to switch between root and subnets, plus toolbar support for “add component instance” mode.
  • Enhances mutation helpers to target the active net (root or subnet) and adds CRUD helpers for subnets/component instances.
  • Adds ReactFlow rendering for component instance nodes (with port handles) and dashed “wire” edges, plus a cursor-following tooltip for add modes.
  • Adds a new “Hospital Network” example demonstrating a root net with an ER triage subnet and a component instance wired to ports.

Technical Notes: Graph layout and selection cleanup now operate on the active net; getItemType was broadened to search both root and all subnets for IDs.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode 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.

Review completed. 4 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread libs/@hashintel/petrinaut/src/state/mutation-provider.tsx Outdated
Comment thread libs/@hashintel/petrinaut/src/state/mutation-provider.tsx Outdated
Comment thread libs/@hashintel/petrinaut/src/core/types/sdcpn.ts
Comment thread libs/@hashintel/petrinaut/src/state/mutation-provider.tsx Outdated
Comment thread libs/@hashintel/petrinaut/src/state/mutation-provider.tsx Outdated
@kube kube force-pushed the cf/fe-522-basic-support-for-subnets-component-based-net-composition branch from 01705ea to 0e89ed3 Compare May 26, 2026 23:46
@github-actions github-actions Bot added the area/infra Relates to version control, CI, CD or IaC (area) label May 26, 2026
@kube kube changed the title Subnets/Components and Composition FE-522: Add subnet composition support to Petrinaut May 26, 2026
@kube kube force-pushed the cf/fe-522-basic-support-for-subnets-component-based-net-composition branch from 0e89ed3 to 8c3f8d5 Compare June 10, 2026 22:52
Comment thread apps/petrinaut-website/scripts/brunch-sse-fixture.ts Fixed
Comment thread apps/petrinaut-website/scripts/brunch-sse-fixture.ts Fixed
@kube kube changed the title FE-522: Add subnet composition support to Petrinaut FE-522: Add subnes support to Petrinaut Jun 16, 2026
@kube kube changed the title FE-522: Add subnes support to Petrinaut FE-522: Add subnets to Petrinaut Jun 16, 2026
@kube kube force-pushed the cf/fe-522-basic-support-for-subnets-component-based-net-composition branch from 83281a1 to e69d46b Compare June 16, 2026 10:14
Comment thread libs/@hashintel/petrinaut-core/src/file-format/sdcpn-to-tikz.ts
Comment thread libs/@hashintel/petrinaut-core/src/actions.ts
Comment thread libs/@hashintel/petrinaut-core/src/extensions.ts
Fix lint errors: derived state for activeSubnetId reset; merge duplicate
import in local-storage-demo-app
Copilot AI review requested due to automatic review settings June 24, 2026 15:01

@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 2 potential issues.

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

Comment thread libs/@hashintel/petrinaut-core/src/clipboard/serialize.ts

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.

Pull request overview

Copilot reviewed 95 out of 95 changed files in this pull request and generated 4 comments.

Comment thread libs/@hashintel/petrinaut/src/ui/components/arc-item.tsx
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.
Copilot AI review requested due to automatic review settings June 24, 2026 17:09

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.

Pull request overview

Copilot reviewed 95 out of 95 changed files in this pull request and generated 6 comments.

Comment thread libs/@hashintel/petrinaut/src/ui/components/arc-item.tsx
Comment thread libs/@hashintel/petrinaut-core/src/extensions.ts
Comment thread libs/@hashintel/petrinaut/docs/drawing-a-net.md Outdated
Copilot AI review requested due to automatic review settings June 24, 2026 17:28
kube and others added 2 commits June 24, 2026 19:29
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>

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.

Pull request overview

Copilot reviewed 95 out of 95 changed files in this pull request and generated 6 comments.

Comment thread libs/@hashintel/petrinaut/src/ui/components/arc-item.tsx
Comment thread libs/@hashintel/petrinaut/docs/drawing-a-net.md
Comment thread libs/@hashintel/petrinaut-core/src/extensions.ts
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/apps 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

Development

Successfully merging this pull request may close these issues.

3 participants