File size: 3,155 Bytes
aad7814
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from __future__ import annotations

from docx import Document

from backend.config import settings
from backend.core import ingest, section_mapper, template_discoverer
from backend.core.pii_scrubber import scrub_rag_chunk
from backend.core.report_assembler import to_docx
from backend.models.schema import RatingSystem, TemplateSchema


def _write_bundle(tmp_path):
    """Minimal PDF-structure docx + Word paragraphs docx."""
    tpl = tmp_path / "template.docx"
    doc = Document()
    doc.add_paragraph("D1 Chimney stacks")
    doc.add_paragraph("D2 Roof coverings")
    doc.save(str(tpl))

    paras = tmp_path / "paragraphs.docx"
    doc2 = Document()
    doc2.add_paragraph("Section E1 - Chimney Stacks")
    doc2.add_paragraph("The chimney stacks were inspected from ground level.")
    doc2.add_paragraph("Section E2 - Roof Coverings")
    doc2.add_paragraph("The roof covering comprises slate.")
    doc2.save(str(paras))
    return tpl, paras


def test_no_rating_when_schema_undetected(tmp_path, monkeypatch):
    monkeypatch.setattr(settings, "data_dir", str(tmp_path / "data"))
    tpl, paras = _write_bundle(tmp_path)
    tenant = "t-int"
    ingest.ingest_report_template(tenant, tpl)
    ingest.ingest_standard_paragraphs(tenant, paras)
    ingest.ingest_reference(tenant, paras)

    schema = template_discoverer.load_schema(tenant)
    schema.rating_system = RatingSystem(detected=False)
    template_discoverer.save_schema(tenant, schema)

    result = section_mapper.generate_report(
        tenant, "D1: chimney cracked\n\nroof slate slipped", interference_level="maximum"
    )
    for sec in result.sections:
        assert sec.rating_value is None


def test_pii_never_in_docx_output(tmp_path, monkeypatch):
    monkeypatch.setattr(settings, "data_dir", str(tmp_path / "data"))
    tpl, paras = _write_bundle(tmp_path)
    tenant = "t-pii"
    ingest.ingest_report_template(tenant, tpl)
    ingest.ingest_standard_paragraphs(tenant, paras)
    ingest.ingest_reference(tenant, paras)

    notes = "D1: chimney cracked at SW1A 1AA\n\nroof slate slipped"
    result = section_mapper.generate_report(tenant, notes, interference_level="maximum")
    schema = template_discoverer.load_schema(tenant)
    docx = to_docx(result, schema)

    assert b"SW1A" not in docx
    assert b"1AA" not in docx
    full = scrub_rag_chunk(result.unassigned_text + "".join(s.text for s in result.sections))
    assert "SW1A" not in full


def test_unmatched_observation_preserved_in_notes_field(tmp_path, monkeypatch):
    """Offline stitch still produces section text from notes (no invention)."""
    monkeypatch.setattr(settings, "data_dir", str(tmp_path / "data"))
    tpl, paras = _write_bundle(tmp_path)
    tenant = "t-ground"
    ingest.ingest_report_template(tenant, tpl)
    ingest.ingest_standard_paragraphs(tenant, paras)
    ingest.ingest_reference(tenant, paras)

    result = section_mapper.generate_report(
        tenant, "D1: unusual widget failure on chimney", interference_level="maximum"
    )
    d1 = next(s for s in result.sections if s.section_id == "D1")
    assert "widget" in d1.text.lower() or "chimney" in d1.text.lower()