Skip to content

FE-1153: Collapse per-type switches into a type-policy registry#8964

Open
kube wants to merge 1 commit into
cf/fe-769-add-string-discrete-type-supportfrom
cf/fe-1153-petrinaut-collapse-per-type-switches-into-a-type-policy
Open

FE-1153: Collapse per-type switches into a type-policy registry#8964
kube wants to merge 1 commit into
cf/fe-769-add-string-discrete-type-supportfrom
cf/fe-1153-petrinaut-collapse-per-type-switches-into-a-type-policy

Conversation

@kube

@kube kube commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

Pure refactor closing out the discrete-types architecture retrospective: adding a token dimension type previously meant editing switch (element.type) statements in seven far-apart places (buffer layout, coercion/defaults, generated kernel code, LSP virtual files, schema migration, scenario compilation, spreadsheet cell parsing) that stayed consistent by convention only. This PR gathers the per-type data into a single TYPE_POLICIES registry in petrinaut-core and adds a conformance test so a sixth type fails loudly until every touchpoint is defined.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

New simulation/engine/type-policies.ts: TYPE_POLICIES: Record<ColorElementType, TypePolicy> where each policy carries:

  • physicalKind (f64 | u8 | u64 | u64x2) — packed-struct layout kind
  • defaultValue (runtime form) and defaultValueSource (TS expression for generated default kernels, e.g. Uuid.generate())
  • tsInputType / tsKernelOutputType / kernelOutputOptional — LSP virtual-file type strings
  • coerce(value, context) — runtime coercion (the old switch bodies)
  • decodeNumberSlot — f64/u8 slot decode, null for uuid/string (decoded in token-layout.ts)
  • encodeAtRest(value) — runtime → JSON-safe document form (uuid bigint → canonical lowercase string)
  • parseEditorText(raw) — total spreadsheet cell parse

Plus COLOR_ELEMENT_TYPES, the canonical runtime list of the union (as const satisfies keeps it in lockstep; the Record shape guarantees the reverse direction at compile time).

Consumers converted (existing exported function names kept as thin wrappers, so the public API is unchanged): token-values.ts (defaults/coercion/number-slot decode; new shared coerceToStoredTokenAttributeValue helper), token-layout.ts (physicalTypeFor), default-codes.ts, lsp/lib/generate-virtual-files.ts, schema-migration.ts, compile-scenario.ts, and in the React package migrate-initial-marking.ts and the spreadsheet's parseCellValue. The zod colour element schema's type enum now derives from COLOR_ELEMENT_TYPES.

Deliberately left structural (control flow, not per-type data): uuid sentinel/RNG handling and string interning in encode-kernel-token.ts; uuid-lane/string-pool read-write paths in token-layout.ts; the real+stochasticity Distribution union and ?: never derivative exclusions in the LSP generator; spreadsheet uuid short-form/overlay and boolean-checkbox rendering (presentation); scenario-mapping.ts / initial-state-editor.tsx at-rest decoding (intentionally laxer semantics than core coercion — converting them would change behaviour).

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s) (fe-1153-type-policy-registry.md — the registry and its types are new public exports)

📜 Does this require a change to the docs?

The changes in this PR:

  • do not require any changes to docs (no user-facing behaviour change)

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • The registry intentionally does not absorb mode-dependent LSP logic or UI rendering; those stay exhaustive switches at their sites.

🐾 Next steps

  • A future Enum element type should be addable by filling in one TypePolicy record plus the structural sites the conformance test points at.

🛡 What tests cover this?

  • New type-policies.test.ts (32 assertions): registry keys ≡ COLOR_ELEMENT_TYPES ≡ the zod enum's options; per type: physicalKind agrees with computeTokenSlotLayout (kind, width, alignment); decodeNumberSlot present iff f64/u8; defaults round-trip coercion unchanged; at-rest encode is JSON-serializable; editor parse is total and coercion-stable.
  • All pre-existing tests pass unmodified (665 core + 149 UI), which is the no-behaviour-change evidence.

❓ How to test this?

npx turbo run lint:tsc lint:eslint test:unit --filter '@hashintel/petrinaut-core' --filter '@hashintel/petrinaut' — behaviour is otherwise identical to #8956.

📹 Demo

N/A — no user-facing change.

Copilot AI review requested due to automatic review settings July 6, 2026 14:09
@vercel

vercel Bot commented Jul 6, 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 7, 2026 12:48pm
petrinaut Ready Ready Preview, Comment Jul 7, 2026 12:48pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 7, 2026 12:48pm

@cursor

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches coercion, scenario/migration storage, and simulation token codecs across core and UI, but the PR positions it as behavior-preserving with existing unit tests unchanged; risk is mainly regression in edge-case parsing/coercion rather than new features.

Overview
Centralizes per-token-type behavior in a new TYPE_POLICIES registry (type-policies.ts) so each ColorElementType defines layout kind, defaults, coercion, at-rest encoding, LSP type strings, and spreadsheet parseEditorText in one place, instead of duplicated switch (element.type) blocks across the codebase.

Refactors call sites to delegate to the registry: token-values (plus shared coerceToStoredTokenAttributeValue), token-layout, default-codes, LSP virtual-file generation, schema migration, scenario compilation, initial-marking migration, and the spreadsheet cell parser. The Zod colour-element type enum now derives from COLOR_ELEMENT_TYPES.

Exports TYPE_POLICIES, COLOR_ELEMENT_TYPES, TypePolicy, and StoredTokenAttributeValue from @hashintel/petrinaut-core (patch changeset). Adds type-policies.test.ts conformance coverage so a new element type must get a full policy and stay aligned with layout and schema.

Mode-specific LSP widening (e.g. stochastic Distribution on real) and uuid/string buffer paths in token-layout / kernel encoding stay as structural code outside the registry.

Reviewed by Cursor Bugbot for commit 30ca842. 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 Jul 6, 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

Refactors Petrinaut’s token-dimension “per-type” behavior into a single TYPE_POLICIES registry in @hashintel/petrinaut-core, replacing multiple scattered switch (element.type) blocks while keeping existing exported wrapper APIs stable.

Changes:

  • Adds simulation/engine/type-policies.ts (TYPE_POLICIES, COLOR_ELEMENT_TYPES, TypePolicy) to centralize per-type defaults, coercion, layout kind, at-rest encoding, and editor parsing.
  • Migrates key consumers (token codec/layout, LSP virtual-file generation, scenario compilation, schema migration, UI spreadsheet parsing) to read behavior from the registry.
  • Adds a conformance test (type-policies.test.ts) and derives the Zod enum from COLOR_ELEMENT_TYPES to keep the union/list/schema in lockstep.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
libs/@hashintel/petrinaut/src/ui/components/spreadsheet.tsx Uses core TYPE_POLICIES for spreadsheet cell parsing instead of a local per-type switch.
libs/@hashintel/petrinaut/src/react/simulation/provider/migrate-initial-marking.ts Simplifies stored-value coercion via shared coerceToStoredTokenAttributeValue.
libs/@hashintel/petrinaut-core/src/simulation/engine/type-policies.ts Introduces the centralized type-policy registry and canonical COLOR_ELEMENT_TYPES list.
libs/@hashintel/petrinaut-core/src/simulation/engine/type-policies.test.ts Adds conformance coverage to ensure registry/schema/layout invariants stay aligned.
libs/@hashintel/petrinaut-core/src/simulation/engine/token-values.ts Replaces switches with policy-driven defaults/coercion/decoding; adds coerceToStoredTokenAttributeValue.
libs/@hashintel/petrinaut-core/src/simulation/engine/token-layout.ts Derives physical layout kind via TYPE_POLICIES rather than a switch.
libs/@hashintel/petrinaut-core/src/simulation/authoring/scenario/compile-scenario.ts Encodes compiled initial state to JSON-safe at-rest form via policies.
libs/@hashintel/petrinaut-core/src/schemas/entity-schemas.ts Derives the color-element type enum from COLOR_ELEMENT_TYPES.
libs/@hashintel/petrinaut-core/src/schema-migration.ts Reuses policy-driven stored coercion/defaulting for scenario row migration.
libs/@hashintel/petrinaut-core/src/lsp/lib/generate-virtual-files.ts Uses policy-driven TS type strings and optionality for generated token types.
libs/@hashintel/petrinaut-core/src/index.ts Exposes TYPE_POLICIES, COLOR_ELEMENT_TYPES, and related types/utility to consumers.
libs/@hashintel/petrinaut-core/src/default-codes.ts Uses policy-driven defaultValueSource for generated default code.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread libs/@hashintel/petrinaut-core/src/simulation/engine/type-policies.ts Outdated

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 12 out of 12 changed files in this pull request and generated no new comments.

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 12 out of 12 changed files in this pull request and generated 1 comment.

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 12 out of 12 changed files in this pull request and generated 1 comment.

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 12 out of 12 changed files in this pull request and generated no new comments.

kube commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

Copilot AI review requested due to automatic review settings July 7, 2026 10:22
@kube kube force-pushed the cf/fe-1153-petrinaut-collapse-per-type-switches-into-a-type-policy branch from cace8f7 to 9c85e16 Compare July 7, 2026 10:22
@kube kube force-pushed the cf/fe-769-add-string-discrete-type-support branch from d1f4562 to 0344187 Compare July 7, 2026 10:22

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 13 out of 13 changed files in this pull request and generated no new comments.

TYPE_POLICIES collapses the per-type switches (physical kind, defaults,
coercion, at-rest encoding, LSP type strings, editor parsing) into one
registry consumed across core and UI, with a conformance test so a new
element type fails loudly until every touchpoint is defined.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kube kube force-pushed the cf/fe-769-add-string-discrete-type-support branch from 83dabe0 to dabfc56 Compare July 7, 2026 12:40
@kube kube force-pushed the cf/fe-1153-petrinaut-collapse-per-type-switches-into-a-type-policy branch from d27b847 to 30ca842 Compare July 7, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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