FE-1130: Token frame format v2 β packed struct token layout#8944
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryHigh Risk Overview The stepping path (initial marking, dynamics, transition read/write, add/remove compaction) and Monte Carlo buffers are rewired to copy and integrate byte blocks; Euler dynamics only update Public API: removes Reviewed by Cursor Bugbot for commit e784cb6. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
This PR upgrades Petrinautβs simulation frame token storage to frame format v2: a packed-struct, byte-addressed token region with a schema-driven per-colour layout (f64 for real/integer, u8 for boolean), and updates the engine, Monte Carlo pipeline, frame readers, and the token encoding playground to use that layout consistently.
Changes:
- Introduces a core
TokenSlotLayoutabstraction and helpers for computing layouts and reading/writing packed token bytes (computeTokenSlotLayout,readTokenRecord,encodeTokenToBytes, etc.). - Bumps engine frames to version 2 and converts all token-region handling from
Float64Arrayvalue slots toUint8Arraybyte regions with sharedu8/f64views. - Updates Monte Carlo buffering/transition effects/dynamics and the dev token encoding playground to reflect the packed layout; removes the now-meaningless raw f64 token-values API.
Reviewed changes
Copilot reviewed 44 out of 45 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/token-memory-view.tsx | Adapts the memory view UI to render TokenSlotLayout fields (byte offsets/sizes and field metadata) from core. |
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/token-encoding-playground.tsx | Removes v1/v2 toggle and scopes Monacoβs built-in TS language service to the playground lifecycle. |
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/playground-monaco.ts | Adds enable/disable controls for Monaco TS mode configuration and clears TS markers on unmount. |
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/physical-layout.ts | Replaces local layout/codec implementation with thin wrappers over core token-layout encode/decode helpers. |
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/physical-layout.test.ts | Updates playground layout and encode/decode tests to use core TokenSlotLayout. |
| libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/monaco-typescript.d.ts | Extends the local TS defaults typing to include setModeConfiguration. |
| libs/@hashintel/petrinaut/src/react/playback/provider.test.tsx | Updates playback mocks to match the removal of getPlaceTokenValues. |
| libs/@hashintel/petrinaut/src/main.ts | Removes the exported SimulationPlaceTokenValues type from the Petrinaut package surface. |
| libs/@hashintel/petrinaut-core/src/simulation/runtime/simulation.test.ts | Updates frame construction in tests to use an empty Uint8Array token buffer. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/types.ts | Renames Monte Carlo token capacity/count fields to byte-based equivalents. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/transition-effect.ts | Switches transition effects to read/write packed token bytes via token-layout helpers. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/run-state.ts | Converts frame resizing and run summaries to use token byte counts/capacities. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/monte-carlo-simulator.test.ts | Updates Monte Carlo tests to assert byte-sized token regions and to use typed token access. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/internal-types.ts | Changes transition additions to store Uint8Array token blocks rather than number arrays. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/frame-reader.ts | Updates Monte Carlo frame reader to return typed token records from packed bytes. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/frame-operations.ts | Converts dynamics/removal/addition operations to work on packed byte regions. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/frame-buffer.ts | Updates Monte Carlo frame buffer layout to include u8/f64 views over a byte-addressed token region. |
| libs/@hashintel/petrinaut-core/src/simulation/monte-carlo/advance-run.ts | Updates pending token-additions map type to Uint8Array[]. |
| libs/@hashintel/petrinaut-core/src/simulation/index.ts | Removes SimulationPlaceTokenValues export from the simulation entrypoint. |
| libs/@hashintel/petrinaut-core/src/simulation/frames/internal-frame.ts | Bumps FRAME_VERSION to 2 and migrates internal frame layout/state to byte offsets + packed token bytes. |
| libs/@hashintel/petrinaut-core/src/simulation/frames/frame-reader.ts | Updates the main frame reader to decode typed tokens from packed bytes via readTokenRecord. |
| libs/@hashintel/petrinaut-core/src/simulation/frames/frame-reader.test.ts | Rewrites frame-reader tests to validate copied token records rather than copied f64 buffers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/types.ts | Updates engine types for byte-addressed dynamics inputs and includes per-place tokenLayout. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/token-layout.ts | Adds the core packed token layout module (layout computation + encode/decode + shared views). |
| libs/@hashintel/petrinaut-core/src/simulation/engine/token-layout.test.ts | Adds unit tests covering layout math, encode/decode round-trips, and alignment checks. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/token-layout.test-helpers.ts | Adds helpers for constructing/decoding v2 frames and token blocks in tests. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/remove-tokens-from-simulation-frame.ts | Migrates token removal/compaction to operate on packed byte ranges. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/remove-tokens-from-simulation-frame.test.ts | Rewrites token-removal tests around packed bytes and typed token decoding helpers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/README.md | Updates engine documentation to describe frame format v2 token storage and access patterns. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/execute-transitions.ts | Updates transition execution to append packed token byte blocks and adjust byte offsets. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/execute-transitions.test.ts | Updates transition execution tests to validate packed-token behavior via decode helpers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-possible-transition.ts | Updates possible-transition computation to decode/encode packed token byte blocks and preserve determinism. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-possible-transition.test.ts | Updates possible-transition tests to validate packed byte outputs by decoding token blocks. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-place-next-state.ts | Updates dynamics stepping to integrate real fields only while copying discrete bytes through unchanged. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-place-next-state.test.ts | Updates dynamics tests and adds coverage for βdiscrete fields untouchedβ behavior. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-next-frame.ts | Updates frame evolution to apply dynamics on packed bytes and write results back by byte offsets. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/compute-next-frame.test.ts | Updates next-frame tests to assert on decoded tokens rather than raw numeric buffers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/check-transition-enablement.test.ts | Updates enablement tests for byte-offset/stride-based place state and v2 frame buffers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/build-simulation.ts | Updates initial marking packing and dynamics compilation to use packed token layouts and byte buffers. |
| libs/@hashintel/petrinaut-core/src/simulation/engine/build-simulation.test.ts | Updates build-simulation tests to validate packed layout properties and decoded token records. |
| libs/@hashintel/petrinaut-core/src/simulation/ARCHITECTURE.md | Updates architecture docs to describe frame format v2 and packed-struct token layout. |
| libs/@hashintel/petrinaut-core/src/simulation/api.ts | Removes SimulationPlaceTokenValues and getPlaceTokenValues from the public frame reader API. |
| libs/@hashintel/petrinaut-core/src/index.ts | Exports the new token-layout module API from the package root and removes the old token-values export. |
| libs/@hashintel/petrinaut-core/src/actual-mode/timeline.ts | Removes getPlaceTokenValues implementation from actual-mode timeline frame reader. |
| .changeset/h-6519-discrete-token-attribute-types.md | Bumps changeset impact to minor for both packages and notes the v2 frame format change. |
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 50 out of 51 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (2)
libs/@hashintel/petrinaut-core/src/simulation/engine/compute-possible-transition.ts:107
- Typo in comment: "acumulate" β "accumulate".
// TODO: This should acumulate lambda over time, but for now we just consider that lambda is constant per combination.
// (just multiply by time since last transition)
libs/@hashintel/petrinaut-core/src/simulation/engine/remove-tokens-from-simulation-frame.ts:62
- This error message still refers to "dimensions"; it should describe the non-zero
strideBytescase to match the new frame format terminology.
if (typeof indices === "number") {
throw new Error(
`For place ${placeId} with dimensions, expected Set of token indices to remove, got number.`,
);
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 49 out of 49 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
libs/@hashintel/petrinaut-core/src/simulation/frames/internal-frame.ts:58
- Several header/enum field names still refer to "Value"/"Values" even though the frame format is now byte-addressed (e.g.,
placeValueOffsetsOffset,TokenValuesOffset). This is likely to cause confusion for future edits (especially when reasoning about units: values vs bytes). Consider renaming these toplaceByteOffsetsOffset/TokenBytesOffset(and updating related locals liketokenValuesOffset) to reflect the v2 semantics.
type EngineFrameHeader = {
placeCount: number;
transitionCount: number;
tokenByteLength: number;
placeCountsOffset: number;
placeValueOffsetsOffset: number;
transitionElapsedOffset: number;
transitionFiringCountsOffset: number;
transitionFiredFlagsOffset: number;
tokenValuesOffset: number;
735e846 to
696fc4f
Compare
696fc4f to
890dfa4
Compare
890dfa4 to
77540f0
Compare
Token fields are packed by alignment (f64 numbers, u8 booleans), strides round to 8 bytes, places are byte-addressed (frame header version 2). getPlaceTokens(place) and buildMetricState(frame, places) drop unused parameters; the number-slot-only decoders leave the public API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

π What is the purpose of this PR?
Replaces the simulation engine's uniform one-Float64-slot-per-dimension token encoding with a schema-driven packed struct per token (format v2), everywhere: interactive engine, Monte Carlo, frame readers, and the encoding playground. Booleans now occupy a single byte instead of eight, places are byte-addressed, and the per-colour layout module gives future wider types (128-bit UUIDs, FE-1121) a place to slot in as
u64Γ2fields.π Related links
π« Blocked by
π What does this change?
engine/token-layout.tsβ single source of truth for the physical layout:real/integerβ f64 (8 B),booleanβ u8 (1 B); fields ordered by decreasing alignment (stable), stride rounded up to 8 B so every f64 field stays addressable through a sharedFloat64Arrayview (noDataViewin hot paths). Read/write goes throughreadTokenRecord/writeTokenValue/encodeTokenToBytesonly.EngineFramebumped toFRAME_VERSION = 2: per-place state is byte-addressed ({ byteOffset, count, strideBytes }), the header records the token region's byte length, snapshots carryUint8Arrays, and all whole-token moves (kernel-produced insertions, removal/compaction) are byte-range copies.realFieldF64Offsets; discrete bytes are copied through untouched (structurally stronger than zeroing derivatives).tokenByteCount/tokenByteCapacity, same Γ2 growth policy, dual u8/f64 views).getPlaceTokenValues/SimulationPlaceTokenValuesremoved β raw f64 access is meaningless under mixed field widths; consumers usegetPlaceTokens(typed records). The monorepo was swept: no usage outside the petrinaut packages.simulation/ARCHITECTURE.mdandengine/README.mdtoken-storage sections rewritten for the packed layout.Pre-Merge Checklist π
π’ Has this modified a publishable library?
This PR:
token-frame-format-packed-structs.mdβ dedicated entry for the layout change and the API slimming)π 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
u64Γ2field (align 8) withbigintat the JS boundary β the layout machinery here is built for it.π‘ What tests cover this?
engine/token-layout.test.ts(layout computation, encode/decode round-trips incl. u8 booleans and integer rounding) + a discrete-fields-untouched dynamics integration test@hashintel/petrinaut-core, 137 in@hashintel/petrinautlint:tsc(tsgo) andlint:eslint(oxlint) clean for both packagesβ How to test this?
yarn devinlibs/@hashintel/petrinaut.sizeof(token)reflects the packed stride.πΉ Demo
See the token-encoding playground story: the memory view renders the exact v2 layout this PR ships (u8 booleans, alignment padding, byte-addressed slots).