Skip to content

Subnets/Components and Composition#8662

Draft
kube wants to merge 4 commits intomainfrom
cf/fe-522-basic-support-for-subnets-component-based-net-composition
Draft

Subnets/Components and Composition#8662
kube wants to merge 4 commits intomainfrom
cf/fe-522-basic-support-for-subnets-component-based-net-composition

Conversation

@kube
Copy link
Copy Markdown
Collaborator

@kube kube commented Apr 28, 2026

This is a draft PR, just as an exploration for what subnets and composition should be in Petrinaut.

But the actual implementation will be done after Petrinaut Core Library Extraction (FE-628).

kube and others added 4 commits April 23, 2026 11:31
Introduces the Subnet type (isolated sub-networks within a net) across
the core types, file format, import/export, mutation layer, and UI.
Adds a "Nets" subview to the left sidebar listing the root net and
subnets, with a button to create new subnets. Includes a Hospital
Network example demonstrating the feature.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces ActiveNetContext to decouple "which net is being viewed"
from the full SDCPN. Display consumers (canvas, sidebar lists,
properties panel, diagnostics) read from ActiveNetContext while
export/simulation/LSP keep reading the full SDCPN. Mutations route
through resolveNet() so edits target the active subnet.

Adds "add-component" edition mode with componentSubnetId in
EditorContext, a Component dropdown in the BottomBar toolbar (root
net only), and a cursor-following tooltip showing what will be
created on click.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lace

Introduces the ComponentInstance entity: a subnet instantiation with
parameter values, wiring (place-to-port connections), and canvas
positioning. Places gain an `isPort` flag to mark them as ports
exposed on component instances.

Rendering: sharp-cornered rectangle node with port handles derived
from the subnet's port places. Wiring rendered as a dedicated "wire"
edge type (dashed, bezier) distinct from arcs. Edges array replaces
the former arcs-only array to hold both arc and wire edge types.

Mutations: addComponentInstance, updateComponentInstance,
removeComponentInstance, plus deleteItemsByIds and
commitNodePositions support.

Hospital Network example updated with an ER Triage component
instance wired to the root net.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Render a properties panel when a component instance node is selected,
showing instance details and parameter overrides for the underlying
subnet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Apr 28, 2026 10:15am
petrinaut Ready Ready Preview, Comment Apr 28, 2026 10:15am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Apr 28, 2026 10:15am

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 28, 2026

PR Summary

Medium Risk
Introduces new SDCPN data structures (subnets, componentInstances, wiring) and routes most editor mutations/rendering through an ActiveNet abstraction, which can affect many core edit flows and file import/export compatibility.

Overview
Adds basic subnet-based composition to Petrinaut by extending the SDCPN schema with subnets, componentInstances, port places (Place.isPort), and wiring, plus a new hospitalNetwork example demonstrating the format.

Introduces an ActiveNetProvider to switch the editor between the root net and a selected subnet, updating sidebar lists, diagnostics, selection cleanup, parameter defaults, graph layout, and mutation helpers to operate on the active net.

Adds UI for managing/viewing nets (new Nets sidebar subview), creating component instances from the toolbar (add-component mode + cursor tooltip), rendering component instance nodes with port handles, and drawing dashed wire edges; selection/properties support is extended to componentInstance items. File import/remove-visual-info and Zod schemas are updated to handle subnets/component instances and their positions.

Reviewed by Cursor Bugbot for commit 01705ea. 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
Copy link
Copy Markdown

augmentcode Bot commented Apr 28, 2026

🤖 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 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

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.

@@ -75,12 +89,13 @@ export const MutationProvider: React.FC<MutationProviderProps> = ({
},
removePlace(placeId) {
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libs/@hashintel/petrinaut/src/state/mutation-provider.tsx:L90 — When a place is removed from a net, any componentInstances[].wiring entries that reference it (as externalPlaceId, or indirectly via a port ID) aren’t cleaned up, which can leave dangling wire edges/handles in the ReactFlow view. This same issue can also occur when places are deleted via deleteItemsByIds (wires aren’t considered there either).

Severity: medium

Other Locations
  • libs/@hashintel/petrinaut/src/state/mutation-provider.tsx:403

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

sdcpn.subnets = subnets;
});
},
removeSubnet(subnetId) {
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libs/@hashintel/petrinaut/src/state/mutation-provider.tsx:L389 — removeSubnet removes the subnet definition but doesn’t address any componentInstances (in the root net or other nets) that reference that subnetId, which can leave instances/wires pointing at non-existent ports. Consider either preventing subnet deletion while referenced or cleaning up dependent instances/wiring to avoid inconsistent state.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

);
const rafRef = useRef(0);

useEffect(() => {
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libs/@hashintel/petrinaut/src/views/SDCPN/components/cursor-tooltip.tsx:L40 — This useEffect attaches a global mousemove listener and calls setPosition(...) on every mouse move even when not in an add mode (when the tooltip returns null). That can cause unnecessary re-renders across long sessions; consider only subscribing/updating while label is non-null (i.e., when the tooltip would actually render).

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

};
};

/**
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libs/@hashintel/petrinaut/src/core/types/sdcpn.ts:L117 — The JSDoc for “An instance of a subnet…” currently sits above Wire, so it looks like it’s documenting the wrong type (and the Wire docblock follows immediately after). Consider moving that first docblock onto ComponentInstance to avoid misleading generated docs/tooltips.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 3 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 01705ea. Configure here.

type === "place" ||
type === "transition" ||
type === "componentInstance"
) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Component instances treated as non-canvas items in selection

Medium Severity

The hasNonCanvasItems check (around line 86) only considers place, transition, and arc as canvas item types. Since this PR adds componentInstance as a new canvas node type, any selected component instance is incorrectly treated as a "non-canvas" item. This causes the selection base to be cleared when a component instance is in the selection and the user interacts with canvas selection, breaking multi-select behavior for component instances.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01705ea. Configure here.

},
commitNodePositions(commits) {
guardedMutate((sdcpn) => {
const net = resolveNet(sdcpn);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paste always targets root net, ignoring active subnet

Medium Severity

pasteEntities calls pasteFromClipboard(mutatePetriNetDefinition) which directly mutates the root SDCPN's places, transitions, etc. arrays. Unlike all other mutation functions in this provider, it does not use resolveNet to target the active net. When a user is viewing a subnet and pastes, entities are incorrectly added to the root net instead of the active subnet.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01705ea. Configure here.

break;
}
}
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing subnet leaves dangling component instance references

Medium Severity

removeSubnet splices the subnet from the array but does not clean up componentInstances in the root net (or other subnets) whose subnetId references the deleted subnet. Other removal functions like removeType and removeDifferentialEquation follow a pattern of clearing dangling references, but removeSubnet does not, leaving orphaned component instances pointing to a non-existent subnet.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01705ea. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

1 participant