feat(agent-harness): persist authoritative state in SQLite - #5675
Open
iscekic wants to merge 1 commit into
Open
Conversation
This was referenced Aug 28, 2026
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (16 files)
Reviewed by grok-4.6 · Input: 281.6K · Output: 28.4K · Cached: 715.4K Review guidance: REVIEW.md from base branch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No new behavior — this change prepares data storage without changing how people use the product.
Summary
The new
conversation,messages,commands,runs,checkpoints,calls,interactions,grants,attempts,clientActions,events,snapshots, andprojectionWorktables persist authoritative conversation state.ConversationStore.transitioncommits state, increasing event sequences, andCommandReplyresults atomically; matching command retries replay the original reply, while changed inputs returncommand_conflict.bindExistingConversationrequires authenticated PostgreSQL identity and rejects ownership or context changes; thepermission_modestorage default isask.Files
services/agent-harness/src/db/sqlite-schema.ts— Source, added (+171/-0 lines). Defines 13 tables with singleton checks, reference constraints, history and queue indexes, and unique positions, active slots, and generations. Stores full message parts and command replies separately from replay events. Persistspermission_revision,sequence,compacted_through,active_run_id,legacy_cursor, runstep, and record revisions. Keepsdefinition_versions,input_digest,policy, andintentwith execution records; retainsoutcomeandprovider_referencefor attempts. Tracks projection work throughmessage_id,due_at,acknowledged_at, andrevision.transitionWithWakeserializes preparation and commits throughblockConcurrencyWhile, then prearms the earliest durable alarm before the synchronous transaction.AlarmStoragefailures raise retryableStoreError('storage_unavailable')without committing;wakeAt: nullis reserved for wait-only changes.Runnable run events and active-run release with queued work require a wake, including terminal transitions and callback writes; commit callbacks cannot return promises.
Files
services/agent-harness/src/db/wake.ts— Source, added (+54/-0 lines). Adds injectable alarm storage, synchronous preparation and commit, safe-integer deadlines, and earliest-alarm preservation. CallstransactionSyncimmediately after alarm scheduling, with no intervening asynchronous operation. Rejects thenable commit results and rethrows expected errors outside the concurrency gate to avoid resetting the object. Keeps an armed alarm if the commit fails.applyEventandcompareAndSetActiveRunpreserve identity, permission revisions, queue order, one active run, and final interaction resolutions.CheckpointSchema,insertCall,insertGrant, andinsertAttemptretain validated dispatch inputs and intent; partial or failed checkpoints cannot authorize execution.compareAndSetCallrejects stale revisions, settled-call changes, and execution without durable intent; waiting runs keep the active slot and block later runs.Files
services/agent-harness/src/db/records.ts— Source, added (+318/-0 lines). AddsStoreDatabase, record validation,pageLimitfrom 1 to 200, and compare-and-set helpers. Materializes conversation, message, run, interaction, and client-action events within the caller's transaction. Preserves conversation ownership and context, message identity, and run identity; changed permissions require the next revision. New runs start queued; terminal run states and resolved interactions cannot change. Call insertion requires a complete checkpoint for the same run, a matching definition version, and the conversation context. Grants must match the call, owner, conversation, client, digest, and definition version; attempts must match the grant generation. Persists the call, digest, policy, and grant before execution. Client attempts require a grant; call updates require the current revision, and executing calls require a stored attempt.ConversationStoreadds atomic snapshots, paged history, bounded replay, and legacy import;pendingProjectionsandacknowledgeProjectionuse due times and revisions for acknowledgments.eventsAfterlimits replay to 200 events and 256 kibibytes (KiB); expired cursors or an oversized first legacy delta returncursor_expired.compactEventsretains command results, canonical messages, and unresolved work;importLegacyaccepts valid large text, deduplicates message identifiers, and advances the legacy cursor.Files
services/agent-harness/src/db/store.ts— Source, added (+401/-0 lines). AddsopenStore, conversation binding, command lookup, and atomic transitions with monotonically increasing event sequences. Requires matching command and reply identifiers; matching retries return stored replies without another write. Rejects runnable events without a wake and rejects active-run release when queued work remains without a wake, including callback writes. Reads snapshots and their event cursors together; includes 50 recent messages, the active run, queued runs, unresolved interactions, and pending client actions. Snapshot reads fail rather than hide any queue, interaction, or action list longer than 200. Orders history by creation time and identifier; bounds history, queue, call, event, and projection pages to 200 records. Reads events strictly after the cursor, checks the serialized response size, and rejects oversized non-legacy events. Old or future cursors expire; an oversized legacy event requires snapshot recovery when it cannot fit first in a replay page. Compaction stores a snapshot before deleting bounded event batches; it retains original replies, canonical message parts, checkpoints, and unresolved records. Legacy import deduplicates message identifiers and advances the ingestion cursor atomically.pendingProjectionsreturns due, unacknowledged work;acknowledgeProjectioncompares and increments the revision, so stale or repeated acknowledgments return false.openStoreruns pending Drizzle migrations before serving operations; callers must initialize it within the Durable Object constructor's concurrency gate.The SQLite migration configuration uses the
durable-sqlitedriver, and themigrationsdeclaration derives its type from the maintainedmigratecontract.Two tracked migrations create the authoritative tables and projection work; each instance upgrades on access, without a centralized migration command.
Files
services/agent-harness/drizzle.config.ts— Source, added (+8/-0 lines). Configures SQLite schema generation with the Durable Object driver and tracked migration output.services/agent-harness/drizzle/migrations.d.ts— Source, added (+4/-0 lines). Types the generated migration bundle withParameters<typeof migrate>[1].services/agent-harness/drizzle/0000_authoritative_store.sql— Generated, added (+116/-0 lines). Adds the authoritative-store migration.services/agent-harness/drizzle/0001_projection_work.sql— Generated, added (+10/-0 lines). Adds the projection-work migration.services/agent-harness/drizzle/meta/0000_snapshot.json— Generated, added (+758/-0 lines). Adds the initial schema snapshot.services/agent-harness/drizzle/meta/0001_snapshot.json— Generated, added (+821/-0 lines). Adds the next schema snapshot.services/agent-harness/drizzle/meta/_journal.json— Generated, added (+20/-0 lines). Adds the migration journal.services/agent-harness/drizzle/migrations.js— Generated, added (+11/-0 lines). Adds the migration loader.The
STOREandOLD_STOREbindings run storage tests against real SQLite Durable Objects, including empty and older schemas.The test harness replaces conditional Wrangler discovery with a test-only entrypoint and raw SQL imports, so production bindings and environment files stay unloaded.
remoteBindingsremains disabled; this configuration validates storage without providing a production Worker or an alarm handler.Files
services/agent-harness/vitest.config.ts— Source, modified (+11/-6 lines). SelectsTestStoreandOldTestStorethroughSTOREandOLD_STORE; enables SQLite and raw SQL imports without loading deployment configuration.services/agent-harness/src/db/store.test.ts— Test, added (+1370/-0 lines). Adds real Worker storage coverage, including large legacy text and wake retention after terminal transitions.services/agent-harness/src/db/test-worker.ts— Test, added (+64/-0 lines). Adds the test-only Worker and storage fixtures for current and older schemas.services/agent-harness/src/db/test-env.d.ts— Test, added (+1/-0 line). Adds the test environment declaration.Tests: 3 files added —
store.test.ts(+1370 lines),test-worker.ts(+64 lines), andtest-env.d.ts(+1 line).Generated: 6 files added —
0000_authoritative_store.sql(+116 lines),0001_projection_work.sql(+10 lines),0000_snapshot.json(+758 lines),0001_snapshot.json(+821 lines),_journal.json(+20 lines), andmigrations.js(+11 lines).Verification
Manual runtime verification did not run because this level adds storage without production Worker composition or an alarm handler.
Visual Changes
Visual Changes: N/A
Reviewer Notes
Human steps
Scope
Kilo-Org/cloud./Users/igor/Projects/.worktrees/shared-agent-harness-3bb0.shared-agent-harness-3bb0-s9toshared-agent-harness-3bb0-s10.Notes
No manual runtime verification ran for this level. Full backend, browser, iOS, and Android verification remains required on the completed stack tip.
The focused SQLite suite passed 39 real Worker tests. Production Worker composition and the alarm handler remain later stack levels.
Stacked PRs — merge bottom to top. Each level shows only its own diff.
Runtime verification (E2E, user advocacy, simplify) runs on the tip PR over every level.
Every level keeps its own checks, its own bot review, and its own threads; each one is answered on its own PR.
Each level is its own deliverable: it builds and passes its own checks alone.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.
shared-agent-harness-3bb0— chore(agent-harness): register workspaces and enforce CI boundaries #5632shared-agent-harness-3bb0-s2— feat(agent-harness): define portable domain and snapshots #5637shared-agent-harness-3bb0-s3— feat(agent-harness): define commands tools and permission policy #5639shared-agent-harness-3bb0-s4— feat(agent-harness): share client state and cursor recovery #5643shared-agent-harness-3bb0-s5— feat(agent-harness): persist command intents and execution receipts #5647shared-agent-harness-3bb0-s6— feat(db): add harness ingress grants and retirement fences #5655shared-agent-harness-3bb0-s7— feat(agent-harness): deliver legacy history and project durable text #5659shared-agent-harness-3bb0-s8— feat(agent-harness): authorize durable grants and registered clients #5662shared-agent-harness-3bb0-s9— feat(agent-harness): fence retirement and retry payload cleanup #5667shared-agent-harness-3bb0-s10— feat(agent-harness): persist authoritative state in SQLite #5675 ← this PRshared-agent-harness-3bb0-s11— feat(agent-harness): admit durable runs and revisioned commands #5678 (tip)