Skip to content

Commit 853e804

Browse files
committed
chore(rivetkit): impl follow up review
1 parent 3b4d928 commit 853e804

106 files changed

Lines changed: 6444 additions & 5760 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agent/notes/driver-test-progress.md

Lines changed: 82 additions & 6 deletions
Large diffs are not rendered by default.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# DT-021 package exports audit
2+
3+
- `./driver-helpers`: keep removed. The old entrypoint re-exported actor-instance, runtime-router, and gateway-resolution internals that are not a stable public surface anymore.
4+
- `./driver-helpers/websocket`: keep removed. It was an internal lazy `WebSocket` loader wrapper, and the supported path is the public client/connection API rather than importing transport helpers directly.
5+
- `./test`: restore. Examples and docs on this branch still import `rivetkit/test`, and the helper still makes sense as a thin native-envoy test bootstrap.
6+
- `./inspector`: restore. The package still ships live inspector runtime code (`ActorInspector`) plus workflow-history transport helpers.
7+
- `./topologies/*`: keep removed. The source modules are gone and `tests/package-surface.test.ts` already treats those subpaths as intentionally deleted.
8+
- `./dynamic`: keep removed permanently. This branch no longer ships a supported dynamic actor package entrypoint.
9+
- `./sandbox/*`: keep removed permanently. This branch no longer ships sandbox helpers from `rivetkit`.

.agent/notes/flake-conn-websocket.md

Lines changed: 0 additions & 68 deletions
This file was deleted.

.agent/notes/flake-inspector-replay.md

Lines changed: 0 additions & 50 deletions
This file was deleted.

.agent/notes/flake-queue-waitsend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Date: 2026-04-22
44

55
Scope: `rivetkit-typescript/packages/rivetkit`, static registry, bare encoding.
66

7+
## Current Status
8+
9+
- The isolated `wait send returns completion response` path was fixed by DT-012 and is no longer the active bug for this area.
10+
- Remaining queue flake tracking is the high-fan-out child-actor path under fast static/http/bare verification. See DT-051 and DT-056 in `scripts/ralph/prd.json`.
11+
712
## Repro Commands
813

914
```bash

CHANGELOG.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
- `rivetkit` no longer exposes `ctx.sql` on actor contexts. Migrate raw SQLite calls to `ctx.db` from `rivetkit/db`, and keep Drizzle setup on the `rivetkit/db/drizzle` subpath.
6+
7+
Migration example:
8+
9+
```ts
10+
import { db } from "rivetkit/db";
11+
12+
const myActor = actor({
13+
db: db(),
14+
actions: {
15+
listTodos: async (ctx) => {
16+
return await ctx.db.execute("SELECT * FROM todos ORDER BY created_at DESC");
17+
},
18+
},
19+
});
20+
```
21+
22+
- `rivetkit` no longer exports the old concrete typed error classes from `rivetkit/actor/errors` such as `QueueFull`, `ActorNotFound`, and `ActionTimedOut`. The native runtime now standardizes on `RivetError` plus `group` and `code` so the same error shape survives HTTP, WebSocket, and bridge boundaries instead of depending on `instanceof` across runtimes.
23+
24+
Migration example:
25+
26+
```ts
27+
try {
28+
await actor.someAction();
29+
} catch (e) {
30+
if (e instanceof QueueFull) {
31+
// old path
32+
}
33+
34+
if (isRivetErrorCode(e, "queue", "full")) {
35+
// new path
36+
}
37+
}
38+
```
39+
40+
Common replacements:
41+
42+
| Removed class | Use now |
43+
| --------------------------------- | ------------------------------------------------- |
44+
| `QueueFull` | `isRivetErrorCode(e, "queue", "full")` |
45+
| `QueueMessageTooLarge` | `isRivetErrorCode(e, "queue", "message_too_large")` |
46+
| `QueueMessageInvalid` | `isRivetErrorCode(e, "queue", "message_invalid")` |
47+
| `QueuePayloadInvalid` | `isRivetErrorCode(e, "queue", "invalid_payload")` |
48+
| `QueueCompletionPayloadInvalid` | `isRivetErrorCode(e, "queue", "invalid_completion_payload")` |
49+
| `QueueAlreadyCompleted` | `isRivetErrorCode(e, "queue", "already_completed")` |
50+
| `ActionTimedOut` | `isRivetErrorCode(e, "action", "timed_out")` |
51+
| `ActionNotFound` | `isRivetErrorCode(e, "action", "not_found")` |
52+
| `ActorNotFound` | `isRivetErrorCode(e, "actor", "not_found")` |
53+
| `ActorStopping` | `isRivetErrorCode(e, "actor", "stopping")` |
54+
| `ActorAborted` | `isRivetErrorCode(e, "actor", "aborted")` |
55+
| `IncomingMessageTooLong` | `isRivetErrorCode(e, "message", "incoming_too_long")` |
56+
| `OutgoingMessageTooLong` | `isRivetErrorCode(e, "message", "outgoing_too_long")` |
57+
| `InvalidEncoding` | `isRivetErrorCode(e, "encoding", "invalid")` |
58+
| `InvalidRequest` | `isRivetErrorCode(e, "request", "invalid")` |
59+
| `InvalidQueryJSON` | `isRivetErrorCode(e, "request", "invalid_query_json")` |
60+
| `RequestHandlerNotDefined` | `isRivetErrorCode(e, "handler", "request_not_defined")` |
61+
| `WebSocketHandlerNotDefined` | `isRivetErrorCode(e, "handler", "websocket_not_defined")` |
62+
| `FeatureNotImplemented` | `isRivetErrorCode(e, "feature", "not_implemented")` |
63+
| `Unsupported` | `isRivetErrorCode(e, "feature", "unsupported")` |
64+
65+
Keep catching `UserError` when you intentionally throw user-facing application errors yourself. The removal only affects the built-in typed subclasses that used to wrap framework/runtime failures.
66+
67+
- Restored `Registry.handler(request)` and `Registry.serve()` for the native serverless runner endpoint described in `.agent/specs/serverless-restoration.md`. The route surface is `/api/rivet`, `/api/rivet/health`, `/api/rivet/metadata`, and `/api/rivet/start`; user traffic still goes through the Rivet Engine gateway.
68+
- `Registry.start()` now starts the native envoy path only. Built-in `staticDir` serving is not wired through the native engine subprocess yet and remains a follow-up.
69+
- Restored the supported `rivetkit/test`, `rivetkit/inspector`, and `rivetkit/inspector/client` entrypoints. `rivetkit/test` now waits for the native envoy metadata endpoint instead of the removed TypeScript in-memory runtime.
70+
- Restored the zero-runtime `*ContextOf` helper types on the root `rivetkit` export so patterns like `ActionContextOf<typeof myActor>` work again. `PATH_CONNECT`, `PATH_WEBSOCKET_PREFIX`, `KV_KEYS`, `ActorKv`, `ActorInstance`, `ActorRouter`, `createActorRouter`, and `routeWebSocket` stay removed.
71+
- `rivetkit/driver-helpers` and `rivetkit/driver-helpers/websocket` stay removed. They only exposed internal runtime/router helpers; migrate to the public `rivetkit`, `rivetkit/client`, and engine-client APIs instead of importing package internals.
72+
- `rivetkit/topologies/*` stays removed. The topology helpers are deleted on this branch; keep custom coordinate/partition logic in app code if you still need it.
73+
- `rivetkit/dynamic` and `rivetkit/sandbox/*` stay permanently removed on this branch. There is no in-package replacement, so move those integrations out of `rivetkit` imports instead of waiting for a hidden subpath to come back.

CLAUDE.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -343,18 +343,6 @@ When the user asks to track something in a note, store it in `.agent/notes/` by
343343
- If an external dependency's struct requires `std::sync::Mutex`, keep it at the construction boundary with an explicit forced-std-sync comment.
344344
- Prefer async locks because sync guards can be silently held across `.await`, poisoning creates `.expect("lock poisoned")` boilerplate, and the tiny uncontended-lock win is dwarfed by actor I/O latency.
345345

346-
## TypeScript Concurrency
347-
348-
- Use `antiox` for TypeScript concurrency primitives instead of ad hoc Promise queues, custom channel wrappers, or event-emitter based coordination.
349-
- Prefer the Tokio-shaped APIs from `antiox`. For example, use `antiox/sync/mpsc` for `tx` and `rx` channels, `antiox/task` for spawning tasks, and the matching sync and time modules as needed.
350-
- Treat `antiox` as the default choice for any TypeScript concurrency work because it mirrors Rust and Tokio APIs used elsewhere in the codebase.
351-
352-
## TLS / HTTP clients
353-
354-
- Always use rustls. Never enable `native-tls` / `default-tls` on `reqwest` or anything else on Linux. Consumers, especially `.node` addons published via npm, must have no runtime `libssl.so` dependency.
355-
- `reqwest` workspace dep must set `default-features = false` and enable `rustls-tls-native-roots` + `rustls-tls-webpki-roots`. Per-crate overrides must keep the same.
356-
- Never vendor openssl as a workaround. If `openssl-sys` shows up in `cargo tree`, trace the transitive dep, usually `reqwest` default features, and switch it to rustls.
357-
358346
## Error Handling
359347

360348
- Custom error system at `packages/common/error/` using `#[derive(RivetError)]` on struct definitions. For the full derive example and conventions, see `.claude/reference/error-system.md`.
@@ -374,6 +362,9 @@ When the user asks to track something in a note, store it in `.agent/notes/` by
374362

375363
- **Never use `vi.mock`, `jest.mock`, or module-level mocking.** Write tests against real infrastructure (Docker containers, real databases, real filesystems). For LLM calls, use `@copilotkit/llmock` to run a mock LLM server. For protocol-level test doubles (e.g., ACP adapters), write hand-written scripts that run as real processes. `vi.fn()` for simple callback tracking is acceptable.
376364
- Driver tests that wait for actor sleep must not poll actor actions while waiting; each action counts as activity and can reset the sleep deadline.
365+
- **Never paper over flakes with retry loops or bumped waits.** When a test flakes, (1) root-cause the race, (2) write a deterministic repro using `vi.useFakeTimers()` or event-ordered `Promise` resolution, (3) fix the underlying ordering in core/napi/typescript, (4) delete any flake-workaround note. `vi.waitFor` is acceptable for legitimate "wait for an async event" coordination but never as a retry-until-success masking layer. Every `vi.waitFor` call must have a one-line comment explaining why polling rather than direct awaiting is necessary.
366+
- In `rivetkit-typescript/packages/rivetkit/tests/`, put the `vi.waitFor(...)` justification on the immediately preceding `//` line. `pnpm run check:wait-for-comments` enforces the adjacent comment.
367+
- **Rust tests live under `tests/`, not inline `#[cfg(test)] mod tests` in `src/`.** Move every inline test module in Rust crates to the crate's `tests/` directory. Exceptions must be justified (e.g., testing a private internal that can't be reached from an integration test).
377368
- For running RivetKit tests, Vitest filter gotchas, the driver-test parity workflow, and Rust test layout rules, see `.claude/reference/testing.md`.
378369

379370
## Traces Package

engine/CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ When changing a versioned VBARE schema, follow the existing migration pattern.
2929
- `engine/packages/runner-protocol/src/lib.rs` `PROTOCOL_MK2_VERSION`
3030
- `rivetkit-typescript/packages/engine-runner/src/mod.ts` `PROTOCOL_VERSION`
3131
- Update the Rust latest re-export in `engine/packages/runner-protocol/src/lib.rs` to the new generated module.
32+
5. For any Rust VBARE protocol crate, bump the protocol constant together with the matching latest generated/schema wiring (`generated::vN`, latest re-exports, `protocol.rs`/`versioned.rs` if present, and the corresponding `engine/sdks/schemas/.../vN.bare` file).
3233

3334
## Epoxy durable keys
3435

@@ -54,6 +55,7 @@ Use `test-snapshot-gen` to generate and load RocksDB snapshots of the full UDB K
5455
- `sqlite-storage` LTX decoders should validate the varint page index against the actual page-frame layout instead of trusting footer offsets alone.
5556
- `sqlite-storage` `get_pages(...)` should keep META, cold PIDX loads, and DELTA/SHARD blob fetches inside one `db.run(...)` transaction, then decode each unique blob once and evict stale cached PIDX rows that now need SHARD fallback.
5657
- `sqlite-storage` fast-path commits should update an already-cached PIDX in memory after the store write, but must not load PIDX from store just to mutate it or the one-RTT path is gone.
58+
- `sqlite-storage` shrink writes must delete above-EOF PIDX rows and fully-above-EOF SHARD blobs inside the same commit/takeover transaction; compaction only cleans partial shards by filtering pages at or below `head.db_size_pages`.
5759
- `sqlite-storage` fast-path cutoffs should use raw dirty-page bytes, and slow-path finalize must accept larger encoded DELTA blobs because UniversalDB chunks logical values internally.
5860
- `sqlite-storage` compaction should choose shard passes from the live PIDX scan, then delete DELTA blobs by comparing all existing delta keys against the remaining global PIDX references so multi-shard and overwritten deltas only disappear when every page ref is gone.
5961
- `sqlite-storage` compaction must re-read META inside its write transaction and fence on `generation` plus `head_txid` before updating `materialized_txid` or quota fields, so takeover and commits cannot rewind the head.

0 commit comments

Comments
 (0)