Skip to content

feat(state): #98 v1 kernel contract, memory driver, conformance suite (PR-1) - #142

Merged
ScriptedAlchemy merged 1 commit into
mainfrom
wave2/98-state-kernel
Sep 1, 2026
Merged

feat(state): #98 v1 kernel contract, memory driver, conformance suite (PR-1)#142
ScriptedAlchemy merged 1 commit into
mainfrom
wave2/98-state-kernel

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Wave 2 Lane B, PR 1 of 2 for the #98 v1 state kernel (plan #107 §6, G3 recorded).

  • Driver-neutral contract behind the new @agent-bundle/runtime/state subpath: defineState({ schema, initial, events, reduce }) (zod schemas, typed event union, pure deterministic reducer), typed AgentStateError codes, monotonic revisions, exact-revision snapshot reads, idempotency-key replay (duplicate key returns the committed result; conflicting payload under the same key is a typed idempotency-conflict), compare-and-swap via expectedRevision, explicit versioned migrations that rebase history, deterministic resets, and polling change cursors — nothing stronger promised.
  • Explicit lifetime taxonomy AgentStateLifetime = 'request' | 'process' | 'workspace-durable' | 'external' with exhaustive never-default switches; volatile vs durable is a typed property, never inferred from an MCP process.
  • In-memory driver for the request and process lifetimes — labeled test-only as a durability stand-in, durable: false structurally, refuses durable lifetimes.
  • Request-bound handle createAgentStateHandle(store, { signal }) fills the reserved state slot feat: framework request store and agent() (#95) #113 shipped on AgentRequestContext: (await agent()).state.dispatch(event, payload, { idempotencyKey }). Slot type goes undefinedAgentStateHandle | undefined; wiring stays additive.
  • Conformance suite (stateDriverConformanceCases, node:assert-based, runner-agnostic): 18 shared cases every driver must pass; runs here against the memory driver. PR-2 runs the same suite against the node:sqlite workspace-durable driver.
  • Packaging: ./state is its own rslib entry + subpath export; dist/index.js / dist/plugin.js contain none of the kernel (verified against the built tree; PR-2 adds the packaged-tree test alongside the sqlite entry). README + docs/framework-mode.md persistence statements flipped in-PR.

PR-2 (same branch family) ships the node:sqlite workspace-durable driver (G3), cross-process proofs, and the examples/rsc-agent-runtime migration that retires the 781-line JSONL kernel.

Test plan

  • pnpm --filter @agent-bundle/runtime test — 73 passed (17 conformance cases on memory, kernel/migration/handle units; 1 durable-only case skipped by design)
  • pnpm --filter @agent-bundle/runtime typecheck + root pnpm typecheck — clean
  • pnpm lint — clean
  • Built-tree check: dist/state.js smoke-tested; root entries free of state/kernel identifiers

Refs #98, #107.

…formance suite (#98 v1, PR-1)

defineState({ schema, initial, events, reduce }) with the explicit lifetime
taxonomy (request | process | workspace-durable | external), typed
AgentStateError codes, monotonic revisions, exact-revision reads,
idempotency-key replay/conflict, CAS, explicit versioned migrations, and
polling change cursors. Ships behind the new ./state subpath so stateless
artifacts include none of it; the volatile in-memory driver (never durable)
fills the request/process lifetimes; createAgentStateHandle fills the
reserved `state` slot on AgentRequestContext; the exported conformance
suite is the bar every driver, including external ones, must pass.
@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a9b787e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@agent-bundle/runtime Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy merged commit d024e81 into main Sep 1, 2026
9 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T07:04:09.394047Z a9b787e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9b787e1ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/rsc-runtime/src/state/memory-driver.ts
Comment thread packages/rsc-runtime/src/state/memory-driver.ts
Comment thread packages/rsc-runtime/src/state/json.ts
Comment thread packages/rsc-runtime/README.md
@ScriptedAlchemy
ScriptedAlchemy deleted the wave2/98-state-kernel branch September 1, 2026 07:49
ScriptedAlchemy added a commit that referenced this pull request Sep 1, 2026
…head verification, replay across migrations (#171)

Codex review follow-ups on the state kernel and drivers, re-verified
against the Effect-native internals from #154:

- Both drivers consult the idempotency key before running the reducer
  (#142/#149 P1): a committed key replays its stored result even when the
  reducer would now fail against the current head. Payload validation and
  canonicalization moved ahead of the key lookup; the reducer runs only on
  the append path.
- Committed results replay across migrations (#142 P1): every journal
  record stores its post-commit state (event rows too, in the sqlite
  driver's existing nullable column), and migrations run the same chain
  over the stored results, so replay no longer depends on exact-revision
  history that migrations rebase. Legacy event rows without a stored state
  fall back to journal replay.
- The sqlite driver verifies storage on open (#149 P1): journal continuity
  via expectConsistentJournal (a deleted intermediate row fails closed) and
  the materialized head against journal replay (a schema-valid hand-edited
  head fails closed); with a pending migration the head is checked against
  the last stored post-commit state instead.
- sanitizedFileName hashes the complete definition id (sha-256) instead of
  hex-encoding its first six bytes (#149 P2), so ids sharing a sanitized
  prefix get isolated database files.
- isJsonSafe rejects sparse arrays (#142 P2): holes no longer canonicalize
  like dense arrays under permissive schemas.

The conformance suite pins the corrected semantics for both drivers:
replay-before-reduce, replay across migrations, and prefix-colliding id
isolation; sqlite corruption tests cover the two new fail-closed opens.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant