H-6819: Add status views, identities and a Kanban board to Petrinaut (experimental) - #9744
Draft
claude[bot] wants to merge 28 commits into
Draft
claude[bot] wants to merge 28 commits into
claude[bot] wants to merge 28 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
claude
Bot
force-pushed
the
claude/h-6819-status-views
branch
from
September 15, 2026 15:41
542c5d8 to
13ba51d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9744 +/- ##
===========================================
- Coverage 65.90% 15.35% -50.55%
===========================================
Files 1887 210 -1677
Lines 198443 6677 -191766
Branches 8248 1154 -7094
===========================================
- Hits 130774 1025 -129749
+ Misses 66139 5551 -60588
+ Partials 1530 101 -1429 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
claude
Bot
force-pushed
the
claude/h-6819-status-views
branch
from
September 15, 2026 18:30
13ba51d to
341110b
Compare
StatusView is a first-class SDCPN collection next to metrics: an ordered list of labels, each mapping a set of places (optionally instance-scoped) to a named status with a display colour, an optional token-attribute condition, and an optional exit label for instances whose token left the view's places. Label order is the array position; a moveStatusViewLabel mutation reorders labels. The instanceId::placeId convention moves from the simulation engine into a shared scoped-ids module.
…ments Identity is its own root concept: `identities` on the SDCPN root declares what a status view tracks (e.g. "ticket") and the key's element types, with two or more entries forming a compound key correlated by tuple equality. A colour element referencing an identity via `identityRef` is that identity's key element — there is no separate key flag — so keys correlate across colours without relying on element-name equality. Removing an identity clears element references and dependent status views atomically. The type properties panel gains a per-element identity picker that can also create a new identity.
…chine Failure Ticket Processing is a new example net: tickets keyed by a Ticket identity flow Todo / In Progress / In Review / Blocked / Done under one status view, with a review loop for multi-interval dwell, Done as an explicit sink place, and an Archive transition whose consumed tickets fall to the view's exit label. Production with Machine Failure gains one machine identity carried by both machine colours — the cross-colour case — with an Available / Producing / Broken / Under repair view.
A recorded firing may carry the attribute values of the tokens it consumed and produced (`inputTokens`/`outputTokens`, keyed like `input`/`output`, with scoped instanceId::placeId keys valid), so replay can correlate per-instance state. Replay removes consumed tokens by recorded value with a FIFO fallback, and the frame reader coerces recorded values into runtime token records so HIR evaluation sees them. The recording version is bumped to 2 with version 1 still accepted: old recordings parse and simply carry no token values, and an unsupported version fails explicitly rather than as a nested field error.
Status-label token conditions become a seventh HIR surface: a single boolean expression over `token`, lowered and type-checked against the attributes of the label's places' colours and evaluated by the HIR interpreter (like scenario surfaces) rather than emitted as a buffer program. compileHirArtifacts compiles every label condition and reports failures per label. A frame evaluator assigns each tracked instance its current label — labels apply in array order, keyed by the identity's key elements — and a tracker walks frames to build per-instance interval sets, falling back to the view's exit label when a token leaves the view's places. The same code runs on quick-sim and actual-mode frames.
A new Status views tab clones the metrics panel pattern: a table list, create and edit drawers, and a form that picks the identity the view tracks and edits its ordered labels — name, display colour, place multi-select including componentInstances' scoped copies of subnet places, an optional token condition, and the exit-label toggle — with row moves for reordering, since label order is the array position. Token conditions are compiled through the HIR on submit and failures block saving with the label's diagnostics. ColorSelect moves to the panels' shared folder so the type properties and status view forms use one picker.
Frame assignments now carry the place holding each instance's token, so the canvas can attribute tracked instances to component-instance nodes: a hook evaluates the net's status views against the currently viewed frame — simulation or actual, over scoped instanceId::placeId ids — and each instance node shows per-label counts as badges, with the dominant label's display colour tinting the card. Places keep their type colouring untouched.
The production-with-machine-failure scenario seeded every machine without a machine_id, so uuid coercion collapsed the whole fleet into one nil-uuid instance on the Machine status view. Seed each machine with a distinct index-derived key instead. Deleting the last status view hid the canvas/Kanban toggle while the canvas view mode stayed "kanban", leaving the net canvas unreachable. The canvas now always renders when the net has no status views.
…wrong token Recorded input tokens are removed by value with the firing's input count as the cap: records beyond the count are ignored, consumption beyond the records falls back to FIFO, and a record that matches nothing removes nothing instead of splicing out an arbitrary token of another instance. Recorded output tokens now pad up to the output count so partial recordings keep counts consistent. The protocol README documents the semantics and names the unbounded firing-log growth as a known follow-up.
…rences Token conditions no longer fail open: a declared condition without a compiled artifact matches nothing, per-place satisfiability of the condition's attribute reads is decided statically against the colour, and a genuine interpreter failure is reported through a new onConditionError callback instead of silently counting as no match. Tokens whose key element holds the type default (nil uuid, empty string) are untracked rather than merged into one phantom instance. Status-view label places and identity references are validated in addStatusView/updateStatusView, removePlace prunes deleted places out of labels, addIdentity rejects duplicate ids and names, and identity key elements must match the identity's keyElementTypes in order wherever a mutation can break that. The file format now enforces the label invariants on import, and status-condition contexts resolve scoped place ids through the component-instance path instead of a bare-id map that collided across nets. The scoped-place walker, evaluation scope, and label-place resolver move into core as status-view-scope.ts. The tracker sweeps only instances that can still exit, the evaluator decodes each place's tokens once per frame and reuses one locals map, and interpretHir reads the locals map without copying it.
…e pipeline Status-condition artifacts move into a single provider that the canvas badges and the Kanban board share, ending duplicate LSP compiles per edit; it reports pending and failure states instead of leaving a rejected compile as an unhandled rejection with conditions silently dropped. The Kanban board replays incrementally through a serialized board-replay queue (full replay only on backward scrubs or a reshaped timeline), shows replay and condition errors instead of freezing on stale data, and counts instances that match no label. The status-view drawers surface schema failures through the submit validator instead of a silent dead Save, and flag label references to places that no longer exist. Component-instance badges now count tokens for every instance along the scope path, so nested instances keep their badges when their parent subnet is opened, and the evaluation bails out before any work when the net has no instances. Identity pickers offer only identities the element can take without breaking key coherence and new identities get unique names.
…ay quadratics The Events tab's status-changes column now derives from the same frame evaluator and tracker as the Kanban board and canvas badges, so token conditions, scoped component-instance places, and the exit label behave identically across surfaces. The deriver folds in only newly appended firings, keeps a shared marking cursor so each firing is applied once, and the column header names the driving view when several exist. Dwell formatting is the shared helper on both surfaces. Actual-mode getFramesInRange replays the firing log once across the requested range through a new precomputed-marking parameter on the timeline frame reader, replacing the per-reader from-zero replay that made a Kanban render O(firings squared). The tracker exposes per-instance label states without copying interval history for consumers that diff consecutive frames, and the flattening module drops a dead local alias of formatScopedId.
normalizeSDCPN rebuilds the document from an explicit list of root collections and left out identities and statusViews, so every document opened through createJsonDocHandle lost both. Loading the Ticket Processing or Deployment Pipeline example in the website therefore showed an empty Status views panel and no canvas/Kanban toggle.
The left sidebar, properties panel, and bottom panel float over the canvas container. The net canvas can be panned out from under them, but the Kanban board has a fixed layout, so its first column and status-view selector were hidden behind the open sidebar. The board root is now absolutely positioned like the other canvas overlays, with its left, right, and bottom edges set from the panels' current sizes in EditorContext, so it occupies only the visible region and scrolls horizontally within it when columns overflow.
Clicking empty board background clears the selection, as clicking the empty net canvas does, so a properties panel opened from a sidebar list can be dismissed from the Kanban view. Cards and the status-view selector are marked interactive and keep the selection. Card keys render in the UI font instead of monospace, cards lose their coloured left border (the column header swatch already carries the label colour), and columns get a subtle border and a slightly darker surface so they read as distinct containers.
Ticket Processing keyed its identity on a uuid element the engine generated per token, so Kanban cards showed UUIDs. Kernel code cannot build strings, so the example gains a seeded backlog place instead: a TicketRequest token type carries a string id without the identity, every scenario seeds the backlog with a fixed list of ids (FE-1045...), and the create transition consumes one request per new ticket, copying its id onto the tracked Ticket. Ids stay unique and deterministic per run, and arrivals continue at the configured rate until the backlog is drained.
…xample matrix The status-view examples key their tokens on a uuid or string identity element, which WebGPU cannot represent, so the exhaustive GPU-readiness matrix now declines Production Machines and Ticket Processing on `unsupported-attribute-type`. Eligibility declines Production Machines before shader emission, so the multi-place consumer assertion no longer applies. normalizeSDCPN gains a regression test that description and metadata pass through alongside identities and status views, and stay absent when omitted.
Status views follow the other experimental surfaces: an `enableStatusViews` user setting, off by default, with a Status views row in the settings dialog. Off, the Simulate panel offers no Status views tab (a stored "status-views" mode falls back to Experiments), token type attributes show no identity picker, the canvas shows no Kanban toggle, and Actual mode's Events tab has no status changes column. The core types, actions, serialization and the canvas status badges are unaffected, so a document with identities and status views still loads and round-trips.
The website's example pages spell the editor's Simulate section and open overlay into the URL through an exhaustive contract, so the new `status-views` section and `create-status-view` overlay have to be named there for the projection to type-check.
The Load example menu offered Ticket Processing regardless of the status views setting, so a user with the setting off could load a net whose main feature the editor hides. The menu's examples now come from one list in load-example-menu.ts, where an entry can require the setting; Ticket Processing is the only one that does. The example stays exported from petrinaut-core for tests and for the website.
claude
Bot
force-pushed
the
claude/h-6819-status-views
branch
from
September 15, 2026 21:29
341110b to
2578bcf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Ciaran Morinan · Slack thread
Before: Petrinaut shows where tokens sit in a net, but it cannot say which real-world thing a token is (this ticket, that machine) or what status that thing is in. Following one ticket through a workflow, or asking how long machines spend broken, means reading places and markings by hand.
After: A document can declare identities (which token attribute is the key of an instance) and status views (named labels over sets of places, with optional token conditions). With the experimental Settings → Labs → Modeling → Status views setting on, the editor shows a Status views tab, an identity picker on token type attributes, a Kanban board toggle on the canvas, and a Status changes column in Actual mode's Events tab. Every duration comes from the firing log.
🌟 What is the purpose of this PR?
Adds status views, identities, per-instance addressing, and a Kanban board to Petrinaut, behind an experimental setting.
A status view is a set of labels on place-sets: a token in any of a label's places carries that label, an optional boolean condition on the token narrows it, and at most one exit label covers instances whose token has left the view. An identity names the key attribute that makes tokens the same instance, across token types. Status and time-in-status are derived per instance from execution frames, as intervals with entry counts, in simulated or wall-clock time. The Kanban board projects the selected view onto columns. Actual-mode token recording moves to format v2 (firings carry token values so statuses replay); v1 recordings still load. Everything user-facing is behind the
enableStatusViewssetting (Settings → Labs → Modeling → Status views), off by default; the core types, actions and file format accept identities and status views regardless so documents round-trip.🔗 Related links
🚫 Blocked by
🔍 What does this change?
@hashintel/petrinaut-core:identitiesandstatusViewson the SDCPN schema, actions, normalizer and file format;identityRefkey markers on colour elements; a shared status-condition compile pipeline that fails closed on broken conditions; per-instance status and time-in-state derived from execution frames; actual-mode recording format v2 with token values (v1 still parses); a Ticket Processing example; a status view on Production with Machine Failure.@hashintel/petrinaut: Status views authoring panel in the Simulate view; identity picker on token type attributes; status badges and tinting on component-instance nodes; Kanban board view mode and toggle; Status changes column in the Actual-mode Events tab;enableStatusViewsuser setting with a settings-dialog row; docs (status-views.md,examples.md,visual-settings.md).apps/petrinaut-website: the shared example URL contract names the Status views section and overlay.Notes for reviewers
gpu-ready.petrinaut-core(tests use it) but appears in the Load example menu only with the setting on. It is not in the website example catalog, which is a hand-listed static catalog.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:
🐾 Next steps
🛡 What tests cover this?
petrinaut-core: schema, normalizer, file-format round-trip (identities and status views), status-view validation and condition compile, per-instance status derivation, actual-mode replay, the exhaustive GPU readiness and metrics matrices, and the examples suite (now including Ticket Processing).petrinaut: settings dialog default and row, Load example menu gating (load-example-menu.test.ts), status-view form and Kanban tests, editor-view lifecycle.petrinaut-website: navigation and example URL contract tests.❓ How to test this?
📹 Demo
(none yet)
🤖 Generated with Claude Code
https://claude.ai/code/session_01NfgLsCh68QZ1jWeq1ZFNoB
Generated by Claude Code