Skip to content

chore: sql fuzz#4739

Closed
NathanFlurry wants to merge 1 commit into04-24-fix_rivetkit-core_gate_startup_until_runtime_readyfrom
db-fuzzer-kitchen-sink
Closed

chore: sql fuzz#4739
NathanFlurry wants to merge 1 commit into04-24-fix_rivetkit-core_gate_startup_until_runtime_readyfrom
db-fuzzer-kitchen-sink

Conversation

@NathanFlurry
Copy link
Copy Markdown
Member

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

This was referenced Apr 24, 2026
Copy link
Copy Markdown
Member Author

NathanFlurry commented Apr 24, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 24, 2026

Code Review: chore: sql fuzz (#4739)

Draft PR - feedback provided for early review.

Overview

This PR adds a comprehensive SQLite VFS fuzz harness for the kitchen-sink example, fixes two real bugs uncovered by fuzzing, and adds test-only fault injection to vfs.rs. The two production fixes are:

  1. native-database.ts - serializes overlapping exec/run/query calls via an AsyncMutex, fixing concurrent read-write races on raw SQLite handles.
  2. native.ts + actor_context.rs - makes onSleep/onDestroy unconditionally registered (removing the conditional gate) and explicitly calls clearRuntimeState() on teardown, fixing the NAPI ref-count panic on sleep/wake cycles.

Both fixes are well-motivated and address real bugs documented in the issue log.


Issues

Medium

AsyncMutex is a custom ad-hoc implementation (shared.ts:70)

CLAUDE.md mandates using antiox for TypeScript concurrency primitives instead of custom Promise queues. The AsyncMutex in shared.ts is a hand-rolled Promise queue. If antiox provides a mutex, this should use it. At minimum, if the custom implementation stays, add a comment explaining why antiox is not used here.

exec result type unsoundness in native-database.ts:202-210

The mutex closure for exec may return undefined if enrichNativeDatabaseError returns without throwing (TypeScript does not statically guarantee it throws). result would then be undefined and the subsequent result.rows/result.columns access would crash at runtime. This existed before the PR but the refactor was an opportunity to fix it - adding a !result guard after the mutex would make the invariant explicit.

Relative path to sql-loader in db-fuzz.ts:380

The import "../../../rivetkit-typescript/packages/sql-loader/dist/register.js" is brittle if the script or package moves. Prefer a workspace package reference (e.g. @rivetkit/sql-loader/register) so it resolves through the workspace graph.

registry.start() is not awaited in db-fuzz.ts:382

If start() returns a Promise, the fire-and-forget + sleep(warmupMs) is a best-effort wait that can silently lose startup errors. Either await it or document that the warmup window is intentional.

Low / Style

hashSeed and checksum are the same function (raw-sqlite-fuzzer.ts)

Both implement FNV-1a with identical constants and loops under different names. Unify into one helper to prevent drift.

Manual BEGIN/COMMIT in applyEdgePayloads (raw-sqlite-fuzzer.ts)

Most of the actor uses the transaction() helper, but applyEdgePayloads manually issues database.execute("BEGIN") and handles rollback inline. Use the transaction() helper for uniformity.

accountCount !== 8 hardcoded in assertValidation (db-fuzz.ts:253)

The client asserts validation.accountCount !== 8 which is directly coupled to ACCOUNT_COUNT = 8 in the actor. If that constant changes the client breaks silently. Consider including expected account count in ValidationSummary.


What Looks Good

  • Rust vfs.rs test injection is clean - #[cfg(test)] gating on both struct fields and all helper functions, using parking_lot::Mutex correctly for sync VFS/FFI context. Helpers stay in src/ where private access is needed per project conventions.
  • clear_runtime_state NAPI implementation - correctly takes the Option out of the parking_lot::Mutex, releases the lock, then calls unref(env). Safe ordering, correct mutex type for sync NAPI context.
  • Unconditional onSleep/onDestroy registration - the root cause analysis is correct. The old conditional guard meant actors without DB providers had no cleanup path for the NAPI runtimeState reference, causing the ref-count panic on wake. Always registering is the right fix.
  • closed guard in wrapJsNativeDatabase - the error message is actionable and points users toward c.abortSignal for cleanup.
  • Test coverage breadth - the checklist in .agent/notes/raw-sqlite-vfs-fuzz.md is thorough: page boundaries, fragmentation, DDL churn, constraints, savepoints, fault injection, sleep/wake cycles. High-quality regression safety net for the VFS.
  • Idempotent rerun safety - fixing the phase-only ID reuse bug (orders/constraints reusing order-${phase} IDs) prevents false invariant failures on --no-reset reruns.

@NathanFlurry NathanFlurry force-pushed the 04-24-fix_rivetkit-core_gate_startup_until_runtime_ready branch from 6db71dc to e33e626 Compare April 24, 2026 09:52
@NathanFlurry NathanFlurry force-pushed the db-fuzzer-kitchen-sink branch from 6385d07 to d790b63 Compare April 24, 2026 09:52
@NathanFlurry NathanFlurry mentioned this pull request Apr 24, 2026
11 tasks
@NathanFlurry NathanFlurry changed the base branch from 04-24-fix_rivetkit-core_gate_startup_until_runtime_ready to graphite-base/4739 April 24, 2026 09:54
@NathanFlurry NathanFlurry force-pushed the db-fuzzer-kitchen-sink branch from d790b63 to 5018fbd Compare April 24, 2026 10:19
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4739 to 04-24-fix_rivetkit-core_gate_startup_until_runtime_ready April 24, 2026 10:20
@NathanFlurry NathanFlurry force-pushed the 04-24-fix_rivetkit-core_gate_startup_until_runtime_ready branch from 49fed12 to c4a5108 Compare April 24, 2026 10:32
@NathanFlurry NathanFlurry force-pushed the db-fuzzer-kitchen-sink branch from 5018fbd to 9576c80 Compare April 24, 2026 10:32
@NathanFlurry NathanFlurry force-pushed the 04-24-fix_rivetkit-core_gate_startup_until_runtime_ready branch from c4a5108 to b563149 Compare April 24, 2026 11:48
@NathanFlurry NathanFlurry force-pushed the db-fuzzer-kitchen-sink branch 2 times, most recently from 94dbc7a to 7531961 Compare April 24, 2026 12:14
@NathanFlurry
Copy link
Copy Markdown
Member Author

Landed in main via stack-merge fast-forward push. Commits are in main; closing to match.

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