H-6519: Add discrete token attribute types#8764
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryHigh Risk Overview In parallel, adds subnet composition: reusable Reviewed by Cursor Bugbot for commit edd4758. Bugbot is set up for automated code reviews on this repo. Configure here. |
| if (value === undefined || value === null || value === "") { | ||
| return NIL_UUID; | ||
| } | ||
| if (typeof value !== "string" || !UUID_RE.test(value)) { |
There was a problem hiding this comment.
Semgrep identified an issue in your code:
User-supplied UUID input is validated with a regex (UUID_RE.test(value)) that could be vulnerable to ReDoS attacks if the pattern uses inefficient backtracking constructs.
More details about this
The UUID_RE regex is being used to validate user-supplied input via the value parameter in the coerceUuid() function. If UUID_RE is not carefully constructed, an attacker could provide a malicious input string that causes the regex engine to hang or consume excessive CPU time (ReDoS - Regular Expression Denial of Service).
Attack scenario: An attacker could call this validation function with a specially crafted string (for example, a very long string of characters that almost—but not quite—match the UUID pattern, like "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@" repeated many times). When UUID_RE.test(value) executes against this string, the regex backtracking could cause the application to freeze, making the service unavailable to legitimate users.
The vulnerability depends on the actual regex pattern in UUID_RE (not shown here), but common ReDoS patterns include nested quantifiers like (a+)+ or overlapping alternatives that force excessive backtracking on non-matching input.
To resolve this comment:
✨ Commit fix suggestion
| if (typeof value !== "string" || !UUID_RE.test(value)) { | |
| function isHexDigit(char: string): boolean { | |
| return ( | |
| (char >= "0" && char <= "9") || | |
| (char >= "a" && char <= "f") || | |
| (char >= "A" && char <= "F") | |
| ); | |
| } | |
| function validateUuid(value: string): true | string { | |
| if (value.length !== 36) { | |
| return "invalid length"; | |
| } | |
| for (let index = 0; index < value.length; index += 1) { | |
| const char = value[index]; | |
| if (index === 8 || index === 13 || index === 18 || index === 23) { | |
| if (char !== "-") { | |
| return "invalid hyphen placement"; | |
| } | |
| continue; | |
| } | |
| if (!isHexDigit(char)) { | |
| return "invalid character"; | |
| } | |
| } | |
| return true; | |
| } | |
| function coerceUuid(value: unknown, context: string): string { | |
| if (value === undefined || value === null || value === "") { | |
| return NIL_UUID; | |
| } | |
| if (typeof value !== "string") { | |
| throw new Error(`${context} must be a UUID string.`); | |
| } | |
| const normalized = value.trim(); | |
| const validation = validateUuid(normalized); | |
| if (validation !== true) { | |
| throw new Error(`${context} must be a UUID string.`); | |
| } | |
| return normalized.toLowerCase(); | |
| } |
View step-by-step instructions
-
Replace the regex-based UUID check with a dedicated validator function so request data is not matched against a potentially expensive regex.
-
Add a helper such as
validateUuid(value: string): true | stringthat validates UUIDs with simple fixed checks instead ofUUID_RE.test(...).
For example, checkvalue.length === 36, check hyphens at positions8,13,18, and23, and verify every other character is a hex digit with a small character check likechar >= "0" && char <= "9"orchar.toLowerCase() >= "a" && char.toLowerCase() <= "f". -
Update
coerceUuid()to call the new helper after the type check.
For example, change the condition fromtypeof value !== "string" || !UUID_RE.test(value)totypeof value !== "string"followed byconst validation = validateUuid(value); if (validation !== true) { throw new Error(\${context} must be a UUID string.`); }`. -
Keep the existing normalization step and return the lowercase value after validation with
return value.toLowerCase();.
This preserves the current behavior while removing the regex denial-of-service risk. -
If this code accepts user input with surrounding whitespace, trim before validating by using
const normalized = value.trim();and validatenormalizedinstead of the raw string. Then returnnormalized.toLowerCase()so valid values are stored consistently.
Alternatively, if the UUID must specifically be RFC 4122 v1-v5, add fixed character checks for the version and variant positions as part of validateUuid, such as restricting index 14 to 1-5 and index 19 to 8, 9, a, or b.
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by regex_dos.
You can view more details about this finding in the Semgrep AppSec Platform.
27d3d08 to
a7c19d4
Compare
| }; | ||
|
|
||
| const formatCellValue = (value: SpreadsheetCellValue): string => | ||
| typeof value === "boolean" ? String(value) : String(value); |
There was a problem hiding this comment.
Redundant conditional in formatCellValue does nothing
Low Severity
formatCellValue has a ternary that returns String(value) in both branches — the typeof value === "boolean" check is a no-op. This was likely intended to format booleans differently (e.g., capitalizing or showing a symbol), but as written, the conditional adds confusion without changing behavior.
Reviewed by Cursor Bugbot for commit a7c19d4. Configure here.
- Add `subnets` to PetrinautExtension; gate Nets List sidebar, ComponentDropdown, and componentInstance selection on it - Demo website (petrinaut-website) disables subnets via handle capabilities - Add two Storybook stories for subnets: with and without colours (hospital network) - Disable Play button and show tooltip when viewing a subnet; only root net can be simulated - Fix simulation crash: frame store in main thread was built from the unflattened SDCPN (3 places), while the worker produced frames from the flattened SDCPN (6 places), causing an EngineFrame place count mismatch; main thread now mirrors the worker's flatten step so both sides share the same layout - Remove accidentally committed ANALYSIS.md
Add five new example SDCPNs demonstrating component-based composition with multiple instances of the same subnet at different parameter values: - Manufacturing Pipeline (3 ProcessingStation stages — Cutting/Welding/Painting, Welding is bottleneck) - Task Worker Pool (Fast/Standard/Slow workers competing for a shared queue, with internal retry logic) - Airport Terminals (International/Domestic/Charter — parallel flows into shared departures) - Retail Supply Chain (Flagship/Suburban/Online channels fanning out from a warehouse) - Power Generation Grid (Coal/Gas/Peaker plants sharing a fuel reserve and electricity grid) Restructure the Load Example submenu into three labelled groups: "Getting started", "Stochastic", and "Subnets". The five new subnet examples only appear in the menu when extensions.subnets is enabled.
…t ports - Change flattening to use `::` separator for component port place names - Update LSP type generation to use scoped names for component ports - Update tests to expect the new `InstanceName::PortPlaceName` format This harmonizes the typing and runtime expectations for TransitionKernel, ensuring both use the same `::` separator as the flattening algorithm. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Subnets list: delete button (hover-reveal trash) and inline double-click rename for subnet entries; root net has neither action - Component instance properties panel: trash button in header, matching the place panel pattern - ComponentInstance name field now enforces PascalCase (entityNameSchema) matching the place name rule; UI shows inline validation error on blur - toInstanceName() converts free-form subnet display names to valid PascalCase when placing a new instance on the canvas - Fix power-generation-grid examples to use PascalCase instance names
- Delete the 6 subnet example files (airport-terminals, hospital-network, manufacturing-pipeline, power-generation-grid, retail-supply-chain, task-worker-pool) and remove their exports from examples/index.ts - Remove the "Subnets" group from the Load Example menu; the Getting Started and Stochastic groups remain unchanged - Add enableNetComponents UserSetting (default off) with a switch in the ViewportSettings dialog under General (Experimental) - Gate the Nets List subview in the LeftSideBar on enableNetComponents in addition to extensions.subnets - Use sirModel as fallback for SubnetsWithColors/SubnetsWithoutColors stories now that hospitalNetworkSDCPN is removed
…over enableNetComponents extensions.subnets (Handle) is enabled by default and gates all subnet functionality. enableNetComponents (UserSetting) is off by default and only controls the Nets subview and Add Component button — both of which also require extensions.subnets to be true. The Net Components toggle in ViewportSettings is hidden when the host has disabled subnets via the handle capabilities.
…tale destructure, fix a11y span
- nets-list: use a cancellingRef so Escape does not commit the rename via the onBlur that fires when the input unmounts - active-net-provider: reset activeSubnetId to null when petriNetId changes so switching nets does not leak subnet view state
…t-based-net-composition
Fix lint errors: derived state for activeSubnetId reset; merge duplicate import in local-storage-demo-app
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
a7c19d4 to
edd4758
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 3 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit edd4758. Configure here.
| outputArcs: transition.outputArcs.filter((arc) => { | ||
| const placeId = getArcEndpointPlaceId(arc); | ||
| return placeId ? selectedPlaceIds.has(placeId) : false; | ||
| }), |
There was a problem hiding this comment.
Copy drops component-port arcs
Medium Severity
When building a clipboard payload, transition arcs are kept only if getArcEndpointPlaceId returns a selected place ID. Component-port arcs have no place ID, so they are always removed even when the related transition and component instance are copied, leaving pasted transitions unwired.
Reviewed by Cursor Bugbot for commit edd4758. Configure here.
| if (flatPlaceIds.has(placeId) || !rootPlaceIds.has(placeId)) { | ||
| flatInitialMarking[placeId] = value; | ||
| } | ||
| } |
There was a problem hiding this comment.
Flatten breaks subnet initial marking
High Severity
After flattening component instances, place IDs in the net are rewritten to scoped IDs, but initialMarking keys are copied without the same mapping. Scenario or compiled markings keyed by subnet place IDs no longer match flattened places, so simulation build can fail validation or start with missing tokens on inlined places.
Reviewed by Cursor Bugbot for commit edd4758. Configure here.
There was a problem hiding this comment.
Pull request overview
This PR extends Petrinaut to support discrete token attribute types (integer/boolean/uuid in addition to real) across schema, simulation encoding/decoding, scenario/initial marking handling, and UI surfaces; it also introduces subnet/component-instance scaffolding (ports, instances, and active-net scoping) to support hierarchical net composition.
Changes:
- Add typed token plumbing end-to-end (schema types, codecs, frame payloads/readers, scenario compilation, and UI editors/visualizers).
- Introduce component instances + subnets and update editor state/UI to support selecting and editing an “active net” (root vs subnet).
- Update authoring surfaces (transition editors, properties panels, left sidebar, toolbar) to reflect the new structures and token typing.
Reviewed changes
Copilot reviewed 121 out of 121 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/@hashintel/petrinaut/src/ui/views/shared/place-state-visualization.tsx | Use typed TokenRecord tokens from frame reader/marking. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/reactflow-types.ts | Add component-instance node types; rename arcs→edges. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/node-dimensions.ts | Add component-instance node dimensions. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/hooks/use-sdcpn-to-react-flow.ts | Build component-instance nodes and port-handle edges. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/hooks/use-apply-node-changes.ts | Include component instances in selection/position commits. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-settings-dialog.tsx | Add experimental “Net Components” toggle. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/mini-map.tsx | Render component-instance nodes in minimap. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/cursor-tooltip.tsx | Tooltip for add-place/transition/component modes. |
| libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/component-instance-node.tsx | ReactFlow node renderer for component instances + ports. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/scenarios/view-scenario-drawer.tsx | Scenario form defaults accept typed token rows. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/scenarios/scenario-mapping.ts | Update scenario mapping comment for typed rows. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/scenarios/scenario-form.tsx | Spreadsheet initial-state data uses typed cell values. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/experiments-story-fixtures.tsx | Update fixtures for new editor actions. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/type-properties/subviews/main.tsx | Add dimension type selector (real/int/bool/uuid). |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/transition-properties/subviews/transition-results/subview.tsx | Kernel template generation supports component-port endpoints + typed tokens. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/transition-properties/subviews/transition-firing-time/subview.tsx | Guard Monaco onChange undefined values. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/transition-properties/subviews/main.tsx | Arc endpoint handling supports component ports in UI. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/transition-properties/main.tsx | Thread active net into transition properties provider. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/transition-properties/context.tsx | Provider now supplies full SDCPN + active-net info. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/properties-panel.stories.tsx | Story updates for endpoint-based arc APIs. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/place-properties/subviews/place-initial-state/subview.tsx | Pass full Place into initial-state editor. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/place-properties/subviews/place-initial-state/initial-state-editor.tsx | Spreadsheet editor supports typed values + defaults. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/place-properties/subviews/main.tsx | Add “Component port” place property; use ActiveNetContext. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/panel.tsx | Add component-instance properties panel; use ActiveNetContext. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/multi-selection-panel.tsx | Add label for component instance multi-select. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/component-instance-properties/subviews/main.tsx | New component-instance properties subview. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/component-instance-properties/main.tsx | New container wiring for component-instance panel. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/component-instance-properties/context.tsx | New context for component-instance properties. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/arc-properties/main.tsx | Arc properties support endpoint keys + component ports. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/types-list.tsx | Types list uses active net. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/parameters-list.tsx | Parameters list uses active net. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/nodes-list.tsx | Nodes list uses active net; type tweaks. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/nets-list.tsx | New nets (root/subnet) selector with rename/delete. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/entities-tree.tsx | Entities tree uses ActiveNetContext for items. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/subviews/differential-equations-list.tsx | Differential equations list uses active net; null colorId default. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/LeftSideBar/panel.tsx | Gate nets subview behind extension + user setting. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/BottomPanel/subviews/simulation-timeline/legend.test.tsx | Test comment wording update. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/tool-summaries.ts | AI tool summaries support arc endpoints + component ports. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/editor-view.tsx | Initialize SDCPN with subnets/componentInstances; reorder examples. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/use-keyboard-shortcuts.ts | “Select all” includes component instances; use active net for copy. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/toolbar-modes.tsx | Add “Add component” dropdown (root-only, gated). |
| libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/simulation-controls.tsx | Disable simulation controls when inside subnet view. |
| libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/bottom-bar.tsx | Reset non-cursor edition modes when leaving edit; pass inSubnet. |
| libs/@hashintel/petrinaut/src/ui/petrinaut.tsx | Doc wording update. |
| libs/@hashintel/petrinaut/src/ui/petrinaut.stories.tsx | Add subnet-related story variants. |
| libs/@hashintel/petrinaut/src/ui/lib/compile-visualizer.ts | Visualizer token prop accepts typed values. |
| libs/@hashintel/petrinaut/src/ui/constants/ui-subviews.ts | Add nets subview; tighten typing with satisfies. |
| libs/@hashintel/petrinaut/src/ui/components/spreadsheet.stories.tsx | Spreadsheet story uses typed cell values. |
| libs/@hashintel/petrinaut/src/ui/components/arc-item.tsx | Arc list item supports label/color + endpoint IDs. |
| libs/@hashintel/petrinaut/src/react/state/user-settings-provider.tsx | Add action to set enableNetComponents. |
| libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts | Add enableNetComponents setting + defaults. |
| libs/@hashintel/petrinaut/src/react/state/use-selection-cleanup.ts | Selection cleanup supports endpoint arc IDs + component instances. |
| libs/@hashintel/petrinaut/src/react/state/sdcpn-context.ts | Add componentInstance selection type; default SDCPN includes subnets/instances. |
| libs/@hashintel/petrinaut/src/react/state/editor-provider.tsx | Add add-component edition mode + componentSubnetId state; use active net for connections. |
| libs/@hashintel/petrinaut/src/react/state/editor-context.ts | Add add-component edition mode + action; store componentSubnetId. |
| libs/@hashintel/petrinaut/src/react/state/active-net-provider.tsx | New provider deriving active net from SDCPN + active subnet selection. |
| libs/@hashintel/petrinaut/src/react/state/active-net-context.ts | New context for active net definition + active subnet ID. |
| libs/@hashintel/petrinaut/src/react/simulation/provider.tsx | Minor comment tweak. |
| libs/@hashintel/petrinaut/src/react/sdcpn-provider.tsx | getItemType recognizes items across root + subnets + instances. |
| libs/@hashintel/petrinaut/src/react/petrinaut-provider.tsx | Wire in ActiveNetProvider. |
| libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-mutations.ts | Mutations inject targetSubnetId by default; subnets/instances mutations added. |
| libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-mutations.test.tsx | Update test context for new editor action. |
| libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-commands.ts | Commands inject targetSubnetId. |
| libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-commands.test.tsx | Update test context for new editor action. |
| libs/@hashintel/petrinaut/docs/petri-net-extensions.md | Doc update for typed kernel template insertion. |
| libs/@hashintel/petrinaut/docs/drawing-a-net.md | Document component ports + port arcs. |
| libs/@hashintel/petrinaut-core/src/types/selection.ts | Add componentInstance to selection union. |
| libs/@hashintel/petrinaut-core/src/types/sdcpn.ts | Add token typing, arc endpoints, subnets, component instances, ports. |
| libs/@hashintel/petrinaut-core/src/simulation/worker/simulation.worker.ts | Include discrete-values snapshot in frame payload. |
| libs/@hashintel/petrinaut-core/src/simulation/worker/frame-payload.ts | Add discreteValues to payload. |
| libs/@hashintel/petrinaut-core/src/simulation/runtime/simulation.ts | Flatten components for frame-store layout; merge parameter defaults. |
| libs/@hashintel/petrinaut-core/src/simulation/runtime/frame-store.ts | Thread discrete-values into frame readers. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/transition-effect.ts | Decode typed inputs + encode typed outputs via codec. |
| libs/@hashintel/petrinaut-core/src/simulation/frames/frame-reader.ts | Decode typed token attributes using discrete-values snapshot. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/types.ts | TokenRecord/typed kernel output + tokenValueCodec on simulation instance. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/token-values.ts | New encode/decode/coercion helpers + TokenValueCodec. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/execute-transitions.test.ts | Update tests for endpoint place IDs + codec presence. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-possible-transition.ts | Decode/encode typed tokens for transitions. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-possible-transition.test.ts | Add typed token encode/decode coverage. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/check-transition-enablement.ts | Reject component-port endpoints in unflattened enablement checks. |
| libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/compile-scenario.ts | Coerce typed row values into TokenRecords. |
| libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/compile-scenario.test.ts | Add typed scenario row coercion coverage. |
| libs/@hashintel/petrinaut-core/src/simulation/authoring/metric/compile-metric.ts | Metrics receive typed TokenRecords. |
| libs/@hashintel/petrinaut-core/src/simulation/api.ts | Initial marking + frame-reader APIs use TokenRecord. |
| libs/@hashintel/petrinaut-core/src/schemas/scenario-schema.ts | Allow typed token row cell values in schema. |
| libs/@hashintel/petrinaut-core/src/schemas/metric-schema.ts | Update schema description for typed tokens. |
| libs/@hashintel/petrinaut-core/src/lsp/lib/checker.test.ts | LSP checks cover component-port typed inputs/outputs. |
| libs/@hashintel/petrinaut-core/src/lib/get-connections.ts | Connection graph supports endpoint arc IDs + component instances. |
| libs/@hashintel/petrinaut-core/src/layout/dimensions.ts | Add component instance dimensions for layout. |
| libs/@hashintel/petrinaut-core/src/layout/calculate-graph-layout.ts | Layout includes component instances + endpoint node IDs. |
| libs/@hashintel/petrinaut-core/src/index.ts | Export arc-endpoint helpers; export subnet/component schemas. |
| libs/@hashintel/petrinaut-core/src/handle/json-doc-handle/create-json-doc-handle.test.ts | Capabilities include subnets. |
| libs/@hashintel/petrinaut-core/src/file-format/types.ts | File format supports subnets + component instances. |
| libs/@hashintel/petrinaut-core/src/file-format/sdcpn-to-tikz.ts | TikZ export uses endpoint place IDs when possible. |
| libs/@hashintel/petrinaut-core/src/file-format/remove-visual-info.ts | Strip visual info from subnets/instances too. |
| libs/@hashintel/petrinaut-core/src/file-format/parse-sdcpn-file.ts | Parse/fill visual info for subnets + instances. |
| libs/@hashintel/petrinaut-core/src/file-format/parse-sdcpn-file.test.ts | Import tests for subnets/instances + missing positions. |
| libs/@hashintel/petrinaut-core/src/extensions.test.ts | Extension logic covers component-port arcs + sanitization. |
| libs/@hashintel/petrinaut-core/src/default-codes.ts | Default code templates respect typed token attributes. |
| libs/@hashintel/petrinaut-core/src/commands.ts | Commands target active subnet; layout/paste support subnet targets. |
| libs/@hashintel/petrinaut-core/src/commands.test.ts | Tests for subnet paste/layout targeting. |
| libs/@hashintel/petrinaut-core/src/command-schemas.ts | Command schema accepts targetSubnetId. |
| libs/@hashintel/petrinaut-core/src/clipboard/serialize.ts | Clipboard serialization filters arcs via endpoint place IDs. |
| libs/@hashintel/petrinaut-core/src/clipboard/paste.ts | Clipboard paste maps arcs via endpoint place IDs. |
| libs/@hashintel/petrinaut-core/src/arc-endpoints.ts | New helpers for typed arc endpoints + keys. |
| libs/@hashintel/petrinaut-core/src/ai.ts | AI guidance updated for typed tokens + typed scenarios. |
| apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx | Demo handle capabilities + “empty SDCPN” check includes subnets/scenarios. |
| .changeset/quiet-subnets-compose.md | Changeset for subnet/component support. |
| .changeset/h-6519-discrete-token-attribute-types.md | Changeset for discrete token attribute types. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ?.map((pl) => ({ | ||
| value: pl.id, | ||
| text: pl.name, | ||
| })) | ||
| .concat( |
| onKeyDown={(event) => { | ||
| if (event.key === "Enter" || event.key === " ") { | ||
| handleSelect(null); | ||
| } | ||
| }} |
| onKeyDown={(event) => { | ||
| if (event.key === "Enter" || event.key === " ") { | ||
| handleSelect(subnet.id); | ||
| } | ||
| }} |
| Object.assign( | ||
| arc, | ||
| newEndpoint.kind === "place" | ||
| ? { placeId: newEndpoint.placeId } | ||
| : { endpoint: newEndpoint }, | ||
| ); |


🌟 What is the purpose of this PR?
Adds support for discrete token attribute types in Petrinaut, so coloured token dimensions can be represented as
integer,boolean, oruuidvalues in addition to continuousrealvalues.This updates the model schema, simulator runtime, code authoring surface, and editor UI so typed token values can be created, simulated, displayed, and passed into user-authored Petrinaut code consistently.
🔗 Related links
🔍 What does this change?
real,integer,boolean, anduuid.number | boolean | stringvalues throughout Petrinaut core APIs.@hashintel/petrinautand@hashintel/petrinaut-core.Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
🛡 What tests cover this?
yarn workspace @hashintel/petrinaut-core test:unityarn workspace @hashintel/petrinaut test:unityarn exec turbo run lint:tsc --filter '@hashintel/petrinaut-core' --filter '@hashintel/petrinaut'yarn exec turbo run lint:eslint --filter '@hashintel/petrinaut-core' --filter '@hashintel/petrinaut'yarn exec oxfmt --check $(git diff --name-only --diff-filter=ACM) libs/@hashintel/petrinaut-core/src/simulation/engine/token-values.tsgit diff --check❓ How to test this?