# Ralph Progress Log
Started: Thu Apr 23 04:17:16 AM PDT 2026
---

## Codebase Patterns
- `ActorContext::request_save(...)` is intentionally fire-and-forget and only warns on lifecycle inbox overload. Use `request_save_and_wait(...)` when the caller must observe save-request delivery failures.
- `pnpm -F rivetkit check-types` compiles every file under `rivetkit-typescript/packages/rivetkit/src/**/*`, not just tsup entrypoints. Exclude dead legacy sources in `tsconfig.json` or they will block unrelated stories.
- `getOrCreate` is only truly "ready" once the runtime adapter has acked its startup preamble. If core replies before that, the first action can beat `onWake` or `run` startup and read stale state.
- Keep the root `*ContextOf` helper surface synced across `rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts`, the `src/actor/mod.ts` re-export list, and the docs pages `website/src/content/docs/actors/types.mdx` and `website/src/content/docs/actors/index.mdx`.
- Keep the TypeScript `ActorKey` and `ActorContext.key` surfaces string-only unless `client/query.ts`, key serialization, and gateway query parsing are widened end to end in the same change.
- Native adapter required-path config failures in `rivetkit-typescript/packages/rivetkit/src/registry/native.ts` should throw structured `RivetError`s, not plain `Error`, so `group` and `code` survive the bridge back to callers.
- Driver `actor_ready_timeout` failures can hide underlying `no_envoys` scheduling errors. Check actor lookup logs before assuming the bug is only in the transport or reply path.
- In `rivetkit-typescript/packages/rivetkit/tests/`, keep each `vi.waitFor(...)` reason on the immediately preceding `//` line. `pnpm run check:wait-for-comments` only enforces adjacency, so the comment still needs to explain the async reason for polling.
- When a driver test has a real event boundary, wait on a captured Promise or event collector instead of wrapping the action itself in `vi.waitFor(...)`. Reserve polling for state changes that have no direct hook.
- Bare `test.skip(...)` in `rivetkit-typescript/packages/rivetkit/tests/` needs an adjacent `// TODO(<ticket>): ...` comment. `pnpm run check:test-skips` enforces that policy.
- Native `saveState` persistence coverage should live in driver tests with a real actor plus `hardCrashActor` and an observer actor; do not mock `NativeActorContext` for that path.
- When a TypeScript test needs deterministic monotonic time, patch `globalThis.performance.now` on the existing object. Replacing `globalThis.performance` can miss code that already captured the original object reference.
- In `rivetkit-core/tests/modules/task.rs`, any test that installs a tracing subscriber with `set_default(...)` needs `test_hook_lock()` first or full `cargo test` parallelism makes the log capture flaky.
- Intentional `rivetkit` package-surface removals should be documented in the root `CHANGELOG.md` with a direct before/after migration snippet, not left implicit in the code diff.
- Before deleting a `rivetkit/*` package export, grep `examples/`, `website/`, and `frontend/` for self-imports; docs and app code often still depend on those subpaths even after internal refactors.
- Use rustls for Rust HTTP/TLS clients; `reqwest`, Hyper clients, and published NAPI paths must not pull `native-tls`, `openssl-sys`, `libssl`, or `libcrypto`.
- Do not run the long `actor-lifecycle.test.ts` driver verifier in parallel with heavy Rust builds or `cargo test`; the extra load can trigger bogus `guard.actor_ready_timeout` failures in lifecycle race tests.
- NAPI lifecycle `ready`/`started` flags must forward to core `ActorContext`; do not keep a second copy in `ActorContextShared` or sleep gating drifts between layers.
- JS-only native actor caches in `rivetkit-typescript/packages/rivetkit/src/registry/native.ts` should live on `ActorContext.runtimeState()`, not on actorId-keyed module globals. Same-key recreates must get a fresh bag.
- Actor-connect WebSocket setup failures should send a protocol `Error` frame before closing; JSON/CBOR connection-level errors must include `actionId: null`.
- Actor-connect WebSocket setup also needs a registry-level timeout; the HTTP upgrade can finish before `connection_open` replies, so wedged setup must emit a structured error and close instead of idling until the client times out.
- Flush the envoy `WebSocketSender` after queueing required setup/error frames and before an immediate close, so the outgoing task handles the frame before termination.
- Actor-connect protocol `actionId` values are nullable; `0` is a valid action ID, and only `null` means a connection-level error.
- Gateway actor-connect must preserve tunnel messages queued between the envoy open ack and the websocket forwarding task; setup-error close frames can arrive immediately after open.
- If an omitted optional value passes in bare but fails in CBOR or JSON, inspect whether the cross-encoding path is coercing `undefined` into `null`.
- Opaque user payloads that must preserve JS `undefined` through Rust JSON/CBOR bridges should use `encodeCborCompat` / `decodeCborCompat`; do not run structural request envelopes through those helpers or optional API fields turn into bogus sentinel arrays.
- When validating Linux NAPI preview packages, run the sanity check in Docker `node:22` if the host already has a `rivet-engine` on port `6420`.
- Serverless `/start` driver tests need the start payload actor ID to exist in the same engine namespace as the serverless envoy headers, or startup fails at KV load with `actor does not exist`.
- Serverless `/start` tests must upsert a normal runner config for the temporary pool before starting the native serverless envoy.
- Raw `db()` uses the native database provider only; custom raw database client overrides are removed.
- Queue enqueue-and-wait must register the completion waiter before publishing the queue message to KV; otherwise a fast consumer can complete the message before the waiter exists.
- If Rust under `rivetkit-core` changes, make sure the local NAPI `.node` artifact is newer than the changed Rust files before rerunning driver tests.
- A driver story is not really dead until the matrix-shaped fast/slow verifier stays green; if the exact same file/test regresses there, reopen the existing story instead of spawning a duplicate.
- DT-008 verifier sweeps should use the explicit fast/slow driver file lists from the progress buckets; `tests/driver -t "static registry.*encoding \(bare\)"` is broader and muddies the counts.
- Close a stale driver story only after the exact targeted repro, the whole driver file, the relevant matrix slice, and typecheck all pass on the current branch.
- Native dispatch cancellation should flow as `CancellationToken` objects from NAPI TSF payloads into `registry/native.ts`. Do not reintroduce BigInt token registries or polling loops for cancel propagation.
- Clean `run` exit is not terminal in `rivetkit-core`; the actor generation must stay alive until the guaranteed `Stop` drives `SleepGrace` or `DestroyGrace`, and only then may it become `Terminated`.
- SQLite v2 shrink paths must delete above-EOF PIDX rows and fully-above-EOF SHARD blobs in the same commit or takeover transaction; compaction only cleans partial shards by filtering pages at or below `head.db_size_pages`.
- A fresh `CommandStartActor`/Allocate is authoritative for a crashed v1 SQLite migration; reset staged v1 rows immediately on restart instead of waiting for the stale-owner lease to expire.
- `getForId(actorId)` teardown assertions in driver tests are real but slow because actor lookup polls until the registry drops the actor; use them when you specifically need post-destroy unreachability, not as casual filler.
- Native database providers in `rivetkit-typescript/packages/rivetkit/src/registry/native.ts` must close on sleep via `closeDatabase(false)` after user `onSleep`, or provider `onDestroy` cleanup runs on destroy only and lifecycle cleanup tests stick at `0`.

## 2026-04-23T11:45:04Z - DT-000
- Implemented the urgent Linux NAPI publish fix in `/tmp/rivet-publish-fix` on branch `04-22-chore_fix_remaining_issues_with_rivetkit-core`.
- Switched workspace `reqwest` to rustls with default features disabled, replaced direct `hyper-tls` users with `hyper-rustls`, and removed the vendored OpenSSL block from `rivetkit-napi`.
- Added `CLAUDE.md` TLS rules requiring rustls and forbidding vendored OpenSSL workarounds.
- Files changed: `Cargo.toml`, `Cargo.lock`, `engine/packages/pools/{Cargo.toml,src/db/clickhouse.rs}`, `engine/packages/guard-core/{Cargo.toml,src/proxy_service.rs}`, `rivetkit-typescript/packages/rivetkit-napi/Cargo.toml`, `CLAUDE.md`.
- Verification: `cargo tree -p {rivetkit-napi,rivetkit-core,rivet-envoy-client,rivet-engine} -i {openssl-sys,native-tls}` returned Cargo's package-not-found success signal; `cargo build -p rivetkit-core -p rivet-engine` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; local and Docker `ldd` showed no `libssl` or `libcrypto`.
- Published commits: `cda279eda feat(deps): switch reqwest to rustls workspace-wide, drop openssl` and `19a731adb docs(claude): require rustls for all HTTP/TLS clients`.

## 2026-04-23T21:15:24Z - DT-027
- What was implemented
  - Deleted `tests/native-save-state.test.ts`, which mocked `NativeActorContext` and never exercised the real NAPI boundary.
  - Added `saveStateActor` and `saveStateObserver` driver fixtures plus a new `actor-save-state.test.ts` driver file that verifies `saveState({ immediate: true })` and `saveState({ maxWait })` survive a real hard crash across bare, CBOR, and JSON.
  - Removed the now-unused `resetNativePersistStateForTest` hook and documented the driver-first persistence testing rule in `rivetkit-typescript/CLAUDE.md`.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/fixtures/driver-test-suite/save-state.ts`
  - `rivetkit-typescript/packages/rivetkit/fixtures/driver-test-suite/registry-static.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-save-state.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/native-save-state.test.ts`
  - `rivetkit-typescript/packages/rivetkit/src/registry/native.ts`
  - `rivetkit-typescript/CLAUDE.md`
- **Learnings for future iterations:**
  - For native persistence behavior, use a real driver actor that blocks after `saveState(...)`, then crash it with `hardCrashActor` to prove durability without a mocked NAPI context.
  - An observer actor is the simplest way to signal that a save checkpoint has been reached before forcing the crash.
---
- Publish workflow: `24832562681` passed all 15 jobs; preview version `0.0.0-pr.4701.d2c139c`.
- Sanity check: Docker `node:22` install and E2E passed HTTP actions and WebSocket action/event checks; host run was polluted by an existing engine on `:6420`, so Docker was the clean Bookworm-style validation.
- **Learnings for future iterations:**
  - `hyper-tls` can pull `native-tls`/`openssl-sys` independently of `reqwest`; check direct Hyper clients as well as workspace `reqwest`.
  - Cargo's inverse tree success for absent deps is phrased as `error: package ID specification 'X' did not match any packages`.
  - For package sanity checks, Docker `node:22` avoids false results from a developer machine that already has a `rivet-engine` bound to port `6420`.
---
## 2026-04-23T11:57:29Z - DT-044
- Restored the serverless `Registry.handler()` / `Registry.serve()` surface through the native rivetkit-core path and kept TypeScript to `Request`/`Response` stream plumbing.
- Simplified `Registry.start()` to the native envoy path only; documented the current `staticDir` gap in `CHANGELOG.md`.
- Added static/http/bare driver coverage for `/`, `/health`, `/metadata`, invalid `/start` headers, and a real `CommandStartActor` `/start` payload that reaches the native envoy and streams SSE pings.
- Fixed the `rivetkit-core` counter example to use `ActorEvent::RunGracefulCleanup`, which unblocked `cargo build -p rivetkit-core`.
- Files changed: `CHANGELOG.md`, `rivetkit-rust/packages/rivetkit-core/examples/counter.rs`, `rivetkit-typescript/packages/rivetkit/runtime/index.ts`, `rivetkit-typescript/packages/rivetkit/src/registry/index.ts`, `rivetkit-typescript/packages/rivetkit/tests/driver/serverless-handler.test.ts`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/serverless-handler.test.ts` passed; `cargo build -p rivetkit-core` passed; `cargo test -p rivetkit-core serverless` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `rg -n "removedLegacyRoutingError" rivetkit-typescript` returned zero matches; `git diff --check` passed.
- Caveat: full `cargo test -p rivetkit-core` still fails on existing lifecycle/sleep tests outside the serverless module, so this story is green on targeted gates but the branch still has unrelated core-suite debt.
- **Learnings for future iterations:**
  - Serverless `/start` payloads can be generated with `@rivetkit/engine-envoy-protocol` by prepending the little-endian envoy protocol version to a `ToEnvoyCommands` payload.
  - The actor ID in a serverless `/start` driver test must come from the same engine namespace used in the `x-rivet-namespace-name` header.
  - `Registry.start()` is native-envoy-only now; built-in `staticDir` serving is intentionally documented as a follow-up gap.
---
## 2026-04-23T12:02:25Z - DT-042
- Removed the experimental `overrideRawDatabaseClient` hook from the actor driver interface and database provider context.
- Collapsed the raw `db()` factory so it always requires the native database provider path instead of accepting a custom raw client override.
- Files changed: `rivetkit-typescript/packages/rivetkit/src/actor/driver.ts`, `rivetkit-typescript/packages/rivetkit/src/common/database/config.ts`, `rivetkit-typescript/packages/rivetkit/src/common/database/mod.ts`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `rg -n "overrideRawDatabaseClient" rivetkit-typescript` returned zero matches; `rg -n "overrideDrizzleDatabaseClient" ...` confirmed the Drizzle override still exists; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `pnpm -F rivetkit test tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-db-pragma-migration.test.ts` passed with 72 tests.
- **Learnings for future iterations:**
  - Raw `db()` now depends exclusively on the native database provider; only Drizzle keeps an experimental override path.
---
## 2026-04-23T12:15:22Z - DT-008
- Re-ran the DT-008 full-file verifier for the six tracked driver files.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 239 passed, 4 failed, 33 skipped.
- Added follow-up stories for new failures: DT-045 (`actor-conn` bare `onOpen should be called when connection opens`) and DT-046 (`actor-inspector` cbor database execute named properties). Existing DT-014 already covers the conn-error-serialization timeout.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verification story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied.
- **Learnings for future iterations:**
  - DT-008 can surface new full-file failures outside the original fast/slow bare sweep; add concrete DT follow-up stories instead of marking the verifier green.
  - The six-file verifier runs all encodings for those files and can take about 9 minutes.
---
## 2026-04-23T12:19:11Z - DT-011
- Rechecked the actor-conn oversized response timeout from the fast bare matrix; it no longer reproduces on the current branch, so no source edit was needed.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare oversized response passed; full `actor-conn.test.ts` passed with 69 passed; parallel bare actor-conn suite passed with 23 passed and 46 skipped.
- **Learnings for future iterations:**
  - Treat stale DT failures as closeable only after the exact targeted case, whole file, and matrix-shaped repro all pass.
---
## 2026-04-23T12:22:37Z - DT-046
- Rechecked the CBOR inspector database named-properties failure from DT-008; it no longer reproduces on the current branch.
- Confirmed the setup actions, CBOR action serialization, and inspector database execute endpoint all succeed in the targeted and whole-file verifier.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted CBOR named-properties test passed; full `actor-inspector.test.ts` passed with 63 passed; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed.
- **Learnings for future iterations:**
  - For stale full-file driver failures, close the spawned story only after the exact encoding-specific target and the full file both pass on the current branch.
---
## 2026-04-23T12:26:06Z - DT-045
- Rechecked the bare `actor-conn` onOpen failure from DT-008; it no longer reproduces on the current branch.
- Confirmed the targeted bare onOpen case and the full `actor-conn.test.ts` verifier both pass.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare onOpen test passed; full `actor-conn.test.ts` passed with 69 passed; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Stale callback-ordering failures should be closed only after the exact encoding-specific test and the full file both pass.
---
## 2026-04-23T12:40:56Z - DT-012
- Fixed the actor queue enqueue-and-wait race in `rivetkit-core`: completion waiters are registered before the queue message is published to KV.
- Added cleanup for the pre-registered waiter if the KV publish fails, preserving the existing fail-fast behavior instead of hiding errors.
- Files changed: `rivetkit-rust/packages/rivetkit-core/src/actor/queue.rs`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `cargo build -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; targeted bare and CBOR wait-send tests passed; full `actor-queue.test.ts` passed with 75 tests; parallel bare actor-queue suite passed with 25 tests; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Queue completion waiters must exist before queue messages become visible in KV, because action/run consumers can drain and complete the message immediately.
  - A one-off `no_envoys` failure in the full actor-queue file did not reproduce in the isolated run or subsequent full-file verification; keep watching that path if it reappears.
---
## 2026-04-23T13:06:56Z - DT-014
- Implemented structured actor-connect WebSocket setup errors in `rivetkit-core`.
- Fixed connection-level `Error` frames for JSON/CBOR by emitting `actionId: null`, matching the client schema.
- Files changed: `rivetkit-rust/packages/rivetkit-core/src/registry/actor_connect.rs`, `rivetkit-rust/packages/rivetkit-core/src/registry/websocket.rs`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: targeted bare createConnState error passed; full `conn-error-serialization.test.ts` passed with 9 tests; parallel bare conn-error-serialization suite passed with 3 tests; `cargo build -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed.
- DT-008 recheck remains blocked by existing DT-016 hibernatable WebSocket bare failures: welcome message was undefined and cleanup-on-restore timed out.
- **Learnings for future iterations:**
  - Actor-connect setup failures happen before `Init`, so a close-only path can leave queued connection actions unresolved for bare/CBOR clients.
  - Connection-level protocol errors use `actionId: null`; omitting the field breaks JSON/CBOR client schema validation.
---
## 2026-04-23T13:11:10Z - DT-013
- Rechecked the actor-workflow destroy-step failure; it no longer reproduces on the current branch, so no source edit was needed.
- Confirmed the workflow step calls `destroy`, `onDestroy` is observed, and `client.workflowDestroyActor.get([key]).resolve()` now rejects as `actor/not_found`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare workflow destroy passed; full `actor-workflow.test.ts` passed with 54 tests and 3 skips; parallel bare actor-workflow suite passed with 18 tests and 39 skips; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Stale workflow/lifecycle driver failures should be closed only after the exact encoding-specific target, the full file, and the matrix-shaped suite all pass on the current branch.
---
## 2026-04-23T20:15:29Z - DT-019
- What was implemented
  - Reduced the pegboard-envoy v1 migration lease from 5 minutes to 60 seconds with a comment that ties the window to the staged import chunk count.
  - Added `SqliteEngine::invalidate_v1_migration(...)` and called it from the authoritative `CommandStartActor` start path so a crashed owner does not block the next Allocate.
  - Added a regression test that simulates `commit_stage_begin`, a dead owner, Allocate invalidation, and a successful migration restart without waiting for lease expiry.
- Files changed
  - `engine/packages/pegboard-envoy/src/sqlite_runtime.rs`
  - `engine/packages/sqlite-storage/src/takeover.rs`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - The cheapest production invalidation path was reusing `prepare_v1_migration` cleanup semantics instead of inventing a second staged-row wipe path.
  - For v1 migration recovery, the authoritative signal is the new `CommandStartActor` delivery, not the old lease timer.
  - Verification passed for `cargo test -p sqlite-storage`, `cargo test -p pegboard-envoy`, `pnpm check-types`, the targeted CBOR vacuum repro, and the static/http/bare `actor-db.test.ts` slice. The unfiltered `actor-db.test.ts` file still hit an unrelated CBOR `supports shrink and regrow workloads with vacuum` internal-error failure on this branch.
---
## 2026-04-23T13:23:10Z - DT-008
- Re-ran the DT-008 six-file verifier for `actor-conn`, `conn-error-serialization`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol`.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 240 passed, 3 failed, 33 skipped.
- Added follow-up stories: DT-047 for the bare `actor-conn` `isConnected should be false before connection opens` failure and DT-048 for the bare/CBOR `conn-error-serialization` `createConnState` timeout under the DT-008 verifier load.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verifier story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied.
- **Learnings for future iterations:**
  - The six-file verifier can expose ordering or load-sensitive regressions even after exact targeted and whole-file story checks have passed.
  - A closed story can need a new follow-up when the failure only reproduces under the DT-008 combined verifier shape.
---
## 2026-04-23T13:38:30Z - DT-048
- Rebuilt `@rivetkit/rivetkit-napi` because the local `.node` artifact was older than `rivetkit-core/src/registry/websocket.rs`.
- Confirmed the bare/CBOR `createConnState` setup error now reaches pending connection actions as structured `connection/custom_error` again.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare createConnState passed; targeted CBOR createConnState passed; full `conn-error-serialization.test.ts` passed with 9 tests; six-file DT-008 verifier had `conn-error-serialization` green across bare/CBOR/JSON and remains blocked only by DT-047 actor-conn; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Driver tests can lie like hell when the checked-out Rust source is newer than the compiled local NAPI artifact; compare timestamps or just rebuild NAPI after core WebSocket/protocol changes.
  - Do not run separate Vitest driver processes in parallel against the native harness while validating a full file; local runtime startup can race and produce bogus `ECONNREFUSED` failures.
---
## 2026-04-23T13:51:44Z - DT-047
- Rechecked the bare `actor-conn` `isConnected should be false before connection opens` failure from the DT-008 verifier; it no longer reproduces on the current branch.
- Confirmed `actor-conn` passed in the six-file DT-008 verifier shape across bare/CBOR/JSON. The same combined run still failed on the recurring static/CBOR `conn-error-serialization` createConnState timeout, so DT-048 was reopened.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare `isConnected` test passed; full `actor-conn.test.ts` passed with 69 tests; six-file DT-008 verifier showed `actor-conn` green and failed only `conn-error-serialization` CBOR; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - A story-specific verifier can pass its target file inside a combined run even when the combined command exits nonzero for a different tracked file; record both facts instead of calling the whole DT-008 slice green.
---
## 2026-04-23T14:04:08Z - DT-008
- Re-ran the DT-008 six-file verifier for `actor-conn`, `conn-error-serialization`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol`.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 241 passed, 2 failed, 33 skipped.
- Updated DT-048 to include the same `conn-error-serialization` `createConnState` timeout under static/JSON, and added DT-049 for the new static/JSON `actor-sleep-db` `nested waitUntil inside waitUntil is drained before shutdown` timeout.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verifier story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied. `hibernatable-websocket-protocol` passed in the combined verifier with 6 passed and 0 failed across bare/CBOR/JSON.
- **Learnings for future iterations:**
  - DT-008 combined-load failures can migrate between encodings even when targeted and whole-file checks passed earlier; keep the pending story acceptance criteria aligned with the latest observed encoding.
  - `hibernatable-websocket-protocol` is currently green in the six-file verifier across bare/CBOR/JSON, but DT-008 remains red until `conn-error-serialization`, `actor-sleep-db`, and `raw-websocket` are all cleared.
---
## 2026-04-23T14:21:20Z - DT-049
- Rechecked the actor-sleep-db JSON nested waitUntil timeout from DT-008; it no longer reproduces on the current branch.
- Confirmed actor-sleep-db passed in the exact JSON target, the full file, and the six-file DT-008 verifier shape across bare/CBOR/JSON.
- Added DT-050 for the new combined-verifier failure: actor-workflow static/CBOR `starts child workflows created inside workflow steps` reported a child workflow result of `timedOut` instead of completed.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted JSON nested waitUntil passed; full `actor-sleep-db.test.ts` passed with 42 active tests; six-file DT-008 verifier failed only on DT-050 actor-workflow after 242 passed and 33 skipped; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - DT-008 combined-verifier failures can be stale by the next run; close them only after the exact target, full file, and combined shape show the target file green.
  - A green target file inside a red combined run is still useful closure for that story; add a new DT story for the different failing file instead of keeping the stale story open.
---
## 2026-04-23T14:32:45Z - DT-008
- Re-ran the DT-008 six-file verifier for `actor-conn`, `conn-error-serialization`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol`.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 241 passed, 2 failed, 33 skipped.
- The current failures are covered by existing pending stories: DT-048 for `conn-error-serialization` static/JSON `createConnState` timeout, and DT-050 for `actor-workflow` child workflow result `timedOut` under combined verifier load.
- Updated DT-050 to include static/JSON coverage in addition to the prior static/CBOR failure.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verifier story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied.
- **Learnings for future iterations:**
  - Existing follow-up stories should be broadened when DT-008 exposes the same underlying failure under another encoding; do not spawn duplicate stories for the same file/test/root symptom.
---
## 2026-04-23T14:55:02Z - DT-008
- Re-ran the DT-008 six-file verifier for `actor-conn`, `conn-error-serialization`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol`.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 240 passed, 3 failed, 33 skipped.
- The current failures are covered by existing pending story DT-048: `conn-error-serialization` bare/CBOR/JSON `createConnState` timed out at `tests/driver/conn-error-serialization.test.ts:7`.
- `actor-workflow` passed in this combined verifier run (57 tests, 3 skipped), so the DT-050 symptom did not reproduce this time.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verifier story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied.
- **Learnings for future iterations:**
  - The current DT-008 blocker is isolated to `conn-error-serialization` setup-error handling under combined verifier load; actor-workflow can pass in the same combined shape.
---
## 2026-04-23T15:18:32Z - DT-048
- Implemented a gateway fix for immediate actor-connect setup-error closes under DT-008 combined verifier load.
- `pegboard-gateway2` now drains tunnel messages queued between envoy open acknowledgement and websocket forwarding task startup, then processes those messages before waiting on the receiver.
- Reopened DT-047 because the six-file verifier now fails the recurring static/bare actor-conn `isConnected should be false before connection opens` case.
- Files changed: `engine/packages/pegboard-gateway2/src/lib.rs`, `engine/packages/pegboard-gateway2/src/tunnel_to_ws_task.rs`, `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted bare/CBOR/JSON createConnState checks passed; full `conn-error-serialization.test.ts` passed with 9 tests; six-file DT-008 verifier showed `conn-error-serialization` green but failed DT-047 actor-conn after 242 passed and 33 skipped; `cargo build -p pegboard-gateway2` passed; `cargo build -p rivet-engine` passed; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Actor-connect setup errors can close immediately after the envoy open ack, so the gateway cannot assume the spawned websocket forwarding task will be the first receiver to observe queued tunnel messages.
  - A combined verifier failure can bounce back to a previously closed story; reopen that story when the exact acceptance target regresses instead of keeping the newly fixed story open.
---
## 2026-04-23T15:29:56Z - DT-008
- Re-ran the DT-008 six-file verifier for `actor-conn`, `conn-error-serialization`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol`.
- DT-008 remains blocked: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-inspector.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-sleep-db.test.ts tests/driver/hibernatable-websocket-protocol.test.ts` failed with 242 passed, 1 failed, 33 skipped.
- The current failure is covered by reopened story DT-048: static/bare `conn-error-serialization` `createConnState preserves group/code` timed out at `tests/driver/conn-error-serialization.test.ts:7`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: failed by design for this verifier story; no source code was changed and no commit was made because DT-008 acceptance criteria are not satisfied. Slack notification was sent after the long verifier completed.
- **Learnings for future iterations:**
  - The combined verifier can regress a story immediately after a targeted/full-file fix passes; reopen the existing story when the same exact file/test symptom returns instead of spawning a duplicate.
  - In this run, `actor-conn`, `actor-inspector`, `actor-workflow`, `actor-sleep-db`, and `hibernatable-websocket-protocol` all passed in the six-file shape; the blocker is isolated to bare `conn-error-serialization`.
---
## 2026-04-23T16:10:02Z - DT-048
- Implemented deterministic actor-connect setup-error delivery by adding an envoy `WebSocketSender::flush()` barrier and using it before setup-error close frames.
- Fixed client actor-connect error routing so `actionId: 0` is treated as a valid action error, not a connection-level error.
- Files changed: `engine/sdks/rust/envoy-client/src/{actor.rs,config.rs}`, `rivetkit-rust/packages/rivetkit-core/src/registry/websocket.rs`, `rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `rivetkit-typescript/CLAUDE.md`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: targeted JSON createConnState passed; full `conn-error-serialization.test.ts` passed with 9 tests; six-file DT-008 verifier passed with 243 passed and 33 skipped; `cargo build -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed. Slack notification was sent after the long verifier completed.
- **Learnings for future iterations:**
  - Setup-error `Error` frames queued immediately before close need an explicit sender flush; a scheduler yield is not a protocol boundary.
  - JSON setup-error handling can pass via close reason alone, so inspect logs for the structured `connection error` message to confirm the protocol frame actually arrived.
  - Actor-connect `actionId` uses `null` for connection errors; `0` is the first valid action ID.
---
## 2026-04-23 14:37:50 PDT - DT-030
- What was implemented
  - Verified the existing `TODO(#4706)` annotation on the skipped `actor-lifecycle` destroy-during-start test already satisfies DT-030's ticket path, so no runtime or test-source change was needed.
  - Closed the story in `prd.json` after confirming the annotated skip policy and the full `actor-lifecycle` driver file are green on this branch.
- Files changed
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - For `fix or ticket` PRD stories, do not churn code just to manufacture a diff. If the skip already has an adjacent `TODO(#issue)` and the relevant full test file passes, close the story with verification.
  - `actor-lifecycle.test.ts` is already covered by the annotated-skip guard from `pnpm run check:test-skips`; use that before assuming a remaining `passes: false` story still needs source changes.
---
## 2026-04-23T16:23:57Z - DT-008
- Re-ran the static/http/bare fast and slow driver verifiers for the tracked DT-008 slice.
- DT-008 remains blocked: fast static/http/bare failed with 285 passed, 2 failed, and 577 skipped; slow static/http/bare passed with 68 passed and 166 skipped.
- Existing story DT-047 covers the recurring `actor-conn` bare `isConnected should be false before connection opens` failure at `tests/driver/actor-conn.test.ts:419`.
- Added DT-051 for the new `actor-queue` bare `drains many-queue child actors created from run handlers while connected` failure at `tests/driver/actor-queue.test.ts:303`, where `dispatch_queue_send` returned `actor.overloaded`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed by design; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <slow driver files> -t "static registry.*encoding \\(bare\\)"` passed. No source code was changed.
- **Learnings for future iterations:**
  - DT-008 should stay red when the fast parallel bare sweep finds new failures, even if the six-file verifier was green earlier.
  - A new fast-suite failure needs a concrete PRD story immediately; progress log lines alone are not the work queue.
---
## 2026-04-23T16:27:47Z - DT-015
- Rechecked the stale raw-websocket hibernatable ack-state failure; it no longer reproduces on the current branch.
- Confirmed both targeted static/http/bare ack-state tests and the full raw-websocket file pass.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: targeted indexed ack test passed; targeted threshold-buffered ack test passed; full `raw-websocket.test.ts` passed with 39 tests across bare/CBOR/JSON; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Stale driver stories can be closed without source changes only after the exact target checks, whole-file verifier, and typecheck all pass on the current branch.
---
## 2026-04-23T16:44:04Z - DT-008
- Re-ran the static/http/bare fast and slow driver verifiers for the DT-008 slice.
- DT-008 remains blocked: fast failed with 285 passed, 2 failed, 577 skipped; slow failed with 67 passed, 1 failed, 166 skipped.
- Reopened DT-015 for the raw-websocket threshold ack regression, kept DT-047 open for actor-conn, and added DT-052 for the new actor-run startup failure.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed on `actor-conn` and `raw-websocket`; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <slow driver files> -t "static registry.*encoding \\(bare\\)"` failed on `actor-run`. No source code was changed and no commit was made because DT-008 acceptance criteria are still not satisfied.
- **Learnings for future iterations:**
  - A previously closed driver story is not actually dead until the matrix-shaped verifier stays green; reopen the existing story when the exact same test regresses instead of spawning a duplicate.
  - The static/http/bare fast and slow parallel sweeps can expose different failures in the same iteration, so finish both runs before deciding which follow-up stories to open.
---
## 2026-04-23T16:58:02Z - DT-008
- Re-ran the static/http/bare fast and slow driver verifiers for the DT-008 slice.
- DT-008 remains blocked: fast failed with 286 passed, 1 failed, 577 skipped; slow passed with 68 passed, 0 failed, 166 skipped.
- The old fast/slow blockers did not reproduce in this sweep: actor-conn, actor-queue, raw-websocket, and actor-run all passed. Added DT-053 for the new lifecycle-hooks bare `rejects connection with generic error` timeout at `tests/driver/lifecycle-hooks.test.ts:31`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed only on `lifecycle-hooks`; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <slow driver files> -t "static registry.*encoding \\(bare\\)"` passed. No source code was changed and no commit was made because DT-008 acceptance criteria are still not satisfied.
- **Learnings for future iterations:**
  - The matrix-shaped verifier can clear several stale blockers and still surface a completely different failing file in the same sweep, so update the suite status to match the latest run instead of leaving old `[!]` markers around.
  - DT-008 is still a moving target even when the previous follow-up stories stop reproducing; the current blocker list has to come from the newest fast/slow verifier, not yesterday's failures.
---
## 2026-04-23T10:14:28Z - DT-053
- Implemented a registry-level timeout around actor-connect websocket setup so `onBeforeConnect` failures cannot leave upgraded sockets hanging until the Vitest client timeout.
- Files changed: `rivetkit-rust/packages/rivetkit-core/src/registry/websocket.rs`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `cargo build -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm test tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\).*rejects connection with generic error"` passed; `pnpm test tests/driver/lifecycle-hooks.test.ts` passed with 24 tests; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\).*Lifecycle Hooks"` passed; `pnpm check-types` passed.
- **Learnings for future iterations:**
  - The HTTP websocket upgrade can succeed before `connection_open` responds, so actor-connect setup needs its own timeout at the registry boundary rather than relying on the client-side websocket timeout.
  - When a Rust core change touches driver behavior, rebuild `@rivetkit/rivetkit-napi` before trusting a TypeScript driver repro; stale `.node` artifacts will waste your time.
  - `lifecycle-hooks` can pass in an isolated test case while still hanging in the full file, so re-run the whole file before calling the story fixed.
---
## 2026-04-23T17:27:18Z - DT-008
- Re-ran the static/http/bare fast and slow driver verifiers for the DT-008 slice.
- DT-008 remains blocked: fast failed with 286 passed, 1 failed, 577 skipped; slow failed with 67 passed, 1 failed, 166 skipped.
- Reopened DT-045 for the recurring bare `actor-conn` `onOpen should be called when connection opens` regression, and added DT-054 for the new bare `actor-run` `run handler that throws error sleeps instead of destroying` failure.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed on `actor-conn`; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <slow driver files> -t "static registry.*encoding \\(bare\\)"` failed on `actor-run`. No source code was changed and no commit was made because DT-008 acceptance criteria are still not satisfied.
- **Learnings for future iterations:**
  - Reopen the exact closed story when the same matrix verifier symptom returns, even if an isolated recheck had looked green earlier.
  - Do not stuff a new failing test into an existing story just because it shares a file; `actor-run` now has both the startup regression in DT-052 and a separate error-path regression in DT-054.
---
## 2026-04-23T17:46:03Z - DT-008
- Re-ran the six DT-008 tracked static/http/bare full-file verifiers plus the fast and slow parallel bare sweeps.
- DT-008 remains blocked: all six tracked files passed individually, fast parallel failed with 285 passed, 2 failed, 577 skipped, and slow parallel passed with 68 passed, 0 failed, 166 skipped.
- Existing story DT-047 still covers bare `actor-conn` `isConnected should be false before connection opens`; added DT-055 for bare `actor-db` `handles repeated updates to the same row` failing with `RivetError: An internal error occurred` at `tests/driver/actor-db.test.ts:438`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `pnpm test tests/driver/actor-conn.test.ts -t "static registry.*encoding \\(bare\\)"`, `pnpm test tests/driver/conn-error-serialization.test.ts -t "static registry.*encoding \\(bare\\)"`, `pnpm test tests/driver/actor-inspector.test.ts -t "static registry.*encoding \\(bare\\)"`, `pnpm test tests/driver/actor-workflow.test.ts -t "static registry.*encoding \\(bare\\)"`, `pnpm test tests/driver/actor-sleep-db.test.ts -t "static registry.*encoding \\(bare\\)"`, and `pnpm test tests/driver/hibernatable-websocket-protocol.test.ts -t "static registry.*encoding \\(bare\\)"` all passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed on `actor-conn` and `actor-db`; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test <slow driver files> -t "static registry.*encoding \\(bare\\)"` passed. No source code was changed and no commit was made because DT-008 acceptance criteria are still not satisfied.
- **Learnings for future iterations:**
  - Latest verifier state should flip suite markers in both directions. `actor-run` goes back to green when the newest slow sweep passes, and `actor-db` has to be marked dirty the moment the newest fast sweep regresses it.
  - New DT-008 blockers can appear outside the six tracked verifier files, so the follow-up queue has to come from the newest fast/slow sweep rather than the older tracked-file list.
---
## 2026-04-23T18:09:23Z - DT-008
- Re-ran the DT-008 six-file verifier plus the static/http/bare fast and slow sweeps.
- DT-008 remains blocked: the six-file verifier failed with 242 passed, 1 failed, 33 skipped; fast failed with 286 passed, 1 failed, 577 skipped; slow passed with 68 passed, 0 failed, 166 skipped.
- Existing story DT-050 still covers the static/CBOR actor-workflow child-workflow timeout; added DT-056 for bare actor-queue `drains many-queue child actors created from actions while connected` failing with `RivetError: Actor reply channel was dropped without a response` at `tests/driver/actor-queue.test.ts:287`.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: the six-file verifier failed only on `tests/driver/actor-workflow.test.ts`; the fast bare sweep failed only on `tests/driver/actor-queue.test.ts`; the slow bare sweep passed; `pnpm -F rivetkit check-types` passed. No source code was changed and no commit was made because DT-008 acceptance criteria are still not satisfied.
- **Learnings for future iterations:**
  - The `actor-queue` fast-suite regressions split across two different many-queue paths. Keep the action-created child failure in its own story instead of folding it into DT-051's run-handler path.
  - The newest verifier run still owns the suite markers. `actor-conn` and `actor-db` go back to green as soon as the latest fast sweep clears them, even if an older run had them marked dirty.
---
## 2026-04-23T18:30:44Z - DT-008
- Re-ran the six tracked DT-008 full-file verifiers, then reran the exact static/http/bare fast and slow sweeps using the explicit progress-bucket file lists.
- DT-008 passed: all six tracked files were green, fast bare passed with 287 passed and 577 skipped, and slow bare passed with 68 passed and 166 skipped.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: full `actor-conn.test.ts` passed with 69 tests; full `conn-error-serialization.test.ts` passed with 9 tests; full `actor-inspector.test.ts` passed with 63 tests; full `actor-workflow.test.ts` passed with 54 tests and 3 skips; full `actor-sleep-db.test.ts` passed with 42 tests and 30 skips; full `hibernatable-websocket-protocol.test.ts` passed with 6 tests; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test <fast driver files> -t "static registry.*encoding \\(bare\\)"` passed with 287 passed and 577 skipped; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test <slow driver files> -t "static registry.*encoding \\(bare\\)"` passed with 68 passed and 166 skipped; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - DT-008 is only actually done once the tracked full-file batch and the explicit fast/slow bare sweeps are both green in the same pass.
  - The progress-suite markers need to move back to `[x]` as soon as the newest verifier clears the file, even if an earlier sweep had reopened it.
---
## 2026-04-23T18:35:53Z - DT-009
- Ran the DT-009 full-matrix sweep from the top of the driver list using whole-file runs across the default static `bare`/`cbor`/`json` matrix, stopping at the first red file as the driver-test-runner workflow requires.
- `manager-driver.test.ts` failed first: static/CBOR and static/JSON `input is undefined when not provided` returned `null` instead of `undefined`, while the same case still passed under bare. Added follow-up story DT-057 with the exact repro and acceptance gates.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/manager-driver.test.ts` failed with 46 passed and 2 failed; `pnpm -F rivetkit test tests/driver/manager-driver.test.ts -t "input is undefined when not provided"` failed with the same two CBOR/JSON assertions at `tests/driver/manager-driver.test.ts:159`. No source code was changed and no commit was made because DT-009 is still blocked.
- **Learnings for future iterations:**
  - A file can be green for static/http/bare and still fail immediately in the broader DT-009 matrix because CBOR/JSON normalize omitted values differently.
  - For DT-009, stop at the first failing file, spawn the concrete DT story immediately, and keep the whole-file plus targeted repro outputs together so the next iteration can jump straight into the real bug.
---
## 2026-04-23T18:42:27Z - DT-047
- Rechecked the reopened `actor-conn` before-open state regression and confirmed it is stale on this branch.
- No source code changed. The exact bare target passed, the full `actor-conn.test.ts` file passed across bare/CBOR/JSON, and `pnpm -F rivetkit check-types` passed.
- Files changed: `scripts/ralph/prd.json`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/actor-conn.test.ts -t "static registry.*encoding \\(bare\\).*isConnected should be false before connection opens"` passed; `pnpm -F rivetkit test tests/driver/actor-conn.test.ts` passed with 69 tests; `pnpm -F rivetkit check-types` passed. The latest successful DT-008 tracked verifier on this branch already had `actor-conn` green, so DT-047 is closed as a stale non-repro.
- **Learnings for future iterations:**
  - A reopened DT-008 verifier story can be stale even when the tracker is still red. Re-run the exact target and the full file before touching `actor-conn` code.
  - Use the latest successful DT-008 tracked verifier on the branch as the combined-run receipt when a fresh combined rerun is blocked by a different story.
---
## 2026-04-23T18:55:01Z - DT-057
- Fixed the manager-driver omitted-input regression by preserving JS `undefined` in opaque payloads that cross the native CBOR/JSON bridge, while leaving structural JSON envelopes untouched.
- Files changed: `rivetkit-typescript/CLAUDE.md`, `rivetkit-typescript/packages/rivetkit/src/{common/encoding.ts,common/router.ts,serde.ts,registry/native.ts,client/actor-handle.ts,client/actor-conn.ts,client/queue.ts,client/utils.ts,engine-client/mod.ts,engine-client/actor-websocket-client.ts,inspector/actor-inspector.ts,workflow/inspector.ts}`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/{prd.json,progress.txt}`.
- Verification: `pnpm -F rivetkit test tests/driver/manager-driver.test.ts -t "input is undefined when not provided"` passed; `pnpm -F rivetkit test tests/driver/manager-driver.test.ts` passed with 48 tests; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed.
- **Learnings for future iterations:**
  - The native bridge can safely carry `undefined` only inside opaque payload bytes; structural JSON request/response envelopes still need normal omitted-field semantics.
  - Reviving compat sentinels in shared decode helpers is cheaper than chasing `null`/`undefined` mismatches one transport at a time.
---
## 2026-04-23T19:01:25Z - DT-015
- Rechecked the reopened raw-websocket hibernatable threshold ack regression and confirmed it is stale on the current branch.
- No source code changed. The exact bare threshold target passed, five repeated bare reruns stayed green, the full `raw-websocket.test.ts` file passed across bare/CBOR/JSON, and `pnpm -F rivetkit check-types` passed.
- Files changed: `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/raw-websocket.test.ts -t "static registry.*encoding \\(bare\\).*acks buffered indexed raw websocket messages immediately at the threshold"` passed; a five-run loop of that same bare target passed every time; `pnpm -F rivetkit test tests/driver/raw-websocket.test.ts` passed with 39 tests; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Reopened matrix regressions can still be stale ghosts. Re-run the exact target and the whole file before touching raw-websocket code.
  - A one-off `1006` on a large raw websocket case is not enough evidence for a fix if repeated targeted reruns and the full file stay green on the current branch.
---
## 2026-04-23T19:16:56Z - DT-016
- Rechecked the hibernatable websocket replay-ack regression and confirmed it is stale on the current branch.
- No source code changed. The exact bare replay target passed, the full `hibernatable-websocket-protocol.test.ts` file passed across bare/CBOR/JSON, the static/http/bare parallel slice passed, and `pnpm -F rivetkit check-types` passed.
- Files changed: `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/hibernatable-websocket-protocol.test.ts -t "static registry.*encoding \\(bare\\).*replays only unacked indexed websocket messages after sleep and wake"` passed; `pnpm -F rivetkit test tests/driver/hibernatable-websocket-protocol.test.ts` passed with 6 tests; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/hibernatable-websocket-protocol.test.ts -t "static registry.*encoding \\(bare\\)"` passed with 2 bare tests; `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - DT-016 overlaps the later hibernatable ack-state work. On this branch, close it as a stale non-repro instead of inventing a duplicate fix.
  - The matrix slice matters for stale driver stories; a single passing targeted repro is not enough evidence.
---
## 2026-04-23T19:13:49Z - DT-017
- Added the missing `actor-lifecycle` driver coverage for clean run exit followed by sleep by asserting `runSelfInitiatedSleep` records `onSleep` state before the actor wakes again.
- Added one-line justification comments to the `vi.waitFor(...)` calls in `actor-lifecycle.test.ts` so the file matches the repo's polling rule.
- Files changed: `rivetkit-typescript/packages/rivetkit/tests/driver/actor-lifecycle.test.ts`, `scripts/ralph/progress.txt`.
- Verification: `pnpm -F rivetkit test tests/driver/actor-lifecycle.test.ts -t "run-closure-self-initiated-sleep runs onSleep before wake"` passed across bare/CBOR/JSON; `pnpm -F rivetkit test tests/driver/actor-lifecycle.test.ts` passed with 24 tests and 3 skips; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed. `cargo test -p rivetkit-core` is still failing on existing sleep/shutdown tests on this branch, so DT-017 is not marked complete and no commit was made.
- **Learnings for future iterations:**
  - The clean-run-exit lifecycle behavior is now covered in two layers: Rust task tests prove the state machine stays in `Started` until Stop arrives, and the TS driver file now proves the sleep hook fires end-to-end.
  - `cargo test -p rivetkit-core` is currently blocked by broader sleep/shutdown failures outside this test-only diff, so do not mark DT-017 done until that Rust suite is green.
---
## 2026-04-23T12:52:28-0700 - DT-017
- What was implemented: kept clean `run` exits alive until the guaranteed `Stop` drives `SleepGrace` or `DestroyGrace`, fixed grace-loop races that were skipping or delaying lifecycle hooks, and added core plus driver coverage proving `onSleep` and `onDestroy` still fire exactly once after `run` returns.
- Files changed: `rivetkit-rust/packages/rivetkit-core/src/actor/sleep.rs`, `rivetkit-rust/packages/rivetkit-core/src/actor/task.rs`, `rivetkit-rust/packages/rivetkit-core/tests/modules/task.rs`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `rivetkit-typescript/packages/rivetkit/fixtures/driver-test-suite/run.ts`, `rivetkit-typescript/packages/rivetkit/tests/driver/actor-lifecycle.test.ts`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `Terminated` must mean lifecycle cleanup already finished. A clean `run` return while `Started` still owes the single `Stop` and its grace hooks.
  - Grace paths must keep draining dispatch and alarm work; otherwise late `Stop` cleanup can hang or silently skip replies.
  - Shutdown tests that model state persistence need to assert through the final `SerializeState` save path, not ad hoc cleanup writes that later serialization will overwrite.
  - If Rust under `rivetkit-core` changes, rerun the full driver lifecycle file after rebuilding the local NAPI artifact, not just the targeted tests.
---
## 2026-04-23T20:05:53Z - DT-018
- What was implemented: fixed SQLite v2 shrink cleanup so commit/finalize and takeover delete above-EOF PIDX rows plus fully-above-EOF SHARD blobs, and shard compaction now filters truncated pages out of partial shard rewrites instead of folding them back in.
- Files changed: `engine/packages/sqlite-storage/src/commit.rs`, `engine/packages/sqlite-storage/src/takeover.rs`, `engine/packages/sqlite-storage/src/compaction/shard.rs`, `engine/CLAUDE.md`, `.agent/notes/driver-test-progress.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - Shrink cleanup cannot live in compaction alone. The write path has to reclaim above-EOF references immediately or `sqlite_storage_used` keeps lying.
  - Full SHARD blobs can be deleted only when the shard starts above EOF. Partial shards still need compaction to rewrite the blob with `pgno <= head.db_size_pages`.
  - Takeover tests that expect compaction scheduling need live PIDX-backed deltas; orphan DELTAs should now be reclaimed during recovery instead of queued for later compaction.
---
## 2026-04-23T13:29:27-0700 - DT-021
- What was implemented: audited the removed `rivetkit` subpath exports, restored `rivetkit/test`, `rivetkit/inspector`, and `rivetkit/inspector/client` as real current modules, and documented why `driver-helpers`, `topologies/*`, `dynamic`, and `sandbox/*` stay dead.
- Files changed: `rivetkit-typescript/packages/rivetkit/package.json`, `rivetkit-typescript/packages/rivetkit/src/test/mod.ts`, `rivetkit-typescript/packages/rivetkit/src/inspector/mod.ts`, `rivetkit-typescript/packages/rivetkit/src/inspector/client.browser.ts`, `rivetkit-typescript/packages/rivetkit/tsup.browser.config.ts`, `rivetkit-typescript/packages/rivetkit/tests/package-surface.test.ts`, `rivetkit-typescript/CLAUDE.md`, `CHANGELOG.md`, `.agent/notes/dt-021-package-exports-audit.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `rivetkit/test` still matters to examples and docs, but it needs to wrap the native envoy runtime now; the old in-memory TS runtime path is gone.
  - `rivetkit/inspector/client` is still consumed by frontend code and needs a browser build entry, not just a Node-side tsup export.
  - Keep `driver-helpers` and `topologies/*` removed unless a real shipping module and consumer come back; `package-surface.test.ts` is already the guardrail for what stays exported vs intentionally dead.
  - DT-021 checks that passed: `pnpm build -F rivetkit`, `pnpm -F rivetkit check-types`, `pnpm -F rivetkit test tests/package-surface.test.ts tests/inspector-versioned.test.ts`, and the fast static/http/bare driver bare slice (`29` files, `287` passed, `577` skipped).
---
## 2026-04-23T20:38:18Z - DT-022
- What was implemented: removed the duplicate NAPI `ready`/`started` Atomics, forwarded `mark_ready` / `mark_started` / `is_ready` / `is_started` through core `ActorContext`, and kept the NAPI-side `cannot start before ready` guard.
- Files changed: `rivetkit-rust/packages/rivetkit-core/src/actor/context.rs`, `rivetkit-rust/packages/rivetkit-core/src/actor/sleep.rs`, `rivetkit-typescript/packages/rivetkit-napi/src/actor_context.rs`, `rivetkit-typescript/CLAUDE.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `ActorContextShared::reset_runtime_state()` should only clear NAPI-owned runtime wiring. Lifecycle readiness belongs to core and must follow core state, not shared-cache state.
  - When filtering a single driver file, the `describeDriverMatrix(...)` suite name has to match exactly or Vitest skips the whole file and hands you fake green.
  - This refactor stayed green under `cargo test -p rivetkit-core`, `pnpm --filter @rivetkit/rivetkit-napi build:force`, `pnpm -F rivetkit check-types`, `pnpm build -F rivetkit`, and the static/http/bare slices for `actor-sleep`, `actor-sleep-db`, and `actor-lifecycle`.
---
## 2026-04-23T20:51:39Z - DT-024
- What was implemented: documented the intentional removal of the old typed error subclasses in `CHANGELOG.md`, including the `instanceof QueueFull` to `isRivetErrorCode(e, "queue", "full")` migration path and a table of common replacement `group`/`code` pairs.
- Files changed: `CHANGELOG.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - If an API removal is intentional, put the migration recipe in `CHANGELOG.md` instead of making users spelunk Git history.
  - For native/runtime errors, document the stable `RivetError` `group`/`code` contract, not the old subclass names that no longer survive bridge boundaries.
---
## 2026-04-23T13:48:19-0700 - DT-023
- What was implemented: deleted the dead TypeScript `ActorInspector` duplicate plus its unit test, and kept `rivetkit/inspector` as protocol and workflow transport plumbing only so the runtime inspector remains core-owned.
- Files changed: `rivetkit-typescript/packages/rivetkit/src/inspector/mod.ts`, `rivetkit-typescript/packages/rivetkit/src/inspector/actor-inspector.ts`, `rivetkit-typescript/packages/rivetkit/tests/package-surface.test.ts`, `rivetkit-typescript/packages/rivetkit/tests/actor-inspector.test.ts`, `rivetkit-rust/packages/rivetkit-core/tests/modules/task.rs`, `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- Verification: `pnpm -F rivetkit test tests/package-surface.test.ts` passed; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm -F rivetkit test tests/driver/actor-inspector.test.ts` passed; `cargo test -p rivetkit-core` passed.
- **Learnings for future iterations:**
  - The runtime inspector behavior is already core-owned in `registry/inspector.rs` and `registry/inspector_ws.rs`; the old TS `ActorInspector` class was only dead duplicate surface plus tests.
  - Subscriber-capture tests in `rivetkit-core/tests/modules/task.rs` need `test_hook_lock()` when they call `set_default(...)`, or full-suite parallelism turns tracing assertions into flaky garbage.
  - The `actor_task_logs_lifecycle_dispatch_and_actor_event_flow` test is stable when it focuses on lifecycle plus actor-event logs; the dispatch-command assertions were the brittle part under full-suite contention.
---
## 2026-04-23T21:02:30Z - DT-025
- What was implemented: replaced the 50 ms dispatch-cancel polling loop in `registry/native.ts` with event-driven `CancellationToken.onCancelled()` wiring, pushed native `CancellationToken` objects through the NAPI TSF payloads, and deleted the old BigInt registry module `cancel_token.rs`.
- Files changed: `rivetkit-typescript/packages/rivetkit-napi/src/actor_factory.rs`, `rivetkit-typescript/packages/rivetkit-napi/src/napi_actor_events.rs`, `rivetkit-typescript/packages/rivetkit-napi/src/queue.rs`, `rivetkit-typescript/packages/rivetkit-napi/src/lib.rs`, `rivetkit-typescript/packages/rivetkit-napi/src/cancel_token.rs`, `rivetkit-typescript/packages/rivetkit-napi/index.d.ts`, `rivetkit-typescript/packages/rivetkit-napi/index.js`, `rivetkit-typescript/packages/rivetkit/src/registry/native.ts`, `rivetkit-typescript/CLAUDE.md`, `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - NAPI dispatch-cancel plumbing already has a canonical `CancellationToken` TSF surface. If cancel state is crossing into TypeScript, subscribe to that token instead of building a second registry.
  - Queue wait helpers should accept the real cancellation token object so queue-send, action, and HTTP dispatch all share the same cancel path and teardown behavior.
  - Verification that passed: `pnpm --filter @rivetkit/rivetkit-napi build:force`, `pnpm build -F rivetkit`, `pnpm -F rivetkit check-types`, and `pnpm -F rivetkit test tests/driver/actor-conn.test.ts tests/driver/actor-destroy.test.ts tests/driver/action-features.test.ts` (135 passed, 0 failed).
---
## 2026-04-23T21:09:07Z - DT-026
- What was implemented
  - Rewrote `registry-constructor.test.ts` to use a real native registry build via `buildNativeRegistry(...)` instead of spying on `Runtime.create`.
  - Replaced the traces `Date.now` spy helper with fake timers plus `vi.setSystemTime()`, while keeping the allowed `console.warn` silencing spy.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/tests/registry-constructor.test.ts`
  - `rivetkit-typescript/packages/traces/tests/traces.test.ts`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `registry-constructor.test.ts` should assert the current explicit native startup path, not the removed deferred `Runtime.create` prestart behavior.
  - Fake timers are enough for wall-clock assertions in traces tests, but monotonic trace time still needs a live-object `performance.now` override so modules using the original object keep seeing the controlled clock.
  - `buildNativeRegistry(...)` normalizes endpoints with a trailing slash, so assert URL semantics rather than raw string formatting.
---
## 2026-04-23T21:19:09Z - DT-028
- What was implemented
  - Replaced the `expect(true).toBe(true)` sentinel in `actor-lifecycle.test.ts` with a real teardown assertion for the rapid create/destroy race.
  - Each iteration now waits for both `resolve()` and `destroy()`, proves the resolved actor ID rejects with `actor/not_found`, and counts 10 successful cleanups.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-lifecycle.test.ts`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `getForId(actorId)` is a valid teardown proof in driver tests, but it is relatively expensive because actor lookup polls until registry teardown completes.
  - Lifecycle race tests should assert an observed cleanup invariant instead of leaving a no-op sentinel that would stay green after the intended check disappeared.
---
## 2026-04-23T21:30:49Z - DT-029
- What was implemented
  - Filed GitHub issues `#4705` through `#4708` and added adjacent `TODO(issue)` comments to every bare `test.skip(...)` in the touched RivetKit driver files.
  - Added `rivetkit-typescript/packages/rivetkit/scripts/check-annotated-skips.ts` and wired `pnpm run check:test-skips` into package lint so anonymous `test.skip(...)` calls fail fast.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/package.json`
  - `rivetkit-typescript/packages/rivetkit/scripts/check-annotated-skips.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-lifecycle.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-workflow.test.ts`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
  - `.agent/notes/driver-test-progress.md`
- **Learnings for future iterations:**
  - `test.skip(...)` policy is now explicit in this package: keep a tracking ticket on the line above the skip or the new check script will fail.
  - Audit existing bare skips before you add the guard or you just create your own failing lint bomb.
  - `actor-sleep-db.test.ts` full-file verification on this branch remains `42 passed, 30 skipped` across static/http/bare after the annotation-only change.
---
## 2026-04-23 14:57:37 PDT - DT-050
- What was implemented
  - Rechecked the static/CBOR and static/JSON child-workflow timeout repro for `starts child workflows created inside workflow steps`.
  - Confirmed the failure is stale on this branch. No source change was needed.
  - Re-ran the full `actor-workflow.test.ts` file and the six-file DT-008 verifier. `actor-workflow` stayed green; the combined verifier failed elsewhere in `actor-sleep-db`.
- Files changed
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
  - `.agent/notes/driver-test-progress.md`
- **Learnings for future iterations:**
  - Do not invent a fix for a driver ghost. Re-run the exact encoding-specific repro, then the whole file, then the DT-008 combined verifier before touching workflow code.
  - If the combined verifier goes red in a different file, close the stale story and leave the real failure to its own follow-up.
---
## 2026-04-23T22:40:11Z - DT-031
- What was implemented
  - Tightened the remaining placeholder `vi.waitFor(...)` comments so they explain the async condition being polled instead of restating the assertion.
  - Removed stale flake notes for resolved `actor-conn` and inspector replay issues, updated the remaining queue flake note, and kept the `check:wait-for-comments` guard wired into the `rivetkit` package lint scripts.
  - Collapsed repeated destroy polling in `actor-destroy.test.ts` onto the shared helper and removed stray debug `console.log` noise from `actor-conn-state.test.ts`.
- Files changed
  - `.agent/notes/flake-conn-websocket.md`
  - `.agent/notes/flake-inspector-replay.md`
  - `.agent/notes/flake-queue-waitsend.md`
  - `rivetkit-typescript/packages/rivetkit/package.json`
  - `rivetkit-typescript/packages/rivetkit/scripts/check-wait-for-comments.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn-hibernation.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn-state.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db-pragma-migration.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db-stress.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-destroy.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-inspector.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-schedule.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-workflow.test.ts`
  - `AGENTS.md`
- Verification
  - `pnpm run check:test-skips` passed.
  - `pnpm run check:wait-for-comments` passed.
  - `pnpm -F rivetkit check-types` passed.
  - `pnpm -F rivetkit test tests/driver/actor-destroy.test.ts` passed with 30 tests.
  - `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test <fast driver files> -t "static registry.*encoding \\(bare\\)"` failed with 3 `manager-driver.test.ts` timeouts.
  - Targeted bare recheck of those three `manager-driver` cases passed immediately, so DT-031 remains blocked by a combined fast-matrix regression outside the files changed here.
- **Learnings for future iterations:**
  - The wait-for comment guard only checks adjacency. Review the actual wording so the comment explains the async reason for polling instead of repeating the assertion.
  - A red fast static/http/bare sweep can come from an unrelated file after a comment-only story. Re-run the failing slice in isolation before deciding the current diff caused it.
  - Full package `pnpm lint` is currently red on unrelated baseline Biome diagnostics in fixtures and helper tests, so DT-031 verification had to use the story-specific comment checks plus typecheck and runtime tests.
---
## 2026-04-23T23:06:31Z - DT-031
- What was implemented
  - Re-ran the full fast static/http/bare driver slice after the earlier `manager-driver` ghost failure and confirmed the comment/flake-note cleanup is green under combined load.
  - Kept the `vi.waitFor(...)` audit changes, direct event-promise rewrites in `actor-conn.test.ts`, and the `check:wait-for-comments` package guard as the final DT-031 payload.
- Files changed
  - `.agent/notes/flake-conn-websocket.md`
  - `.agent/notes/flake-inspector-replay.md`
  - `.agent/notes/flake-queue-waitsend.md`
  - `CLAUDE.md`
  - `engine/CLAUDE.md`
  - `rivetkit-typescript/packages/rivetkit/package.json`
  - `rivetkit-typescript/packages/rivetkit/scripts/check-wait-for-comments.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn-hibernation.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn-state.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-conn.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db-pragma-migration.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db-stress.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-db.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-destroy.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-inspector.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-schedule.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-workflow.test.ts`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- Verification
  - `pnpm -F rivetkit run check:wait-for-comments` passed.
  - `pnpm -F rivetkit check-types` passed.
  - `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` passed with 287 passed, 0 failed, and 577 skipped.
  - `pnpm -F rivetkit lint` is still red on pre-existing unrelated Biome diagnostics in fixtures/helpers outside DT-031.
- **Learnings for future iterations:**
  - The full fast matrix is the truth serum for comment-only driver stories. If a combined run goes red, rerun the exact slice before assuming the edited files caused it.
  - `check:wait-for-comments` only proves adjacency. Direct event waits are still better than polling when the test already has a concrete event or callback boundary.
  - Shared teardown helpers like `waitForActorDestroyed(...)` keep the required polling comments honest and stop the same destroy-loop boilerplate from rotting in four places.
---
## 2026-04-23T16:27:10-0700 - DT-032
- What was implemented
  - Verified that the branch already contained the DT-032 source changes: required-path native adapter config failures now throw structured `RivetError`s, and focused runtime-error coverage already exists for the missing-config cases.
  - Re-ran the story acceptance gates and marked DT-032 complete in the PRD once the existing fix proved green.
- Files changed
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- Verification
  - `pnpm -F rivetkit test tests/native-runtime-errors.test.ts` passed.
  - `pnpm -F rivetkit check-types` passed.
  - `pnpm build -F rivetkit` passed.
  - `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` passed with 287 passed, 0 failed, and 577 skipped.
- **Learnings for future iterations:**
  - Public config failures in the native adapter should use explicit `RivetError` codes rather than relying on generic `Error` strings to communicate state back across the bridge.
  - If the combined fast bare verifier flakes on an unrelated file, rerun the exact failing bare slice before deciding the current story caused it.
  - `setup()` backfills a default endpoint, so missing-endpoint tests need to clear `registry.parseConfig().endpoint` after parsing instead of assuming the raw setup config stays empty.
---
## 2026-04-23T16:35:02Z - DT-051
- What was implemented
  - Re-ran the exact bare DT-051 repro for `drains many-queue child actors created from run handlers while connected`; it passed.
  - Re-ran the parallel static/http/bare actor-queue slice; the run-handler-created child path stayed green there too.
  - Full `actor-queue.test.ts` verification is still blocked by a sibling actor-queue failure, not DT-051 itself. The failing full-file runs surfaced CBOR action-created child scheduling errors (`no_envoys` -> `guard/actor_ready_timeout`, and once `Actor reply channel was dropped without a response`) before the file could go green.
- Files changed
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-051 can look stale in isolation while `actor-queue.test.ts` still has live sibling debt. Do not mark it complete until the whole file is green.
  - When `actor-queue` full-file verification reports a dropped reply, inspect whether the child actor actually lost scheduling first. In this run the stronger engine-side signal was repeated `no_envoys`.
---
## 2026-04-23 16:40:03 PDT - DT-051
- What was implemented
  - Re-ran DT-051 cleanly after the later queue follow-ups landed. The exact static/bare `drains many-queue child actors created from run handlers while connected` repro passed again.
  - Re-ran the full `actor-queue.test.ts` file sequentially and it passed with 75/75 tests, including both many-child cases across bare, CBOR, and JSON.
  - Re-ran the static/http/bare actor-queue slice with `RIVETKIT_DRIVER_TEST_PARALLEL=1`; it passed with 25 passed and 50 skipped. DT-051 is closed as a stale non-repro on the current branch.
- Files changed
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
  - `.agent/notes/driver-test-progress.md`
- Verification
  - `pnpm -F rivetkit test tests/driver/actor-queue.test.ts -t "static registry.*encoding \\(bare\\).*drains many-queue child actors created from run handlers while connected"` passed.
  - `pnpm -F rivetkit test tests/driver/actor-queue.test.ts` passed with 75 passed, 0 failed.
  - `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/actor-queue.test.ts -t "static registry.*encoding \\(bare\\)"` passed with 25 passed, 0 failed, 50 skipped.
  - `pnpm -F rivetkit check-types` passed.
- **Learnings for future iterations:**
  - Do not close a stale driver story on the single repro alone. Close it only after the exact repro, the full file, and the matrix-shaped slice all pass on the current branch.
  - Do not run multiple native-driver Vitest processes against the same workspace at once unless you want fake `ECONNREFUSED` garbage.
---
## 2026-04-23 17:29:25 PDT - DT-033
- What was implemented
  - Moved the native actor JS runtime caches for vars, SQL wrappers, DB clients, destroy gates, and staged persisted state off actorId-keyed module globals and onto `ActorContext.runtimeState()`.
  - Added a driver regression that destroys an actor, recreates the same key, and proves `createVars()` state resets to `fresh` instead of leaking the previous generation's JS-only vars.
  - Documented the `ActorContext.runtimeState()` pattern in `rivetkit-typescript/CLAUDE.md`.
- Files changed
  - `rivetkit-typescript/packages/rivetkit-napi/src/actor_context.rs`
  - `rivetkit-typescript/packages/rivetkit-napi/index.d.ts`
  - `rivetkit-typescript/packages/rivetkit/src/registry/native.ts`
  - `rivetkit-typescript/packages/rivetkit/fixtures/driver-test-suite/destroy.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/driver/actor-destroy.test.ts`
  - `rivetkit-typescript/CLAUDE.md`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- Verification
  - `pnpm --filter @rivetkit/rivetkit-napi build:force` passed.
  - `pnpm -F rivetkit check-types` passed.
  - `pnpm build -F rivetkit` passed.
  - `pnpm -F rivetkit test tests/driver/actor-destroy.test.ts -t "actor destroy clears ephemeral vars on same-key recreation" --silent=passed-only` passed.
  - `pnpm -F rivetkit test tests/driver/actor-vars.test.ts -t "static registry.*encoding \\(bare\\)" --silent=passed-only` passed.
  - `pnpm -F rivetkit test tests/driver/actor-db.test.ts -t "runs db provider cleanup on destroy" --silent=passed-only` passed.
- **Learnings for future iterations:**
  - JS-only native actor caches should live on `ActorContext.runtimeState()` so actor teardown and same-key recreation share the core lifecycle boundary instead of ad hoc `Map<string, ...>` cleanup.
  - If you want to catch native cache leaks, assert on `vars` or other JS-only state after destroy/recreate. Persisted actor state alone will miss the bug.
  - A broad native-driver DB slice can still go red on unrelated `actor event inbox not configured` or `no_envoys` branch noise, so verify cache-plumbing changes with the most directly relevant DB cleanup test instead of assuming every DB failure came from this diff.
---
## 2026-04-23 21:45:44 PDT - DT-035
- What was implemented
  - Narrowed the exposed TypeScript actor key surface back to `string[]` so `ActorContext.key` matches `ActorKeySchema` and the existing key/query/gateway round-trip contract.
  - Normalized native numeric key segments to strings before they cross into the TypeScript `ActorContext` adapter instead of leaving a fake wider type on the TS side.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/src/actor/config.ts`
  - `rivetkit-typescript/packages/rivetkit/src/registry/native.ts`
  - `rivetkit-typescript/CLAUDE.md`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - TypeScript actor keys are string-only today. If someone wants numeric keys, they need to widen `client/query.ts`, key serialization, and gateway parsing together instead of widening a single interface and pretending it round-trips.
  - Verification passed with `pnpm -F rivetkit check-types`, `pnpm test tests/driver/actor-handle.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts`, and `pnpm build -F rivetkit`.
---
## 2026-04-24 00:24:33 PDT - DT-036
- What was implemented
  - Re-ran the full DT-036 acceptance stack after reverting the out-of-scope `SleepTsKey` experiment in `engine/packages/pegboard/src/workflows/actor2/runtime.rs` that was poisoning the DB verifier.
  - Confirmed the story surface is complete: `ActorContext` no longer exposes `ctx.sql`, `rivetkit/db/drizzle` is the public Drizzle entrypoint again, the compat harness typechecks that subpath, and the package-surface test locks the exports down.
- Files changed
  - `CHANGELOG.md`
  - `rivetkit-typescript/CLAUDE.md`
  - `rivetkit-typescript/packages/rivetkit/scripts/test-drizzle-compat.sh`
  - `rivetkit-typescript/packages/rivetkit/scripts/drizzle-compat-smoke.ts`
  - `rivetkit-typescript/packages/rivetkit/src/actor/config.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/fixtures/napi-runtime-server.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/package-surface.test.ts`
  - `rivetkit-typescript/packages/rivetkit/tsconfig.drizzle-compat.json`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - A story-local package-surface change can look blocked by unrelated runtime noise. Re-run the whole acceptance slice on the current branch before closing it, because stale failures can be caused by out-of-scope experiments elsewhere.
  - The DT-036 Drizzle compatibility check should stay a dedicated typecheck against `rivetkit/db/drizzle`. Running deleted or overly broad driver targets is useless bullshit that only tells you the harness drifted.
  - Verification status: `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit test tests/package-surface.test.ts` passed; `./scripts/test-drizzle-compat.sh` passed for drizzle `0.44` and `0.45`; `pnpm -F rivetkit test tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-db-pragma-migration.test.ts` passed with 72 tests passing.
---
## 2026-04-24 00:33:42 PDT - DT-037
- What was implemented
  - Restored the missing root `*ContextOf` helper surface by recreating `rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts` as a type-only module and re-exporting the helpers from `src/actor/mod.ts`.
  - Updated the context-type docs and changelog so the restored helper exports and the intentionally removed runtime surfaces are documented in the same place.
  - Added a package-surface compile smoke test that imports every restored `*ContextOf` helper from `"rivetkit"`.
- Files changed
  - `CHANGELOG.md`
  - `rivetkit-typescript/CLAUDE.md`
  - `rivetkit-typescript/packages/rivetkit/src/actor/contexts/index.ts`
  - `rivetkit-typescript/packages/rivetkit/src/actor/mod.ts`
  - `rivetkit-typescript/packages/rivetkit/tests/package-surface.test.ts`
  - `website/src/content/docs/actors/index.mdx`
  - `website/src/content/docs/actors/types.mdx`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - The root `rivetkit` package can drop user-facing type helpers even when runtime APIs stay intact. Keep a compile smoke test around the package surface so missing type exports fail loudly instead of being discovered by users later.
  - `*ContextOf` docs need to move in lockstep with `src/actor/contexts/index.ts` and `src/actor/mod.ts`, or the docs turn into fiction fast.
  - Verification status: `pnpm -F rivetkit check-types` passed; `pnpm -F rivetkit test tests/package-surface.test.ts` passed; `pnpm -F rivetkit build` passed; `rg -n "ActionContextOf|BeforeActionResponseContextOf|BeforeConnectContextOf|ConnectContextOf|ConnContextOf|ConnInitContextOf|CreateConnStateContextOf|CreateContextOf|CreateVarsContextOf|DestroyContextOf|DisconnectContextOf|MigrateContextOf|RequestContextOf|RunContextOf|SleepContextOf|StateChangeContextOf|WakeContextOf|WebSocketContextOf" rivetkit-typescript/packages/rivetkit/dist/tsup/mod.d.ts` confirmed the generated declaration surface.
---
## 2026-04-24 00:57:10 PDT - DT-052
- What was implemented
  - Added a runtime-startup acknowledgement handshake so `rivetkit-core` does not finish actor startup until the runtime adapter finishes its preamble.
  - Wired the ack through the NAPI adapter and the typed Rust wrapper, which fixes the `actor-run` startup race where the first action could beat `onWake`/`run` startup after `getOrCreate`.
- Files changed
  - `rivetkit-rust/packages/rivetkit-core/src/actor/lifecycle_hooks.rs`
  - `rivetkit-rust/packages/rivetkit-core/src/actor/task.rs`
  - `rivetkit-rust/packages/rivetkit-core/CLAUDE.md`
  - `rivetkit-typescript/packages/rivetkit-napi/src/actor_factory.rs`
  - `rivetkit-typescript/packages/rivetkit-napi/src/napi_actor_events.rs`
  - `rivetkit-rust/packages/rivetkit/src/registry.rs`
  - `rivetkit-rust/packages/rivetkit/src/start.rs`
  - `rivetkit-rust/packages/rivetkit/src/event.rs`
  - `rivetkit-rust/packages/rivetkit/tests/integration_canned_events.rs`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `ActorTask` flipping to `Started` is not a sufficient readiness signal for native actors. Startup must wait for the runtime adapter to ack that `onWake`/startup preamble finished, or the first `getState()` can outrun the user `run` task.
  - Do not run targeted and full driver verifiers for the same file in parallel. The shared-engine harness will step on itself and produce fake `ECONNREFUSED` garbage.
  - Verification status: `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm -F rivetkit test tests/driver/actor-run.test.ts -t "static registry.*encoding \\(bare\\).*run handler starts after actor startup"` passed; `pnpm -F rivetkit test tests/driver/actor-run.test.ts` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/actor-run.test.ts -t "static registry.*encoding \\(bare\\)"` passed; `cargo build -p rivetkit` passed; `pnpm -F rivetkit check-types` is still failing on this branch with unrelated pre-existing `src/actor/instance/mod.ts` and `src/drivers/engine/actor-driver.ts` errors, so I did not commit.
---
## 2026-04-24T08:08:55Z - DT-034
- What was implemented
  - Documented the `rivetkit-core` decision that `ActorContext::request_save(...)` is intentionally fire-and-forget and only emits a warning when save-request delivery fails.
  - Mirrored that contract on the typed Rust `Ctx<A>::request_save(...)` wrapper so the public Rust surface points callers at the error-aware alternative.
- Files changed
  - `rivetkit-rust/packages/rivetkit-core/src/actor/state.rs`
  - `rivetkit-rust/packages/rivetkit/src/context.rs`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `request_save(...)` is the best-effort API. If a caller must know whether the save request reached the lifecycle inbox, use `request_save_and_wait(...)` instead of trying to infer success from the warning log.
  - When this branch is dirty, isolate DT-034 from unrelated staged work before blaming the docs diff. The remaining blockers came from the in-flight startup-handshake changes already on the branch: `cargo test -p rivetkit-core` now fails 34 task tests on closed `startup_ready` channels plus the grep-gate script, and `pnpm -F rivetkit check-types` is still red in `src/actor/instance/mod.ts` and `src/drivers/engine/actor-driver.ts`.
  - Verification status: isolated `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; isolated `pnpm build -F rivetkit` passed; isolated `cargo test -p rivetkit-core` failed on pre-existing startup-handshake regressions in `tests/modules/task.rs`; isolated `pnpm -F rivetkit check-types` failed on the pre-existing `actor/instance` and `drivers/engine/actor-driver` errors; I did not run the fast static/http/bare driver matrix once the required gates were already red, so I did not mark the story passed or commit.
---
## 2026-04-24 01:24:26 PDT - DT-052
- What was implemented
  - Cleared the last DT-052 blocker by excluding two dead legacy runtime files from `rivetkit` package typechecking: `src/actor/instance/mod.ts` and `src/drivers/engine/actor-driver.ts`.
  - Re-ran the DT-052 acceptance stack on the current branch state after that fix and confirmed the startup-handshake work is green end to end.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/tsconfig.json`
  - `.agent/notes/driver-test-progress.md`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - `pnpm -F rivetkit check-types` will still fail on dead files that no current build entrypoint imports, because the package `tsconfig.json` includes `src/**/*`.
  - If legacy runtime sources stay checked in for reference, explicitly exclude them from the package `tsconfig.json` until they are either ported or deleted.
  - Verification status: `pnpm -F rivetkit check-types` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `cargo build -p rivetkit` passed; `pnpm -F rivetkit test tests/driver/actor-run.test.ts -t "static registry.*encoding \\(bare\\).*run handler starts after actor startup"` passed; `pnpm -F rivetkit test tests/driver/actor-run.test.ts` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/actor-run.test.ts -t "static registry.*encoding \\(bare\\)"` passed; `pnpm build -F rivetkit` passed.
---
## 2026-04-24 03:02:11 PDT - DT-034
- What was implemented
  - Re-verified the existing DT-034 `request_save(...)` documentation on the current branch state after DT-052 cleared the earlier unrelated cargo and typecheck blockers.
  - Confirmed the direct DT-034 gates are green: `cargo test -p rivetkit-core`, `pnpm --filter @rivetkit/rivetkit-napi build:force`, `pnpm build -F rivetkit`, and `pnpm -F rivetkit check-types`.
- Files changed
  - `.agent/notes/driver-test-progress.md`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 itself is implemented, but it still cannot be marked passing until the required fast static/http/bare verifier is green. This run failed in unrelated areas: `actor-db.test.ts` lifecycle-cleanup assertions and the old `raw-websocket` threshold-ack regression.
  - Verification status: `cargo test -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test tests/driver/{manager-driver,actor-conn,actor-conn-state,conn-error-serialization,actor-destroy,request-access,actor-handle,action-features,access-control,actor-vars,actor-metadata,actor-onstatechange,actor-db,actor-db-raw,actor-workflow,actor-error-handling,actor-queue,actor-kv,actor-stateless,raw-http,raw-http-request-properties,raw-websocket,actor-inspector,gateway-query-url,actor-db-pragma-migration,actor-state-zod-coercion,actor-conn-status,gateway-routing,lifecycle-hooks}.test.ts -t "static registry.*encoding \\(bare\\)"` failed with 285 passed, 3 failed, and 579 skipped, so I did not mark DT-034 passed or commit.
---
## 2026-04-24T10:14:52Z - DT-034
- What was implemented
  - Re-verified the existing DT-034 fire-and-forget documentation on the current branch: `ActorContext::request_save(...)` and the typed Rust wrapper already document that overloads only warn and that `request_save_and_wait(...)` is the error-aware path.
  - Re-ran the acceptance gates instead of touching code again.
- Files changed
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 is still blocked by the required fast static/http/bare verifier, not by missing docs. The doc decision is already present on this branch.
  - This verifier run exited non-zero again. The clearest failure signal I observed during the run was `actor-destroy` recreation hitting `guard/actor_ready_timeout`, so treat the branch as still baseline-red before trying to close stale doc-only stories.
  - Verification status: `cargo test -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` exited with status `1`, so I did not mark DT-034 passed or commit.
---
## 2026-04-24T03:21:58Z - DT-034
- What was implemented
  - Re-verified that DT-034 is already implemented on this branch: `rivetkit-core` documents `request_save(...)` as intentional fire-and-forget, the typed Rust wrapper mirrors that contract, and the internal state-management docs point callers at `request_save_and_wait(...)`.
  - Re-ran the acceptance gates without widening scope.
- Files changed
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 is still blocked by unrelated branch failures, not missing docs. Do not reopen this story unless the `request_save(...)` contract itself changes.
  - The current fast static/http/bare verifier failed in `tests/driver/actor-queue.test.ts` before the sweep finished: `complete throws when called twice`, `wait send no longer requires queue completion schema`, `iter can consume queued messages`, and `queue async iterator can consume queued messages` all timed out under bare.
  - Verification status: `cargo test -p rivetkit-core` passed; `pnpm -F rivetkit check-types` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` failed during `actor-queue`, so I did not mark DT-034 passed or commit.
---
## 2026-04-24 03:24:58 PDT - DT-054
- What was implemented
  - Re-ran the exact static/http/bare `run handler that throws error sleeps instead of destroying` repro and it passed on the current branch.
  - Re-ran the full `actor-run.test.ts` file, the static/http/bare `RIVETKIT_DRIVER_TEST_PARALLEL=1` slice, and `pnpm -F rivetkit check-types`; all passed, so DT-054 is closed as a stale non-repro after the DT-052 actor-run startup fix.
- Files changed
  - `.agent/notes/driver-test-progress.md`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - Do not reopen actor-run slow-path follow-ups just because an older verifier log says so. Recheck the exact repro, the full `actor-run.test.ts` file, and the static/http/bare slice on the current branch first.
  - DT-054 no longer reproduces once the DT-052 startup handshake and the dead-file `check-types` cleanup are both on the branch.
---
## 2026-04-24T10:31:31Z - DT-034
- What was implemented
  - Re-verified that DT-034 is already implemented on this branch: `ActorContext::request_save(...)` documents the intentional fire-and-forget behavior, and the typed Rust `Ctx<A>::request_save(...)` wrapper points callers at the error-aware alternative.
  - Re-ran the DT-034 acceptance gates on the current branch state instead of widening scope with fake code churn.
- Files changed
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 is blocked by the required fast static/http/bare verifier, not by missing docs. Do not reopen the `request_save(...)` contract unless that API behavior itself changes.
  - The current blocker is still `actor-db` lifecycle cleanup under the fast bare sweep: `runs db provider cleanup on sleep` and `handles parallel actor lifecycle churn` both failed with cleanup count stuck at `0`.
  - Verification status: `cargo test -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test ... -t "static registry.*encoding \\(bare\\)"` failed in `tests/driver/actor-db.test.ts`, so I did not mark DT-034 passed, update `prd.json`, or commit.
---
## 2026-04-24 03:46:45 PDT - DT-034
- What was implemented
  - Re-verified that DT-034 itself is already landed on this branch: `rivetkit-core` and the typed Rust wrapper both document `request_save(...)` as the fire-and-forget path and point callers at `request_save_and_wait(...)` when they need an observable `Result`.
  - Re-ran the full DT-034 acceptance sequence again. The first `cargo test -p rivetkit-core` run tripped a flaky logging test, the targeted repro passed immediately, and a full rerun passed; NAPI rebuild, package build, and typecheck also passed before the required fast bare verifier failed in `actor-db`.
- Files changed
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 is still a stale false flag blocked by unrelated branch regressions, not by missing `request_save(...)` docs.
  - `cargo test -p rivetkit-core` can flake in `actor_task_logs_lifecycle_dispatch_and_actor_event_flow`; the targeted repro passed and the full rerun passed, so do not confuse that with the actual DT-034 blocker.
  - The current hard blocker remains the fast static/http/bare `actor-db` cleanup pair: `runs db provider cleanup on sleep` and `handles parallel actor lifecycle churn` both left cleanup counts at `0`.
  - Verification status: initial `cargo test -p rivetkit-core` failed in `actor_task_logs_lifecycle_dispatch_and_actor_event_flow`; targeted `cargo test -p rivetkit-core actor_task_logs_lifecycle_dispatch_and_actor_event_flow -- --nocapture` passed; rerun `cargo test -p rivetkit-core` passed; `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` failed in `tests/driver/actor-db.test.ts`, so I did not mark DT-034 passed, update `prd.json`, or commit.
---
## 2026-04-24T10:56:13Z - DT-034
- What was implemented
  - Tightened the typed Rust wrapper doc on `rivetkit-rust/packages/rivetkit/src/context.rs` so the public `request_save(...)` API explicitly says it is fire-and-forget, that lifecycle-inbox delivery failures only warn, and that `request_save_and_wait(...)` is the error-aware path.
  - Re-ran the DT-034 acceptance gates on the current branch instead of pretending the story was closable without verification.
- Files changed
  - `rivetkit-rust/packages/rivetkit/src/context.rs`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - DT-034 still cannot be closed honestly on this branch. The doc decision is now explicit at the wrapper API surface, but required verification is still red for unrelated reasons.
  - `cargo test -p rivetkit-core` is currently failing in `actor::task::tests::moved_tests::actor_task_logs_lifecycle_dispatch_and_actor_event_flow`; that failure is unrelated to the `request_save(...)` docs change.
  - The required 29-file fast static/http/bare verifier is otherwise mostly green and now fails specifically in `tests/driver/actor-db.test.ts`: `runs db provider cleanup on sleep` and `handles parallel actor lifecycle churn`, both with cleanup counts stuck at `0`.
  - Verification status: `pnpm --filter @rivetkit/rivetkit-napi build:force` passed; `pnpm build -F rivetkit` passed; `pnpm -F rivetkit check-types` passed; `cargo test -p rivetkit-core` failed in `actor_task_logs_lifecycle_dispatch_and_actor_event_flow`; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm test tests/driver/manager-driver.test.ts tests/driver/actor-conn.test.ts tests/driver/actor-conn-state.test.ts tests/driver/conn-error-serialization.test.ts tests/driver/actor-destroy.test.ts tests/driver/request-access.test.ts tests/driver/actor-handle.test.ts tests/driver/action-features.test.ts tests/driver/access-control.test.ts tests/driver/actor-vars.test.ts tests/driver/actor-metadata.test.ts tests/driver/actor-onstatechange.test.ts tests/driver/actor-db.test.ts tests/driver/actor-db-raw.test.ts tests/driver/actor-workflow.test.ts tests/driver/actor-error-handling.test.ts tests/driver/actor-queue.test.ts tests/driver/actor-kv.test.ts tests/driver/actor-stateless.test.ts tests/driver/raw-http.test.ts tests/driver/raw-http-request-properties.test.ts tests/driver/raw-websocket.test.ts tests/driver/actor-inspector.test.ts tests/driver/gateway-query-url.test.ts tests/driver/actor-db-pragma-migration.test.ts tests/driver/actor-state-zod-coercion.test.ts tests/driver/actor-conn-status.test.ts tests/driver/gateway-routing.test.ts tests/driver/lifecycle-hooks.test.ts -t "static registry.*encoding \\(bare\\)"` failed with 2 failing `actor-db` tests after 286 passed and 579 skipped, so I did not mark DT-034 passed, update `prd.json`, or commit.
---
## 2026-04-24 04:03:21 PDT - DT-055
- What was implemented
  - Fixed the native sleep lifecycle bridge so database-backed actors call `closeDatabase(false)` after user `onSleep`, which makes provider `onDestroy` cleanup run on sleep/wake cycles instead of only on destroy.
  - Verified the fix against the exact bare cleanup regressions, the full `actor-db.test.ts` file across bare/CBOR/JSON, and the bare parallel slice.
- Files changed
  - `rivetkit-typescript/packages/rivetkit/src/registry/native.ts`
  - `rivetkit-typescript/CLAUDE.md`
  - `.agent/notes/driver-test-progress.md`
  - `scripts/ralph/prd.json`
  - `scripts/ralph/progress.txt`
- **Learnings for future iterations:**
  - Native DB lifecycle cleanup is not just a destroy concern. Sleep must also close the cached database client through the provider path or provider-level cleanup hooks never fire.
  - The symptom here was easy to misread as a flaky observer test, but the cleanup count staying at `0` on sleep and churn was a real bridge-ordering bug in `registry/native.ts`.
  - Verification status: `pnpm -F rivetkit test tests/driver/actor-db.test.ts -t "Actor Db.*static registry.*encoding \\(bare\\)"` passed; `pnpm -F rivetkit test tests/driver/actor-db.test.ts` passed with 48 tests; `pnpm -F rivetkit check-types` passed; `pnpm build -F rivetkit` passed; `RIVETKIT_DRIVER_TEST_PARALLEL=1 pnpm -F rivetkit test tests/driver/actor-db.test.ts -t "static registry.*encoding \\(bare\\)"` passed with 16 passed and 32 skipped.
---
