From 0cc02157b6b31682e1dd2c95aa54a9d604f96119 Mon Sep 17 00:00:00 2001 From: Sinity Date: Thu, 13 Aug 2026 12:32:27 +0200 Subject: [PATCH 1/2] fix: bootstrap durable operation fixtures Problem: durable-operation tests created partial archive roots that mandatory durable authority initialization correctly rejects. The adopted-audit restore metadata reader could also create SQLite sidecars beside a verified backup artifact. Solution: initialize tests through the complete archive bootstrap, clone the canonical archive fixture for independent tag examples, and open restore backups immutably during metadata inspection. --- polylogue/operations/durable_change_train.py | 16 ++++++++++++---- tests/unit/cli/test_archive_maintenance_cli.py | 2 ++ tests/unit/cli/test_reset.py | 5 ++--- tests/unit/storage/test_raw.py | 5 ++--- tests/unit/storage/test_store_ops.py | 17 ++++++++++++----- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/polylogue/operations/durable_change_train.py b/polylogue/operations/durable_change_train.py index d8bb537dee..15915cea1e 100644 --- a/polylogue/operations/durable_change_train.py +++ b/polylogue/operations/durable_change_train.py @@ -723,9 +723,14 @@ def _audit_file_identity(path: Path) -> tuple[int, int]: return metadata.st_dev, metadata.st_ino -def _audit_live_metadata(audit_path: Path) -> tuple[int, int, tuple[str, ...]]: - """Read the durable markers that remain valid after an in-place migration.""" - uri = f"{audit_path.resolve(strict=False).as_uri()}?mode=ro" +def _audit_live_metadata( + audit_path: Path, + *, + immutable: bool = False, +) -> tuple[int, int, tuple[str, ...]]: + """Read durable markers, without mutating an immutable backup artifact.""" + mode = "?mode=ro&immutable=1" if immutable else "?mode=ro" + uri = f"{audit_path.resolve(strict=False).as_uri()}{mode}" with closing(sqlite3.connect(uri, uri=True)) as connection: version = int(connection.execute("PRAGMA user_version").fetchone()[0] or 0) application_id = int(connection.execute("PRAGMA application_id").fetchone()[0] or 0) @@ -1372,7 +1377,10 @@ def restore_adopted_audit_tier( expected_initial_version = adoption.get("audit_user_version") if not isinstance(expected_application_id, int) or not isinstance(expected_initial_version, int): raise MigrationError("audit adoption receipt lacks its durable SQLite markers") - backup_version, backup_application_id, backup_quick_check = _audit_live_metadata(manifest_path.parent / "audit.db") + backup_version, backup_application_id, backup_quick_check = _audit_live_metadata( + manifest_path.parent / "audit.db", + immutable=True, + ) if ( backup_version != artifact_version or backup_version != ARCHIVE_VERSION_BY_TIER[ArchiveTier.AUDIT] diff --git a/tests/unit/cli/test_archive_maintenance_cli.py b/tests/unit/cli/test_archive_maintenance_cli.py index 8126198dff..dbd62b9b23 100644 --- a/tests/unit/cli/test_archive_maintenance_cli.py +++ b/tests/unit/cli/test_archive_maintenance_cli.py @@ -3638,6 +3638,8 @@ def test_migrate_tier_cli_restores_adopted_audit_from_verified_full_evidence( assert restored.exit_code == 0, restored.output payload = json.loads(restored.stdout) assert payload["restore_receipt"].endswith(".committed.json") + backup_audit = Path(verified.output_path) / "audit.db" + assert all(not Path(f"{backup_audit}{suffix}").exists() for suffix in ("-wal", "-shm", "-journal")) with sqlite3.connect(audit_path) as connection: assert connection.execute("PRAGMA user_version").fetchone() == (ARCHIVE_VERSION_BY_TIER[ArchiveTier.AUDIT],) assert connection.execute("SELECT generation FROM audit_continuity_head").fetchone() == (2,) diff --git a/tests/unit/cli/test_reset.py b/tests/unit/cli/test_reset.py index 6d5eba54ec..f2a4a8df07 100644 --- a/tests/unit/cli/test_reset.py +++ b/tests/unit/cli/test_reset.py @@ -12,7 +12,7 @@ from click.testing import CliRunner from polylogue.cli import cli -from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_archive_database +from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_active_archive_root, initialize_archive_database from polylogue.storage.sqlite.archive_tiers.types import ArchiveTier from tests.infra.cli_subprocess import run_cli, setup_isolated_workspace @@ -30,10 +30,9 @@ def _seed_archive_session(archive_root: Path, *, native_id: str, source_path: Path | None = None) -> str: + initialize_active_archive_root(archive_root) source_db = archive_root / "source.db" index_db = archive_root / "index.db" - initialize_archive_database(source_db, ArchiveTier.SOURCE) - initialize_archive_database(index_db, ArchiveTier.INDEX) session_id = f"codex-session:{native_id}" raw_id = f"raw-{native_id}" with sqlite3.connect(source_db) as conn: diff --git a/tests/unit/storage/test_raw.py b/tests/unit/storage/test_raw.py index f19e37c473..d3169191a9 100644 --- a/tests/unit/storage/test_raw.py +++ b/tests/unit/storage/test_raw.py @@ -21,7 +21,7 @@ from polylogue.storage.raw.models import RawSessionStateUpdate from polylogue.storage.repository import SessionRepository from polylogue.storage.runtime import RawSessionRecord -from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_archive_database +from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_active_archive_root, initialize_archive_database from polylogue.storage.sqlite.archive_tiers.types import ArchiveTier from polylogue.storage.sqlite.async_sqlite import SQLiteBackend from polylogue.storage.sqlite.queries.raw_reads import get_capture_mode_resolution @@ -70,8 +70,7 @@ async def test_save_raw_session_new(self, backend: SQLiteBackend) -> None: assert row[0] == 1 async def test_repository_update_raw_state_uses_source_tier(self, tmp_path: Path) -> None: - initialize_archive_database(tmp_path / "source.db", ArchiveTier.SOURCE) - initialize_archive_database(tmp_path / "index.db", ArchiveTier.INDEX) + initialize_active_archive_root(tmp_path) source_backend = SQLiteBackend(db_path=tmp_path / "source.db") try: await source_backend.save_raw_session( diff --git a/tests/unit/storage/test_store_ops.py b/tests/unit/storage/test_store_ops.py index f56bafbc97..6d905b2875 100644 --- a/tests/unit/storage/test_store_ops.py +++ b/tests/unit/storage/test_store_ops.py @@ -1782,14 +1782,21 @@ async def fake_to_thread(func: Callable[..., object], /, *args: object, **kwargs class TestInfraTagAssignment: """Property-based tests using the full TagAssignmentSpec strategy.""" - @given(infra_tag_assignment_strategy(min_sessions=2, max_sessions=4)) + @given(spec=infra_tag_assignment_strategy(min_sessions=2, max_sessions=4)) @settings(max_examples=10, deadline=None) - async def test_tag_assignment_roundtrip_and_counts(self, spec: TagAssignmentSpec) -> None: + async def test_tag_assignment_roundtrip_and_counts( + self, + spec: TagAssignmentSpec, + empty_archive_template: Path, + ) -> None: """Strategy-generated tags are retrievable and counted consistently.""" - with tempfile.TemporaryDirectory() as tmp_dir: - from tests.infra.archive_scenarios import archive_for_scenario_db, native_session_id_for + from tests.conftest import _clone_archive_template + from tests.infra.archive_scenarios import archive_for_scenario_db, native_session_id_for - db_path = Path(tmp_dir) / "index.db" + with tempfile.TemporaryDirectory() as tmp_dir: + archive_root = Path(tmp_dir) / "archive" + _clone_archive_template(empty_archive_template, archive_root) + db_path = archive_root / "index.db" seed_session_graph(db_path, spec.sessions) repo = archive_for_scenario_db(db_path) From 2b203ecaadfdba45191b0ebdb58caefea390dd89 Mon Sep 17 00:00:00 2001 From: Sinity Date: Thu, 13 Aug 2026 12:53:21 +0200 Subject: [PATCH 2/2] test: seed reset fixtures through active index Problem: reset tests seeded archive_root/index.db after bootstrap even when an active-index pointer selected another index generation. The production reset route correctly resolves the pointer target, so the fixture could exercise the wrong database. What changed: resolve and initialize the selected active index before seeding. The reset-session regression now installs an active-index pointer and verifies the selected index is mutated while the conventional shadow index stays empty. --- tests/unit/cli/test_reset.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/unit/cli/test_reset.py b/tests/unit/cli/test_reset.py index f2a4a8df07..390b0d04d0 100644 --- a/tests/unit/cli/test_reset.py +++ b/tests/unit/cli/test_reset.py @@ -12,6 +12,7 @@ from click.testing import CliRunner from polylogue.cli import cli +from polylogue.storage.archive_identity import ArchiveLocation from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_active_archive_root, initialize_archive_database from polylogue.storage.sqlite.archive_tiers.types import ArchiveTier from tests.infra.cli_subprocess import run_cli, setup_isolated_workspace @@ -32,7 +33,8 @@ def _seed_archive_session(archive_root: Path, *, native_id: str, source_path: Path | None = None) -> str: initialize_active_archive_root(archive_root) source_db = archive_root / "source.db" - index_db = archive_root / "index.db" + index_db = ArchiveLocation.resolve(archive_root).active_index_path + initialize_archive_database(index_db, ArchiveTier.INDEX) session_id = f"codex-session:{native_id}" raw_id = f"raw-{native_id}" with sqlite3.connect(source_db) as conn: @@ -413,6 +415,9 @@ def test_reset_session_records_archive_suppression_and_deletes_archive_row( archive_root = tmp_path / "archive" archive_root.mkdir() + active_index = tmp_path / "index-generation" / "index.db" + active_index.parent.mkdir() + (archive_root / ".index-active-pointer").write_text(str(active_index), encoding="utf-8") session_id = _seed_archive_session(archive_root, native_id="reset-one") with patch("polylogue.cli.commands.reset.archive_root", return_value=archive_root): @@ -422,8 +427,10 @@ def test_reset_session_records_archive_suppression_and_deletes_archive_row( assert result.exit_code == 0 assert "1 suppression" in result.output assert "1 archive row" in result.output - with sqlite3.connect(archive_root / "index.db") as conn: + with sqlite3.connect(active_index) as conn: assert conn.execute("SELECT COUNT(*) FROM sessions WHERE session_id = ?", (session_id,)).fetchone()[0] == 0 + with sqlite3.connect(archive_root / "index.db") as conn: + assert conn.execute("SELECT COUNT(*) FROM sessions").fetchone()[0] == 0 with sqlite3.connect(archive_root / "user.db") as conn: row = conn.execute( "SELECT body_text, json_extract(value_json, '$.mode') FROM assertions WHERE kind = 'suppression' AND target_ref = ?",