Skip to content

fix(rivetkit): isolate workflow run state per actor generation - #5822

Open
abcxff wants to merge 1 commit into
stack/fix-rivetkit-napi-key-actor-runtime-state-by-generation-ruyuonlzfrom
stack/fix-rivetkit-isolate-workflow-run-state-per-actor-generation-wurkyvuq
Open

abcxff wants to merge 1 commit into
stack/fix-rivetkit-napi-key-actor-runtime-state-by-generation-ruyuonlzfrom
stack/fix-rivetkit-isolate-workflow-run-state-per-actor-generation-wurkyvuq

Conversation

@abcxff

@abcxff abcxff commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

No description provided.

@abcxff

abcxff commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

@claude

claude Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review: isolate workflow run state per actor generation

The approach looks sound. Keying the coordinator state and the workflow inspector registrations by (actorId, generation) fixes the stale-generation rebind problem. The core generation() accessor is exposed through NAPI, wasm and the CoreRuntime interface consistently, and NativeWorkflowRuntimeAdapter.generation matches what workflow/mod.ts reads from the actor internal. I did not run the tests.

Suggestions

  1. Undefined to defined generation is not a replacement. In #getOrCreate, state created with an undefined generation is never replaced when a defined generation arrives (and the reverse). That is probably fine because the runtime either always or never reports a generation. A short comment saying so would help, since FakeActorContext in runtime-parity.test.ts returns null, which exercises only the legacy path.
  2. Inspector key collision risk is low but real. The actorId#generation key could collide with an actor id that contains #. Actor ids are engine-generated so this is unlikely. A nested map would remove the question.
  3. Test coverage. The coordinator tests cover supersession, late destroy and the stuck older run well. There is no test through the workflow() inspector dispose path, which should leave the newer generation registration intact. A small test would lock in the stale-disposer behavior.
  4. Typing parity. NAPI returns number | null and wasm returns number | undefined. Both are handled by ?? undefined, so this is fine.

No security or performance concerns. Nit: the PR body is empty, so a short bullet summary would help.

@the-company-company the-company-company Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No issues found

Reviewed commit d389d55.

@abcxff
abcxff force-pushed the stack/fix-rivetkit-napi-key-actor-runtime-state-by-generation-ruyuonlz branch from 976d08b to dcf7fcb Compare October 3, 2026 02:05
@abcxff
abcxff force-pushed the stack/fix-rivetkit-isolate-workflow-run-state-per-actor-generation-wurkyvuq branch from d389d55 to 021b0ee Compare October 3, 2026 02:05
@claude

claude Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Review: isolate workflow run state per actor generation

Overall this is a focused, well-tested fix. generation() is plumbed through core, NAPI, wasm and CoreRuntime with no load-bearing logic outside core, which matches the layer rules in CLAUDE.md.

Things to consider

  1. Fallback when the generation is unknown. destroy, #getOrCreate and the inspector key all fall back to the old actor-id-only behavior when either side's generation is undefined. If a runtime reports null at some points and a number at others, the guard is skipped. Cleanup could then close a newer generation's state. Given the fail-by-default guidance, consider asserting that the generation is always present on the native and wasm paths.
  2. Inspector fallback in native.ts. When getInspector returns undefined for a superseded generation, the code falls back to getRunInspectorConfig(config.run, actorId)?.workflow, which is keyed by actor id only. Please confirm that this cannot rebind the newer generation's inspector.
  3. disposeRunInspector(config.run, actorId) in both destroy paths is still keyed by actor id only, while the coordinator destroy is now generation-aware. A late cleanup from an old generation could still dispose the new generation's inspector. Pass the generation or skip the dispose when the coordinator ignored the destroy.
  4. Untyped access. (actor as { generation?: number }).generation in workflow/mod.ts bypasses typing. A typed accessor on the internal actor interface would catch a rename at compile time.
  5. Test coverage. The new coordinator tests are good. Missing: same-generation destroy then recreate, and a test in workflow/mod.ts showing two generations get distinct adapters and disposing one leaves the other intact. runtime-parity only stubs generation() as null, so the non-null path has no end-to-end coverage.
  6. Generated file. index.d.ts appears napi-generated. Confirm it matches the generator output.

No security or performance concerns.

@abcxff
abcxff force-pushed the stack/fix-rivetkit-isolate-workflow-run-state-per-actor-generation-wurkyvuq branch from 021b0ee to 399ced5 Compare October 6, 2026 01:29

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant