"""Disposable PostgreSQL route CAS and runtime-role transaction qualification.""" import importlib import threading from concurrent.futures import ThreadPoolExecutor import pytest from sqlalchemy.orm import Session from modelforge_api.domain.lifecycle_contracts import ApprovalDecision from modelforge_api.persistence.models import CapabilityContract, LifecycleOperation from modelforge_api.persistence.serving_repository import ServingRepository from modelforge_api.services.lifecycle import LifecycleError, LifecycleService from tests.test_lifecycle_serving import approved_plan, build_pair from tests.test_managed_identities_postgres import IdentityDatabase, identity_database __all__ = ["identity_database"] def test_two_committers_switch_once_and_exact_rollback_increments_generation( identity_database: IdentityDatabase, ) -> None: database = identity_database importlib.import_module("alembic.command").upgrade(database.migration(), "head") with Session(database.runtime) as session: pair = build_pair(session) _, _, current, candidate, selection, _ = pair _, _, operation, _ = approved_plan(pair) operation_id, current_id, candidate_id = operation.id, current.id, candidate.id contract_id, generation = ( current.capability_contract_id, selection.expected_route_generation, ) barrier = threading.Barrier(2) def contender(_index: int) -> str: with Session(database.runtime) as session: barrier.wait(timeout=30) try: return ( LifecycleService(session) .commit_operation( operation_id, ApprovalDecision( actor="qualification", reason="Concurrent explicit commit qualification" ), ) .stage ) except LifecycleError: session.rollback() return "CONFLICT" with ThreadPoolExecutor(max_workers=2) as pool: # Same-operation retries return its persisted result, without a second switch. assert list(pool.map(contender, [1, 2])) == ["COMMITTED", "COMMITTED"] with Session(database.runtime) as session: assert ServingRepository(session).stable_deployment(contract_id).id == candidate_id assert session.get(CapabilityContract, contract_id).serving_generation == generation + 1 assert session.get(LifecycleOperation, operation_id).stage == "COMMITTED" restored = LifecycleService(session).rollback_operation( operation_id, ApprovalDecision(actor="qualification", reason="Restore exact prior serving route"), ) assert restored.stage == "ROLLED_BACK" assert ServingRepository(session).stable_deployment(contract_id).id == current_id assert session.get(CapabilityContract, contract_id).serving_generation == generation + 2 with pytest.raises(RuntimeError, match="Serving route history exists"): importlib.import_module("alembic.command").downgrade(database.migration(), "20260909_0033") def test_current_route_generation_survives_postgres_dump_restore( identity_database: IdentityDatabase, tmp_path ): from modelforge_api.services.recovery_fingerprint import ( BENCHMARK_RUN_SCHEMA, audit_fingerprint_differences_are_compatible, fingerprint_compatibility, semantic_fingerprint, ) database = identity_database importlib.import_module("alembic.command").upgrade(database.migration(), "head") with Session(database.runtime) as session: pair = build_pair(session) _, _, operation, _ = approved_plan(pair) LifecycleService(session).commit_operation( operation.id, ApprovalDecision( actor="qualification", reason="Qualify retained committed route after restore" ), ) contract_id = pair[2].capability_contract_id generation = session.get(CapabilityContract, contract_id).serving_generation assert generation > 0 source = semantic_fingerprint(session.connection()) archive = tmp_path / "committed-route-current.dump" database.archive(archive) database.archive(archive, restore=True) with Session(database.restored_runtime) as session: restored = semantic_fingerprint(session.connection()) compatibility = fingerprint_compatibility( source, restored, source_schema_revision=BENCHMARK_RUN_SCHEMA ) assert compatibility.compatible assert audit_fingerprint_differences_are_compatible(source, restored, compatibility) assert session.get(CapabilityContract, contract_id).serving_generation == generation session.get(CapabilityContract, contract_id).serving_generation = 0 session.flush() changed = semantic_fingerprint(session.connection()) assert not audit_fingerprint_differences_are_compatible(source, changed, compatibility) session.rollback()