Skip to content

FE-522: Add subnets to Petrinaut#8662

Merged
kube merged 28 commits into
mainfrom
cf/fe-522-basic-support-for-subnets-component-based-net-composition
Jul 1, 2026
Merged

FE-522: Add subnets to Petrinaut#8662
kube merged 28 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

@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 Jul 1, 2026 2:51pm
petrinaut Ready Ready Preview, Comment Jul 1, 2026 2:51pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 1, 2026 2:51pm

@cursor

cursor Bot commented Apr 28, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Large, cross-cutting changes to the SDCPN model, mutations, and simulation flattening; incorrect hierarchy or port references could yield silent wrong simulation results until follow-up hardening lands.

Overview
Adds hierarchical net composition to Petrinaut: reusable subnet definitions, component instances on the canvas, and arcs that can target either a place or a componentPort on an instance (via new arc-endpoints helpers and Zod schemas).

Core mutations and AI surface gain subnet/component CRUD, optional targetSubnetId on net-local edits (root vs subnet body), stricter arc inputs (placeId xor endpoint), and cascade cleanup when ports, instances, or subnets are removed. Transition sanitization can seed default TransitionKernel templates for typed outputs, including scoped InstanceName::PortName keys for port arcs.

Simulation flattens component hierarchies before buildSimulation runs so the engine still sees a flat net with scoped place IDs and parameter overrides. Extensions add subnets (default on); disabling it strips component-port arcs and subnet data.

File import/export, auto-layout, clipboard paste, LSP virtual files (scoped port names in lambda/kernel types), and connection/arc-id logic are updated for the new model. The local-storage demo treats subnets/instances in “empty net” checks and passes explicit handle capabilities.

Reviewed by Cursor Bugbot for commit 21e3dd5. 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

@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
CiaranMn
CiaranMn previously approved these changes Jun 30, 2026

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 2 comments.

Comment thread libs/@hashintel/petrinaut/src/ui/components/arc-item.tsx
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.

4 participants