Why: Two processes opening the same SQLite file both migrate and reconcile, so the second one seals the first one's live runs.
Evidence: SELF tests are recorded on the Dev task card .task/feature-u8-sqlite-instance-guard.md. PG durability readback is NOT_RUN locally; Dev CI make test-backend-pg is the GATE. Backend CI on this HEAD is the GATE for go test.
Impact: SQLite serve and migrate share one non-blocking flock taken before open. A replaced database or rebuilt lock refuses start unless --adopt-instance-guard. A missing database is not recreated. The lock file cannot alias the database. PostgreSQL refuses when fsync, full_page_writes, or synchronous_commit is off.
Refs: Dev docs/recovery/u8-sqlite-instance-guard.md. Merge this PR before the Dev pin PR.
Why: Two processes opening the same SQLite file both migrate and reconcile, so the second one seals the first one's live runs.
Evidence: SELF tests are recorded on the Dev task card `.task/feature-u8-sqlite-instance-guard.md`. PG durability readback is NOT_RUN locally; Dev CI `make test-backend-pg` is the GATE. Backend CI on this HEAD is the GATE for `go test`.
Impact: SQLite serve and migrate share one non-blocking flock taken before open. A replaced database or rebuilt lock refuses start unless `--adopt-instance-guard`. A missing database is not recreated. The lock file cannot alias the database. PostgreSQL refuses when fsync, full_page_writes, or synchronous_commit is off.
Refs: Dev docs/recovery/u8-sqlite-instance-guard.md. Merge this PR before the Dev pin PR.
Why: Two processes opening the same SQLite file both migrate and reconcile, so the second one seals the first one's live runs. The activity lock is taken before open, and durability settings are read back on the application connection.
Evidence: SELF go test ./internal/instanceguard ./internal/store ./internal/app (filtered T8 cases) on feature/u8-sqlite-instance-guard. PG durability readback is NOT_RUN locally; Dev CI test-backend-pg is the GATE.
Impact: SQLite serve and migrate share one non-blocking flock. A replaced database or rebuilt lock file refuses start unless --adopt-instance-guard. PostgreSQL serve refuses when fsync, full_page_writes, or synchronous_commit is off.
Refs: docs/recovery/u8-sqlite-instance-guard.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Review found that a missing data directory failed before open, adopt recreated a missing database, a lock symlink could be written as the database, and a failed identity check stored the wrong instance id.
Evidence: SELF go test TestMissingDataDirIsCreatedBeforeLock, TestLockSymlinkCannotAliasDatabase, TestAdoptDoesNotCreateMissingDatabase, TestIdentityFailureDoesNotStick.
Impact: First start creates the data directory before taking the lock. Adopt still refuses a missing database. The lock file is opened with O_NOFOLLOW and rejected when it is the database. Identity is checked before the guard row is written.
Refs: docs/recovery/u8-sqlite-instance-guard.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: CI rejected the new table as missing from the storage-migrate copy list, and the replacement test passed on filesystems that reused the deleted inode.
Evidence: SELF go test TestCopyOrderCoversAllFixtureTables and TestDatabaseReplacementRefusedBeforeOpen.
Impact: SQLite to PostgreSQL copy keeps the guard row. The replacement test burns inodes until the new file is distinct.
Refs: docs/recovery/u8-sqlite-instance-guard.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: deleting the lock and creating a new file can recycle the same inode, so an inode-only check treated the rebuilt lock as the original.
Evidence: SELF go test ./internal/instanceguard ./internal/store ./internal/app, including TestClearedLockRecordRefusedWhenInodeStays.
Impact: instance_guard and the lock file now share a random lock_gen. A missing or different generation refuses Bind unless adopt.
Refs: docs/recovery/u8-sqlite-instance-guard.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: main now rejects unknown subcommands and registers schema compatibility, so the guard branch could not merge until migrate stayed in that switch and v28 was registered.
Evidence: go test ./internal/instanceguard ./internal/app ./internal/store ./cmd/agent-system ./cmd/storage-migrate passed locally after the merge.
Impact: the activity lock and durability checks stay in front of open. v28 does not raise the old-reader floor because instance_guard is a new table.
Refs: cmd/agent-system/main.go, internal/store/migrate_compat.go
Co-authored-by: Cursor <cursoragent@cursor.com>
Superseded by #210: the same U8 change ported onto current main by a fresh agent-exec worker (migration renumbered to v36, main.go merged with capabilities/env/extension). Closing without merge; branch kept for reference.
Superseded by #210: the same U8 change ported onto current main by a fresh agent-exec worker (migration renumbered to v36, main.go merged with capabilities/env/extension). Closing without merge; branch kept for reference.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why: Two processes opening the same SQLite file both migrate and reconcile, so the second one seals the first one's live runs.
Evidence: SELF tests are recorded on the Dev task card
.task/feature-u8-sqlite-instance-guard.md. PG durability readback is NOT_RUN locally; Dev CImake test-backend-pgis the GATE. Backend CI on this HEAD is the GATE forgo test.Impact: SQLite serve and migrate share one non-blocking flock taken before open. A replaced database or rebuilt lock refuses start unless
--adopt-instance-guard. A missing database is not recreated. The lock file cannot alias the database. PostgreSQL refuses when fsync, full_page_writes, or synchronous_commit is off.Refs: Dev docs/recovery/u8-sqlite-instance-guard.md. Merge this PR before the Dev pin PR.
Superseded by #210: the same U8 change ported onto current main by a fresh agent-exec worker (migration renumbered to v36, main.go merged with capabilities/env/extension). Closing without merge; branch kept for reference.
Pull request closed