fix(observatory): preserve source identity on unchanged reindex

This commit is contained in:
DCCONSTRUCTIONS
2026-09-03 11:43:03 +03:00
parent 54c8d82884
commit bd947b49f4
3 changed files with 113 additions and 10 deletions
@@ -126,14 +126,13 @@ def _ready_registry(tmp_path: Path) -> PortableRunDefinitionRegistry:
return PortableRunDefinitionRegistry.from_file(path)
def _source_store(
def _source_archive(
tmp_path: Path,
definition: PortableRunDefinition,
) -> tuple[SessionStore, str, str, str]:
repository = tmp_path / "repository"
) -> ObservationArchiveSource:
archive_root = tmp_path / "source-archive"
session_root = archive_root / SOURCE_SESSION_ID
session_root.mkdir(parents=True)
session_root.mkdir(parents=True, exist_ok=True)
candidate = ObservationSessionCandidate(
session_id=SOURCE_SESSION_ID,
display_name="Portable result source",
@@ -152,12 +151,20 @@ def _source_store(
sources=(),
artifacts=(),
)
archive = ObservationArchiveSource(
return ObservationArchiveSource(
plugin_id=definition.source_requirements.plugin_id,
archive_id=definition.source_requirements.archive_id,
root=archive_root,
discover=lambda _root: (candidate,),
)
def _source_store(
tmp_path: Path,
definition: PortableRunDefinition,
) -> tuple[SessionStore, str, str, str]:
repository = tmp_path / "repository"
archive = _source_archive(tmp_path, definition)
store = SessionStore(repository, data_dir=tmp_path / "mission-core-data")
assert store.reconcile_archive(archive) == (SOURCE_SESSION_ID,)
_detail, catalog_sha256 = store.get_session_with_catalog_snapshot(SOURCE_SESSION_ID)
@@ -738,6 +745,26 @@ def test_cache_does_not_hide_another_source_snapshot_or_profile_version(tmp_path
assert sessions.get_lab_instance(RESULT_ID) is not None
def test_cache_survives_new_store_and_archive_reconciliation(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T08:00:00.000Z")
cache, queue, sessions, artifacts, registry, definition, job, _, _ = _cache_fixture(tmp_path)
before = cache.find(SOURCE_SESSION_ID, definition)
assert before
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T09:00:00.000Z")
reopened = SessionStore(sessions.repository_root, data_dir=sessions.data_dir)
reopened.reconcile_archive(_source_archive(tmp_path, definition))
cold_cache = PortableResultCache(
sessions=reopened, artifacts=artifacts, queue=queue, definitions=registry,
calculation_profiles=PortableCalculationProfileRegistry((_profile(definition),)),
)
assert cold_cache.find(SOURCE_SESSION_ID, definition) == before
with pytest.raises(ObservatoryRecordedQueueDuplicateError):
queue.submit(_retry_intent(job), published_result_available=cold_cache.available)
assert len(queue.list_jobs()) == 1
@pytest.mark.parametrize("field", ["executor_image_sha256", "source_bundle_sha256"])
def test_queue_rejects_mutated_job_identity_before_cache_lookup(tmp_path: Path, field: str) -> None:
cache, _, _, _, _, definition, job, _, _ = _cache_fixture(tmp_path)
+56
View File
@@ -186,6 +186,62 @@ def test_evidence_root_is_private_and_configurable(
assert resolve_missioncore_evidence_dir(repository) == configured.resolve()
def test_unchanged_archive_preserves_exact_snapshot_across_reopen(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
session = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T08:00:00.000Z")
store = SessionStore(repository, data_dir=tmp_path / "data")
archive = xgrids_k1_archive_source(sessions)
store.reconcile_archive(archive)
before = store.get_session_with_catalog_snapshot(session.name)
with sqlite3.connect(store.database_path) as connection:
rows = tuple(connection.iterdump())
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T09:00:00.000Z")
reopened = SessionStore(repository, data_dir=store.data_dir)
for _ in range(2):
assert reopened.reconcile_archive(archive) == (session.name,)
assert reopened.get_session_with_catalog_snapshot(session.name) == before
with sqlite3.connect(store.database_path) as connection:
assert tuple(connection.iterdump()) == rows
@pytest.mark.parametrize("table,assignment", [
("observation_sessions", "total_bytes = total_bytes + 1"),
("observation_sessions", "duration_seconds = duration_seconds + 1"),
("observation_session_sources", "seekable = 0"),
("observation_session_artifacts", "byte_length = byte_length + 1"),
("observation_session_artifacts", "sha256 = NULL"),
])
def test_reconcile_retains_clock_change_for_real_catalog_differences(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, table: str, assignment: str,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
session = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T08:00:00.000Z")
store = SessionStore(repository, data_dir=tmp_path / "data")
archive = xgrids_k1_archive_source(sessions)
store.reconcile_archive(archive)
original = store.get_session_with_catalog_snapshot(session.name)
with sqlite3.connect(store.database_path) as connection:
connection.execute(f"UPDATE {table} SET {assignment}") # noqa: S608 - fixed test cases
changed = store.get_session_with_catalog_snapshot(session.name)
assert changed[1] != original[1]
monkeypatch.setattr("k1link.sessions.store.utc_now_iso", lambda: "2026-09-03T09:00:00.000Z")
store.reconcile_archive(archive)
after = store.get_session_with_catalog_snapshot(session.name)
assert after[1] not in (original[1], changed[1])
with sqlite3.connect(store.database_path) as connection:
assert connection.execute(
"SELECT updated_at_utc FROM observation_sessions WHERE session_id = ?",
(session.name,),
).fetchone()[0] == "2026-09-03T09:00:00.000Z"
def test_catalog_reconciles_sessions_removed_from_one_evidence_root(tmp_path: Path) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"