"""Preserve deployed migration meaning and prove additive convergence on isolated databases.""" from __future__ import annotations import hashlib import importlib import importlib.util from datetime import UTC, datetime from pathlib import Path from uuid import uuid4 import pytest from alembic.config import Config from alembic.migration import MigrationContext from alembic.operations import Operations from alembic.script import ScriptDirectory from sqlalchemy import Column, Integer, MetaData, Table, create_engine, inspect, select, text from sqlalchemy.exc import DBAPIError from sqlalchemy.orm import Session from modelforge_api.persistence.models import AuditEvent, ModelRevision, ProjectBinding from modelforge_api.services.recovery_fingerprint import _actual_table from tests.test_managed_identities_postgres import IdentityDatabase, identity_database from tests.test_selected_comparison_postgres import _valid_selection from tests.test_serving_generation_recovery import legacy_generation_fixture __all__ = ["identity_database"] ROOT = Path(__file__).resolve().parents[1] VERSIONS = ROOT / "alembic" / "versions" FROZEN = { "20260909_0029_external_creative_coordination.py": "ac41923b2bd7a8729abeaae5c872afa3186d4b188fe002015d77c9bc23b9c5db", "20260909_0030_model_update_inbox.py": "265379bd5e1c2cee78a9c4a4e6004ec802a6dbbc57e5f30c422e8eb91fea99cf", "20260909_0031_external_creative_governance.py": "397d4b288bb7564eb50da5950e1478db237f2a91d801de3d3786112b638f2c55", "20260909_0032_audio_creative_workloads.py": "ede826fa5ada798e5730ef99b0a8380d1831d3ed11a1baccda9ed5bc0e60d362", } HISTORY_TABLES = ( "model_update_watches", "model_update_notices", "external_creative_allocations", "external_creative_resources", "external_creative_action_attestations", "external_creative_profile_observations", ) def _migration(): specification = importlib.util.spec_from_file_location( "convergence", VERSIONS / "20260909_0033_deployed_hub_convergence.py" ) assert specification is not None and specification.loader is not None module = importlib.util.module_from_spec(specification) specification.loader.exec_module(module) return module def test_deployed_migration_content_remains_frozen_and_graph_is_linear() -> None: for name, digest in FROZEN.items(): # Normalize checkout line endings only; the deployed repository blobs are LF. assert ( hashlib.sha256((VERSIONS / name).read_bytes().replace(b"\r\n", b"\n")).hexdigest() == digest ) config = Config() config.set_main_option("script_location", str(ROOT / "alembic")) graph = ScriptDirectory.from_config(config) assert graph.get_heads() == ["20260924_0039"] assert Path(graph.get_revision("20260909_0029").path).name in FROZEN assert Path(graph.get_revision("20260909_0030").path).name in FROZEN assert graph.get_revision("20260909_0033").down_revision == "20260909_0032" assert graph.get_revision("20260923_0036").down_revision == "20260911_0035" assert graph.get_revision("20260923_0037").down_revision == "20260923_0036" assert graph.get_revision("20260924_0038").down_revision == "20260923_0037" assert graph.get_revision("20260924_0039").down_revision == "20260924_0038" assert not (VERSIONS / "20260909_0029_model_update_inbox.py").exists() assert not (VERSIONS / "20260909_0030_selected_model_comparisons.py").exists() @pytest.mark.parametrize("populated", HISTORY_TABLES) def test_new_downgrade_refuses_populated_deployed_history(populated: str) -> None: engine = create_engine("sqlite://") with engine.begin() as connection: for name in HISTORY_TABLES: Table(name, MetaData(), Column("id", Integer)).create(connection) connection.execute(text("ALTER TABLE model_update_watches ADD COLUMN upstream_ref TEXT")) module = _migration() module.op = Operations(MigrationContext.configure(connection)) module.upgrade() table = Table(populated, MetaData(), autoload_with=connection) connection.execute(table.insert().values(id=1)) with pytest.raises(RuntimeError, match="history exists"): module.downgrade() assert inspect(connection).has_table("selected_model_comparisons") assert { column["name"] for column in inspect(connection).get_columns("model_update_watches") } >= {"enabled", "version"} engine.dispose() def test_populated_0032_upgrade_preserves_creative_watch_audit_history_and_restricts_runtime( identity_database: IdentityDatabase, ) -> None: database = identity_database alembic = importlib.import_module("alembic.command") alembic.upgrade(database.migration(), "20260909_0032") with legacy_generation_fixture(database.owner), Session(database.runtime) as session: request, client_id = _valid_selection(session) connection = session.connection() tables = {name: _actual_table(connection, name) for name in HISTORY_TABLES} project_id = connection.scalar( select(ProjectBinding.project_id).where(ProjectBinding.id == request.project_binding_id), ) revision = connection.execute( select(ModelRevision.id, ModelRevision.model_id, ModelRevision.resolved_commit_sha).order_by(ModelRevision.id).limit(1) ).one() watch_id, allocation_id, resource_id = uuid4(), uuid4(), uuid4() connection.execute( tables["model_update_watches"] .insert() .values( id=watch_id, model_id=revision.model_id, baseline_revision_id=revision.id, baseline_commit_sha=revision.resolved_commit_sha, upstream_ref="main", ) ) connection.execute( tables["model_update_notices"] .insert() .values( id=uuid4(), watch_id=watch_id, model_id=revision.model_id, baseline_commit_sha=revision.resolved_commit_sha, candidate_revision_id=revision.id, candidate_commit_sha=revision.resolved_commit_sha, status="dismissed", ) ) connection.execute( tables["external_creative_allocations"] .insert() .values( id=allocation_id, service_client_id=client_id, project_id=project_id, request_id="preserved", idempotency_key="preserved", request_sha256="a" * 64, workload="audio", resource_ref="fixture.audio@1", provider_resource_id="fixture", required_vram_bytes=1024, priority="background", ttl_seconds=600, state="released", decision_code="OFFLINE_FIXTURE", decision_evidence={"preserve": True}, required_actions=[], ) ) connection.execute( tables["external_creative_resources"] .insert() .values( id=resource_id, project_id=project_id, resource_ref="fixture.audio@1", workload="audio", provider_resource_id="fixture", approved=False, configured_vram_bytes=1024, ) ) connection.execute( tables["external_creative_action_attestations"] .insert() .values( id=uuid4(), allocation_id=allocation_id, action="release_idle_comfy", before_vram_bytes=1024, after_vram_bytes=0, observed_at=datetime.now(UTC), validated=True, ) ) connection.execute( tables["external_creative_profile_observations"] .insert() .values( id=uuid4(), allocation_id=allocation_id, resource_ref="fixture.audio@1", provider_resource_id="fixture", workload="audio", observed_peak_vram_bytes=512, reserved_vram_bytes=1024, duration_ms=1, outcome="succeeded", ) ) session.commit() before = { name: session.execute(select(table).order_by(table.c.id)).mappings().all() for name, table in tables.items() } audit_before = session.execute( select(AuditEvent.id, AuditEvent.canonical_payload, AuditEvent.event_hash).order_by(AuditEvent.sequence) ).all() assert "enabled" not in { column["name"] for column in inspect(session.connection()).get_columns("model_update_watches") } alembic.upgrade(database.migration(), "20260909_0033") with database.runtime.connect() as connection: for name, table in tables.items(): assert ( connection.execute(select(table).order_by(table.c.id)).mappings().all() == before[name] ) assert ( connection.execute( select(AuditEvent.id, AuditEvent.canonical_payload, AuditEvent.event_hash).order_by(AuditEvent.sequence) ).all() == audit_before ) assert connection.execute( text("SELECT enabled, version FROM model_update_watches WHERE id=:id"), {"id": watch_id} ).one() == (True, 1) assert connection.scalar(text("SELECT count(*) FROM selected_model_comparisons")) == 0 for table_name in ( "model_update_watches", "model_update_notices", "selected_model_comparisons", ): for privilege in ("SELECT", "INSERT", "UPDATE"): assert connection.scalar( text("SELECT has_table_privilege(current_user, :table, :privilege)"), {"table": table_name, "privilege": privilege}, ) for privilege in ("DELETE", "TRUNCATE"): assert not connection.scalar( text("SELECT has_table_privilege(current_user, :table, :privilege)"), {"table": table_name, "privilege": privilege}, ) with pytest.raises(DBAPIError): connection.execute( text("DELETE FROM model_update_watches WHERE id=:id"), {"id": watch_id} ) connection.rollback() with pytest.raises(RuntimeError, match="history exists"): alembic.downgrade(database.migration(), "20260909_0032") with database.runtime.connect() as connection: assert connection.scalar(text("SELECT version_num FROM alembic_version")) == "20260909_0033"