fix: make sqlite session entry writes atomic#91491
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 8, 2026, 3:22 PM ET / 19:22 UTC. Summary PR surface: Source +153, Tests +39. Total +192 across 9 files. Reproducibility: yes. from source inspection, though I did not run tests in this read-only review. Current main writes the whole SQLite session_entries scope from the writer snapshot, and the PR's new test simulates an external SQLite write during a callback. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the atomic row-patch approach, but make direct updateSessionStore callers receive the reconciled persisted row, add regression coverage for that returned/in-memory state, and require maintainer review plus real behavior proof before merge. Do we have a high-confidence way to reproduce the issue? Yes from source inspection, though I did not run tests in this read-only review. Current main writes the whole SQLite session_entries scope from the writer snapshot, and the PR's new test simulates an external SQLite write during a callback. Is this the best way to solve the issue? No, not yet. The row-patch direction is the right layer for this tactical safety slice, but the implementation still returns stale mutator results to migrated callers instead of the reconciled persisted row. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 9220761fbaea. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +153, Tests +39. Total +192 across 9 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Closing as superseded by the #88838 stack, per maintainer decision. Context: #91322 was reverted on main on 2026-06-10 ( The substance of this PR survives in the stack that will reland SQLite sessions:
Tracker: #88838. |
Summary
This PR hardens the SQLite session metadata path that landed in #91322 by moving ordinary hot session-entry writes off the stale whole-store replacement path.
session_entriesrow inside the per-agent SQLite write transaction, merges the caller's explicit patch, and upserts only that row.cache_entriesblob backend.Review focus: the row-patch semantics, the cache reconciliation after a row patch, and whether each migrated caller provides a patch that accurately represents its intended write.
Linked context
Related #91322, which moved session metadata from
sessions.jsoninto SQLite but retained the old load/mutate/delete-and-reinsert whole-store write shape for normal metadata updates.Related tracker #88838 for the broader core session/transcript runtime-state SQLite migration.
Supersession notes for Josh's existing stack:
main. It does not supersede refactor: add SQLite session store foundation #89178's broader typed relational schema direction or transcript/event table design.Requested by Josh during review of the post-#91322 SQLite session-store behavior.
Real behavior proof (required for external PRs)
session_entriesrows, which can clobber unrelated fields written by another process between the callback read and the final transaction.node scripts/run-vitest.mjswrapper for focused session/agent tests.node scripts/run-vitest.mjs src/config/sessions.cache.test.ts src/config/sessions.test.ts src/agents/command/session-store.test.ts src/agents/command/attempt-execution.shared.test.tsupdateSessionStoreEntrypreserves an external SQLite write made while its update callback is running, while still applying the local patch.replaceSqliteSessionStore, which deletes all rows for thesession_entriesscope and reinserts from the callback's previously loaded store snapshot.Tests and validation
Commands run:
git diff --checknode scripts/run-vitest.mjs src/config/sessions.cache.test.ts src/config/sessions.test.ts src/agents/command/session-store.test.ts src/agents/command/attempt-execution.shared.test.ts.agents/skills/autoreview/scripts/autoreview --mode localRegression coverage added:
src/config/sessions.test.tsnow covers preserving an external SQLite write while anupdateSessionStoreEntrycallback is in flight.src/agents/command/session-store.test.tsnow verifies after-run persistence passes a narrow metadata patch rather than a broad entry-shaped persistence payload.Autoreview result: clean, no accepted/actionable findings.
Risk checklist
Did user-visible behavior change?
Nointended user-facing behavior change; session metadata persistence should be more concurrency-safe.Did config, environment, or migration behavior change?
No.Did security, auth, secrets, network, or tool execution behavior change?
No.Highest-risk area: incorrectly classifying a caller as safe for row patching when its callback actually depends on deletion, conditional persistence, legacy key cleanup, maintenance, or multi-row invariants.
Mitigation: this PR only uses the row path when callers provide explicit patches.
attempt-execution.shared.tsopts out whenclearedFieldsorshouldPersistare present, because those require semantics beyond a simple merge patch. Whole-store replacement remains available for maintenance and structurally unsafe operations.Current review state
Draft PR for review. Next action is maintainer review of the row-patch contract and the supersession relationship to the older session-store PR stack.
Still waiting on broad CI/Testbox proof before this should be treated as land-ready.