Skip to content

feat(storage): add sqlite durable fencing - #560

Merged
delete-cloud merged 1 commit into
mainfrom
feat/sqlite-transactional-fencing
Jun 5, 2026
Merged

delete-cloud merged 1 commit into
mainfrom
feat/sqlite-transactional-fencing

Conversation

@delete-cloud

@delete-cloud delete-cloud commented Jun 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add local SQLite durable store facade for transactional owner fencing across session, tape, checkpoint, and runtime writes
  • wire fenced SQLite wrappers into SessionManager/local CLI/HTTP bundle defaults
  • make local CLI ownership process-unique and renew leases for run/resume/REPL paths
  • add regression coverage for stale owners, cross-session writes, rollback ordering, equivalent bundle paths, and checkpoint restore atomicity

Verification

  • uv run pytest tests/coding_agent/test_sqlite_local_durable_fencing.py tests/ui/test_session_owner_store.py tests/ui/test_session_manager_owner_checks.py tests/ui/test_session_manager_public_api.py tests/cli/test_entrypoint_contract.py tests/cli/test_local_runtime.py tests/cli/test_repl.py tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_enables_owner_store_for_local_sqlite_bundle tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_enables_owner_store_for_equivalent_local_sqlite_bundle_paths tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_does_not_enable_owner_store_for_non_bundle_storage -q => 211 passed, 50 warnings
  • uv run ruff check <touched files>
  • uv run ruff format --check <touched files>
  • git diff --check

Review

  • Local subagent blocker review completed after fixes: no P1/P2 blocker, ready for PR lifecycle.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added session ownership and lease renewal management for improved session control
    • Implemented ownership-based access fencing to prevent concurrent modification conflicts
    • Introduced durable local session state persistence with atomic guarantees
  • Tests

    • Expanded test coverage for session ownership, durability, and conflict resolution

Implement ADR-0068 PR3 local SQLite transactional fencing for session, tape, checkpoint, and runtime writes.

Verification:

- uv run pytest tests/coding_agent/test_sqlite_local_durable_fencing.py tests/ui/test_session_owner_store.py tests/ui/test_session_manager_owner_checks.py tests/ui/test_session_manager_public_api.py tests/cli/test_entrypoint_contract.py tests/cli/test_local_runtime.py tests/cli/test_repl.py tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_enables_owner_store_for_local_sqlite_bundle tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_enables_owner_store_for_equivalent_local_sqlite_bundle_paths tests/ui/test_http_server.py::TestSessionCreation::test_build_session_manager_does_not_enable_owner_store_for_non_bundle_storage -q

- uv run ruff check <touched files>; uv run ruff format --check <touched files>; git diff --check
@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements SQLite-backed durable session ownership with epoch-based fencing and async lease renewal. It enables local-only deployments to prevent conflicting modifications through authority-scoped mutations, epoch-advancing ownership takeovers, and lease-expiry-based reclamation. The session manager routes tape, checkpoint, and runtime persistence through a fenced durability layer when local SQLite is detected, enforcing ownership at transaction boundaries. CLI and REPL session lifecycle becomes async to support ownership acquisition and lease renewal.

Changes

Durable session ownership with SQLite fencing

Layer / File(s) Summary
Owner authority contract and database methods
coding-agent/src/coding_agent/server/stores/session_owner_store.py
Introduces OwnerAuthority dataclass with session_id, owner_id, epoch, and fencing_token property derived from epoch. Adds acquire_authority and renew_authority async methods to SQLiteSessionOwnerStore for atomic ownership acquisition with epoch increment and renewal with epoch matching.
Local SQLite path resolution and bundle detection
coding-agent/src/coding_agent/local_storage.py, coding-agent/src/coding_agent/server/http_server.py
Adds normalize_storage_path to expand home dirs to absolute paths. Updates local_sqlite_path_from_storage_config to collect and verify explicit backend *_path fields match a single SQLite file. Introduces _storage_uses_local_sqlite_bundle in HTTP server to detect when all backends use SQLite at the same resolved path.
SQLiteLocalDurableStore durability layer
coding-agent/src/coding_agent/local_durable_store.py (init, tables, session, tape, runs, events, interactions, checkpoints, helpers)
Implements transaction-scoped ownership enforcement via BEGIN IMMEDIATE and _assert_authority epoch/lease validation. Persists session payloads, tape entries (with sequence), agent runs (create/update with conflict upserts), runtime events (insert-or-return), message snapshots, agent interactions (insert/resolve), executor-run claims, and checkpoint snapshots. Includes _bind_tape, _assert_tape_belongs_to_session, _assert_run_belongs_to_session to prevent cross-session mutations.
Fenced wrapper stores
coding-agent/src/coding_agent/local_durable_store.py (FencedSQLiteTapeStore, FencedSQLiteCheckpointStore, FencedSQLiteRuntimeStore)
Routes save/truncate/delete mutations through SQLiteLocalDurableStore with session-id resolution from tape/checkpoint/run ids, while delegating reads/listing/search to underlying SQLite stores. Raises ownership conflict errors when ids are not bound to a session.
Checkpoint restore with durable state callback
coding-agent/src/coding_agent/runs/checkpoint_restore.py, coding-agent/src/coding_agent/runs/runtime_checkpoint_restore.py
Introduces RestoreDurableCheckpointState callable type for async durable restore hooks. Adds optional restore_durable_state field to CheckpointRestoreService and RuntimeCheckpointRestoreService. When set, restore invokes callback after runtime attachment and returns early; otherwise continues with tape truncation and session persistence.
SessionManager local durable integration and authority caching
coding-agent/src/coding_agent/server/session_manager.py (__init__, _create_local_durable_store, fenced store setup)
Initializes _local_durable_store and _owner_authorities cache. When durable store enabled, swaps in FencedSQLiteTapeStore, FencedSQLiteCheckpointStore, FencedSQLiteRuntimeStore guarded by authority resolvers. Wires checkpoint restore callback. _create_local_durable_store returns store only when owner_store supports acquire_authority, all backends are SQLite, and paths match.
SessionManager authority-based ownership validation
coding-agent/src/coding_agent/server/session_manager.py (_assert_owner, _owner_authority_for_session, _acquire_owner_for_session, _holds_owner_lease, _holds_active_owner_lease)
Refactors ownership checks to validate cached OwnerAuthority (epoch, id, lease expiry) in preference to legacy fencing tokens. _acquire_owner_for_session prefers acquire_authority when available, caching result. Ownership validation now authority-centric with stale-owner rejection.
SessionManager lease acquire/renew/release/backfill
coding-agent/src/coding_agent/server/session_manager.py (release_owned_sessions, _release_owner_lease_for_session, renew_owner_leases, backfill_owner_leases)
Routes lease operations through OwnerAuthority when available. release_owned_sessions uses cached authority epoch for fencing-token selection and purges cache on success. renew_owner_leases prefers renew_authority when supported. backfill_owner_leases prefers acquire_authority for reacquisition.
SessionManager fenced persistence, deletion, and rollback
coding-agent/src/coding_agent/server/session_manager.py (_persist_session_async, _remove_session_async_no_lock, _rollback_partially_created_session, create_session, _persist_session, register_session, remove_session, clear_sessions)
Routes _persist_session_async to _local_durable_store.save_session(authority, payload) when fenced enabled. Routes _remove_session_async_no_lock to durable delete. Adds _rollback_partially_created_session for durable deletion + lease release on create failures. Raises RuntimeError for synchronous operations when fenced durability active. Reorders create_session to acquire owner before persisting.
HTTP server local SQLite bundle detection and owner store setup
coding-agent/src/coding_agent/server/http_server.py (_build_session_manager, _storage_uses_local_sqlite_bundle)
In _build_session_manager, computes uses_local_sqlite_bundle and conditionally configures SQLiteSessionOwnerStore with UUID-based owner_id and fencing token. Otherwise omits ownership setup.
CLI and REPL async session lifecycle with ownership and renewal
coding-agent/src/coding_agent/cli/local_runtime.py, coding-agent/src/coding_agent/cli/main.py, coding-agent/src/coding_agent/cli/repl.py
Makes LocalCliSessionManager.attach_runtime async. ServerBackedLocalCliSessionManager.__post_init__ derives default owner_store, owner_id (uuid4().hex), and fencing_token from local SQLite path. Makes attach_runtime async with _persist_session_async. CLI resume/one-shot now acquires owner lock and starts lease renewal before session operations. REPL awaits attach_runtime, starts renewal, and closes session manager on shutdown.
Comprehensive SQLite fencing and ownership tests
coding-agent/tests/coding_agent/test_sqlite_local_durable_fencing.py
16 tests validating: SQLiteSessionOwnerStore authority epochs (renewal preserves, takeover/reacquire advance); SessionManager default SQLite bundle behavior (protected session save, fenced deletion, rollback order, sync mutation rejection, fencing on tape/event/claim/checkpoint); SQLiteLocalDurableStore consistency (rejects stale-epoch writes, payload id mismatch, cross-session tape/event/checkpoint writes, atomic restore).
Updated integration tests
coding-agent/tests/cli/test_entrypoint_contract.py, coding-agent/tests/cli/test_local_runtime.py, coding-agent/tests/cli/test_repl.py, coding-agent/tests/ui/test_http_server.py, coding-agent/tests/ui/test_session_manager_public_api.py
CLI entrypoint contract mocks add start_owner_lease_renewal and acquire_session_owner. Local runtime test converts attach_runtime to async, adds two async tests for default renewal and process-unique owner IDs. REPL tests add async attach_runtime and start_owner_lease_renewal with renewal flag. HTTP server tests add two positive tests for local SQLite bundle detection and replace PG test with non-bundle scenario. Session manager public API test adds equivalent-path bundle test.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • delete-cloud/Coding-Agent-Loop#556: Overlaps directly in CLI session ownership/lease renewal and async persistence paths; both implement SQLite owner store integration in local_runtime.py.
  • delete-cloud/Coding-Agent-Loop#407: Adds external-worker claim/heartbeat flows that depend on the fenced local-SQLite durability and async run claiming this PR introduces.
  • delete-cloud/Coding-Agent-Loop#79: Implements same "phase 2" session ownership/lease fencing substrate (owner store + SessionOwnershipConflictError validation) but targets PostgreSQL/UI path; this PR targets local SQLite path.

🐰 A rabbit pauses to nibble on what once was sync,
Now thumping async hearts in SQLite's vault,
Epochs march like seasons, ownership springs forth,
Where fences guard mutations, no conflicts insurmount.
Persisting leases, restoring checkpoints whole—
One durable store to rule them all, I suppose! 🌙

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.16% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(storage): add sqlite durable fencing' directly and clearly describes the main change: adding SQLite-based transactional fencing for durable storage, which is the core feature introduced across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sqlite-transactional-fencing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@delete-cloud
delete-cloud merged commit 3c5a2f6 into main Jun 5, 2026
1 check was pending
@delete-cloud
delete-cloud deleted the feat/sqlite-transactional-fencing branch June 5, 2026 09:22
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