"""API guardrail: block report tier mismatches with primary document.""" from pathlib import Path import pytest from docx import Document as DocxDocument from app.db.models import Document, IngestStatus @pytest.mark.asyncio async def test_create_report_rejects_confident_tier_mismatch( async_client: object, test_db: object, tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: from app.services import survey_level_classifier as slc tenant = "tenant_test" doc_id = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" fp = tmp_path / "primary.docx" d = DocxDocument() d.add_paragraph("RICS Home Survey Level 3 building survey. Further investigations. " * 20) d.save(fp) test_db.add( Document( id=doc_id, tenant_id=tenant, filename="primary.docx", file_path=str(fp.resolve()), status=IngestStatus.complete, survey_level=2, # even if user-labelled wrong, classifier should stop silent mismatch ) ) await test_db.commit() # Force a confident classifier mismatch regardless of corpus contents. fake = slc.SurveyLevelClassification( document_id=doc_id, filename="primary.docx", predicted_survey_level=3, confidence=0.9, candidates=[slc.SurveyLevelCandidate(survey_level=3, score=1.0)], rationale="FIXTURE: looks like a building survey.", ) monkeypatch.setattr(slc, "classify_file_path", lambda *args, **kwargs: fake) res = await async_client.post( f"/reports?document_id={doc_id}&survey_level=2", headers={"X-Tenant-ID": tenant}, ) assert res.status_code == 422 body = res.json() assert "detail" in body assert body["detail"]["error"] == "Tier mismatch" ok = await async_client.post( f"/reports?document_id={doc_id}&survey_level=2&confirm_tier_mismatch=true", headers={"X-Tenant-ID": tenant}, ) assert ok.status_code == 201 data = ok.json() assert data["report_id"]