Skip to content

feat: native SQLite backend via napi-rs with KV channel protocol#4496

Merged
NathanFlurry merged 1 commit intomainfrom
native-sqlite-kv-channel
Apr 5, 2026
Merged

feat: native SQLite backend via napi-rs with KV channel protocol#4496
NathanFlurry merged 1 commit intomainfrom
native-sqlite-kv-channel

Conversation

@NathanFlurry
Copy link
Copy Markdown
Member

@NathanFlurry NathanFlurry commented Mar 24, 2026

No description provided.

@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 March 24, 2026 11:46 Destroyed
@railway-app
Copy link
Copy Markdown

railway-app bot commented Mar 24, 2026

🚅 Deployed to the rivet-pr-4496 environment in rivet-frontend

Service Status Web Updated (UTC)
kitchen-sink ❌ Build Failed (View Logs) Web Apr 5, 2026 at 11:45 am
frontend-cloud ❌ Build Failed (View Logs) Web Apr 5, 2026 at 11:11 am
website ❌ Build Failed (View Logs) Web Apr 5, 2026 at 11:11 am
frontend-inspector ❌ Build Failed (View Logs) Web Apr 5, 2026 at 11:10 am
ladle ❌ Build Failed (View Logs) Web Apr 5, 2026 at 11:10 am
mcp-hub ✅ Success (View Logs) Web Apr 5, 2026 at 10:20 am

@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 053feea to 3525a83 Compare March 24, 2026 11:46
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 March 24, 2026 11:46 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 3525a83 to 5e48bbb Compare March 24, 2026 11:47
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 March 24, 2026 11:47 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 5e48bbb to b9dd7c7 Compare April 2, 2026 02:15
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 2, 2026 02:16 Destroyed
@claude
Copy link
Copy Markdown

claude bot commented Apr 2, 2026

PR Review: Native SQLite Backend via napi-rs with KV Channel Protocol

This is a substantial feature (~14.6k additions across 96 files) introducing a native SQLite backend that routes page-level I/O over a new WebSocket KV channel protocol. The architecture is well-designed overall.


Architecture Assessment

The design choices are sound:

  • Separate KV channel protocol (independent of runner protocol) keeps concerns cleanly separated.
  • Single-writer lock enforcement per actor with per-actor mpsc channel + sequential task correctly preserves intra-actor ordering while enabling cross-actor parallelism.
  • Lock eviction on reconnect handles stale connection races.
  • Preloaded KV bundled into CommandStartActor for near-zero cold-read latency is clever, and the decision to never persist it in workflow history is correct since it is non-deterministic data.

Issues

1. Breaking Metric Renames Without Documentation

engine/packages/pegboard-runner/src/metrics.rs renames two Prometheus metrics:

  • pegboard_runner_event_multiplexer_count -> pegboard_event_multiplexer_count
  • pegboard_runner_ingested_events_total -> pegboard_ingested_events_total

These are silent breaking changes for any existing dashboards or alerts. There is no migration note, no changelog entry, and no update to dashboard definitions in the repo. Existing Grafana dashboards or alert rules referencing these metric names will silently stop working after deployment.

2. Committed Binary Artifact

rivetkit-typescript/packages/sqlite-native/sqlite-native.linux-x64-gnu.node is a compiled native addon binary committed directly to the repository. This is problematic:

  • It bloats git history permanently.
  • There is no way to verify its provenance or that it matches the source in src/.
  • It creates a supply chain risk: if the binary is loaded without a checksum/signature check, a tampered binary would be silently used.

Native addon binaries should be built in CI and distributed via npm platform packages (the npm/ subdirectory already has the platform package structure), not committed to the repo.

3. Fragile prefix_range Implementation

In engine/packages/pegboard/src/actor_kv/preload.rs, the prefix_range function manually strips the trailing 0x00 that FDB tuple encoding appends to byte arrays, then appends 0xFF to compute the prefix end. This relies on an undocumented implementation detail of the tuple layer. If the tuple encoding changes, or if the prefix is empty, this silently produces wrong ranges. FDB tuple layer prefix range helpers should be used instead.

4. Silent Error Swallowing in fetch_preloaded_kv

In engine/packages/pegboard/src/actor_kv/preload.rs:

let Some(preload_config) = metadata_map
    .get("preload")
    .and_then(|value| serde_json::from_value::<PreloadConfig>(value.clone()).ok())
else {
    return Ok(None);
};

A malformed preload metadata field silently returns None (no preloading) instead of an error. Actors will appear to work but with degraded performance and no indication of why. At minimum, log a warning when deserialization fails but a preload key is present.

5. Token in Query Parameter Exposed in Logs

In engine/packages/guard/src/routing/kv_channel.rs, the admin_token is passed as a URL query parameter (?token=...). The full URL (including the token) is present in the HTTP upgrade request and will appear in access logs on intermediate proxies or load balancers. This is worth documenting as a known trade-off, or the token should be redacted from logs.

6. MAX_ACTORS_PER_CONNECTION = 1000 Is Not Configurable

The hardcoded limit in engine/packages/pegboard-kv-channel/ is reasonable as a default but should be surfaced in the pegboard config (like preload_max_total_bytes) so operators can tune it without a code change.


Nits

Benchmark scripts in examples/kitchen-sink/scripts/: Four large diagnostic/benchmark scripts (~1700 lines total) are added to the kitchen-sink example. If these are internal development tools, consider moving them or noting they are not intended for end-user consumption.

No PR description: The PR body is empty. For a feature this large (new protocol, new crate, new native addon, schema changes), a description covering motivation, architecture decisions, and testing approach would be valuable for reviewers and future git archaeology.


What Looks Good

  • Constant-time token comparison (subtle::ConstantTimeEq) in both runner and KV channel auth paths.
  • CLAUDE.md updated with VFS parity requirements and KV channel sync guidance.
  • Cross-backend VFS compatibility tests (cross-backend-vfs.ts) and DB stress tests are well-motivated.
  • Protocol version fallback updated from hard-coded 1 to PROTOCOL_VERSION constant in pegboard-outbound.
  • Per-actor sequential ordering with cross-actor parallelism is the right model for this workload.

@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from b9dd7c7 to 053d289 Compare April 2, 2026 03:53
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 2, 2026 03:53 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 053d289 to bf306e1 Compare April 2, 2026 05:48
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 2, 2026 05:49 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from bf306e1 to 2252912 Compare April 2, 2026 08:38
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 2, 2026 08:38 Destroyed
@NathanFlurry NathanFlurry changed the base branch from main to graphite-base/4496 April 4, 2026 04:12
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 2252912 to e325de0 Compare April 4, 2026 04:13
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 4, 2026 04:13 Destroyed
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4496 to 03-31-feat_basic_rivetkit_impl April 4, 2026 04:13
@NathanFlurry NathanFlurry changed the base branch from 03-31-feat_basic_rivetkit_impl to graphite-base/4496 April 4, 2026 04:25
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from e325de0 to db4e9a3 Compare April 4, 2026 04:25
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4496 to 04-03-fix_optimize_e2e_actor_path April 4, 2026 04:25
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 4, 2026 04:25 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from db4e9a3 to 78bdfd2 Compare April 4, 2026 04:41
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 4, 2026 04:41 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 78bdfd2 to f6a75a6 Compare April 4, 2026 04:42
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 4, 2026 04:42 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from f6a75a6 to 866069d Compare April 4, 2026 07:14
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 4, 2026 07:14 Destroyed
@NathanFlurry NathanFlurry mentioned this pull request Apr 4, 2026
11 tasks
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 866069d to 64510be Compare April 5, 2026 10:19
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 5, 2026 10:19 Destroyed
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 64510be to 22fdbd8 Compare April 5, 2026 10:59
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 5, 2026 10:59 Destroyed
@NathanFlurry NathanFlurry changed the base branch from 04-03-fix_optimize_e2e_actor_path to graphite-base/4496 April 5, 2026 11:10
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 22fdbd8 to 027d71c Compare April 5, 2026 11:10
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4496 to gateway-query-resolution-v2 April 5, 2026 11:10
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 5, 2026 11:10 Destroyed
Copy link
Copy Markdown
Member Author

NathanFlurry commented Apr 5, 2026

Merge activity

  • Apr 5, 11:11 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 5, 11:45 AM UTC: Graphite rebased this pull request as part of a merge.
  • Apr 5, 11:45 AM UTC: @NathanFlurry merged this pull request with Graphite.

@NathanFlurry NathanFlurry changed the base branch from gateway-query-resolution-v2 to graphite-base/4496 April 5, 2026 11:42
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4496 to main April 5, 2026 11:43
@NathanFlurry NathanFlurry force-pushed the native-sqlite-kv-channel branch from 027d71c to 7f81e1b Compare April 5, 2026 11:44
@railway-app railway-app bot temporarily deployed to rivet-frontend / rivet-pr-4496 April 5, 2026 11:44 Destroyed
@NathanFlurry NathanFlurry merged commit e23f0d5 into main Apr 5, 2026
10 of 20 checks passed
@NathanFlurry NathanFlurry deleted the native-sqlite-kv-channel branch April 5, 2026 11:45
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.

2 participants