Skip to content

Commit af31f83

Browse files
committed
chore(rivetkit): impl follow up review
1 parent 69857a0 commit af31f83

88 files changed

Lines changed: 5480 additions & 3130 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: 79 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: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
- `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.
6+
7+
Migration example:
8+
9+
```ts
10+
try {
11+
await actor.someAction();
12+
} catch (e) {
13+
if (e instanceof QueueFull) {
14+
// old path
15+
}
16+
17+
if (isRivetErrorCode(e, "queue", "full")) {
18+
// new path
19+
}
20+
}
21+
```
22+
23+
Common replacements:
24+
25+
| Removed class | Use now |
26+
| --------------------------------- | ------------------------------------------------- |
27+
| `QueueFull` | `isRivetErrorCode(e, "queue", "full")` |
28+
| `QueueMessageTooLarge` | `isRivetErrorCode(e, "queue", "message_too_large")` |
29+
| `QueueMessageInvalid` | `isRivetErrorCode(e, "queue", "message_invalid")` |
30+
| `QueuePayloadInvalid` | `isRivetErrorCode(e, "queue", "invalid_payload")` |
31+
| `QueueCompletionPayloadInvalid` | `isRivetErrorCode(e, "queue", "invalid_completion_payload")` |
32+
| `QueueAlreadyCompleted` | `isRivetErrorCode(e, "queue", "already_completed")` |
33+
| `ActionTimedOut` | `isRivetErrorCode(e, "action", "timed_out")` |
34+
| `ActionNotFound` | `isRivetErrorCode(e, "action", "not_found")` |
35+
| `ActorNotFound` | `isRivetErrorCode(e, "actor", "not_found")` |
36+
| `ActorStopping` | `isRivetErrorCode(e, "actor", "stopping")` |
37+
| `ActorAborted` | `isRivetErrorCode(e, "actor", "aborted")` |
38+
| `IncomingMessageTooLong` | `isRivetErrorCode(e, "message", "incoming_too_long")` |
39+
| `OutgoingMessageTooLong` | `isRivetErrorCode(e, "message", "outgoing_too_long")` |
40+
| `InvalidEncoding` | `isRivetErrorCode(e, "encoding", "invalid")` |
41+
| `InvalidRequest` | `isRivetErrorCode(e, "request", "invalid")` |
42+
| `InvalidQueryJSON` | `isRivetErrorCode(e, "request", "invalid_query_json")` |
43+
| `RequestHandlerNotDefined` | `isRivetErrorCode(e, "handler", "request_not_defined")` |
44+
| `WebSocketHandlerNotDefined` | `isRivetErrorCode(e, "handler", "websocket_not_defined")` |
45+
| `FeatureNotImplemented` | `isRivetErrorCode(e, "feature", "not_implemented")` |
46+
| `Unsupported` | `isRivetErrorCode(e, "feature", "unsupported")` |
47+
48+
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.
49+
50+
- 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.
51+
- `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.
52+
- 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.
53+
- `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.
54+
- `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.
55+
- `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
@@ -167,18 +167,6 @@ When the user asks to track something in a note, store it in `.agent/notes/` by
167167
- If an external dependency's struct requires `std::sync::Mutex`, keep it at the construction boundary with an explicit forced-std-sync comment.
168168
- 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.
169169

170-
## TypeScript Concurrency
171-
172-
- Use `antiox` for TypeScript concurrency primitives instead of ad hoc Promise queues, custom channel wrappers, or event-emitter based coordination.
173-
- 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.
174-
- Treat `antiox` as the default choice for any TypeScript concurrency work because it mirrors Rust and Tokio APIs used elsewhere in the codebase.
175-
176-
## TLS / HTTP clients
177-
178-
- 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.
179-
- `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.
180-
- 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.
181-
182170
## Error Handling
183171

184172
- 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`.
@@ -198,6 +186,9 @@ When the user asks to track something in a note, store it in `.agent/notes/` by
198186

199187
- **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.
200188
- 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.
189+
- **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.
190+
- 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.
191+
- **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).
201192
- For running RivetKit tests, Vitest filter gotchas, the driver-test parity workflow, and Rust test layout rules, see `.claude/reference/testing.md`.
202193

203194
## 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)