"""Phase 4 validation gate tests.""" from __future__ import annotations import asyncio from ont_platform.core.review import CandidatePromotionService from ont_platform.core.validation import OntologyGuard from ont_platform.storage.candidate_repository import CandidateRepository from ont_platform.storage.models import Base, ReviewStatus from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker def _session() -> Session: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) return sessionmaker(bind=engine)() def test_guardrails_facade_reports_structured_schema_issues() -> None: async def run(): guard = OntologyGuard(validator_type="guardrails", strict=False) return await guard.validate( { "entities": [ { "id": "E_bad", "label": "Bad Confidence", "type": "concept", "confidence": 1.5, } ], "relations": [], } ) result = asyncio.run(run()) assert result.validation_passed is False assert result.validation_issues assert result.validation_issues[0].source == "guardrails_facade" assert result.validation_issues[0].code == "entity_schema_violation" def test_validation_issues_are_stored_and_block_promotion() -> None: db = _session() repository = CandidateRepository(db) batch = repository.save_ontocast_result( project_id="proj_guard", document_id="doc_guard", result={ "entities": [ { "id": "E_guard", "label": "Guarded", "entity_type": "concept", "confidence": 0.91, "evidence_ids": ["EV_guard"], } ], "relations": [], "evidence_spans": [ { "id": "EV_guard", "text": "Guarded output has evidence.", "start_offset": 0, "end_offset": 28, } ], "validation_issues": [ { "severity": "error", "code": "confidence_range", "message": "confidence must be between 0 and 1", } ], }, validation_passed=False, ) entity = batch.entities[0] entity.review_status = ReviewStatus.APPROVED issues = repository.list_validation_issues(project_id="proj_guard") plan = CandidatePromotionService(repository).build_commit_plan(project_id="proj_guard") assert len(issues) == 1 assert issues[0].code == "confidence_range" assert len(plan.entities) == 0 assert plan.blocked[0]["reason"] == "validation_failed"