Repository navigation
fix: atomic runtime admission, guarded external values, single-clone history commits - #26
Merged
Merged
Conversation
…invoke limits Cancellation was checked between every callback and after each one returned, so a context that expired while a successful action ran aborted the transition after its side effects. The universe stayed in the previous reality and a retry would repeat the side effects. Cancellation is now honored only while waiting for the machine lock and at admission; callbacks still receive the context and can stop cooperatively by returning an error. MaxConcurrentInvokes admitted invokes one by one after transition actions ran, so a rejected invoke aborted the transition while earlier invokes kept running. Each transition step now reserves capacity for its transition, exit, and target entry invokes (including machine and universe constants) before its first callback, and entries reserve their entry invokes the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyRBcc1W1QuigZPCFx26zm
… avoid double clone - External `value`/`defaultValue` went straight into deserializeStatePro, so a null universe, null reality, or non-array `always` threw while building the reducer's initial state. Definitions are now checked structurally and deserialization errors are caught: the initial render falls back to an empty machine and a controlled update keeps the current graph, reporting via console.error. Semantically invalid machines still load so they can be fixed. - The package styles.css kept Tailwind 3 directives. The host app already owns utility generation per the README; under Tailwind 4 the directives emitted unlayered utilities (.transform, .filter) from the package stylesheet. - Gesture checkpoints were cloned by createHistorySnapshot and again when committed. The history now takes ownership of snapshots created by createHistorySnapshot; other payloads are still cloned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyRBcc1W1QuigZPCFx26zm
rendis
pushed a commit
that referenced
this pull request
Oct 5, 2026
#26 let commit-snapshot take ownership of any snapshot returned by the public createHistorySnapshot, to skip a second clone. That contradicts the contract documented in docs/studio-performance.md (supplied checkpoints are mutable and caller-owned): a consumer that mutated a checkpoint after committing it silently changed what undo restored. createHistorySnapshot is copied on commit again. Ownership transfer is now an internal, non-exported mechanism used only for the editor's own drag/gesture checkpoint, which is never exposed, so the editor keeps the single-clone gain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyRBcc1W1QuigZPCFx26zm
rendis
added a commit
that referenced
this pull request
Oct 5, 2026
fix: atomic runtime admission, guarded external values, single-clone history commits
rendis
added a commit
that referenced
this pull request
Oct 5, 2026
#26 let commit-snapshot take ownership of any snapshot returned by the public createHistorySnapshot, to skip a second clone. That contradicts the contract documented in docs/studio-performance.md (supplied checkpoints are mutable and caller-owned): a consumer that mutated a checkpoint after committing it silently changed what undo restored. createHistorySnapshot is copied on commit again. Ownership transfer is now an internal, non-exported mechanism used only for the editor's own drag/gesture checkpoint, which is never exposed, so the editor keeps the single-clone gain.
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.
Follow-up to the changes merged in #22, #23 and #24. Each fix below was first reproduced with a failing test.
Runtime (Go)
Cancellation no longer aborts an operation that has already started.
SendEventreturnedcontext canceledand the universe stayed in the previous reality, even though the action's side effects had already happened. A retry would repeat them.ctx.Err(), fails like any other callback error.MaxConcurrentInvokesnow rejects a step before it runs anything.ResourceLimitErrorbefore any action runs or invoke starts.docs/runtime.mdandCHANGELOG.mddescribe the new contract.Studio
A malformed
valueordefaultValueno longer crashes the editor.tryBuildEditorStateFromExternalValuechecks that the definition is an object with auniversesmap, and catches deserialization errors.console.error.The package
styles.cssno longer contains@tailwinddirectives..transform,.filter).Gesture checkpoints are cloned once instead of twice.
createHistorySnapshotis already a detached copy. When it is committed withcommit-snapshot, the history now keeps that copy instead of cloning it again.Double-clone benchmark (Node 22, editor-core
dist, median of 15 runs)Before is the reducer at
fb3d56dand after is this branch; nothing else differs. Each gesture captures a base snapshot, applies 30 silent node moves, then commits once.The commit step is about 7–8× faster, and a full drag gesture about 1.8× faster. The cost that remains is the single clone taken when the gesture starts. A second run gave the same numbers.
Validation
All steps of the
Qualityworkflow were run locally on this branch, and all passed:go build ./...,go vet ./...,go test -race -cover ./...(11 packages),make test-fuzz-smokepnpm install --frozen-lockfile,lint,typecheck,test(294 tests), Stryker dry-run,build,auditThe four new Go tests fail against
fb3d56dand pass here. The ten new external-value tests failed withTypeErrorbefore the fix.