91 lines
2.9 KiB
Python
91 lines
2.9 KiB
Python
|
|
"""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"
|