Spaces:
Runtime error
Runtime error
| """Global P2 high-confidence lexicon coverage and backend/frontend sync tests.""" | |
| from __future__ import annotations | |
| import re | |
| from pathlib import Path | |
| import pytest | |
| from backend.core.notes_high_confidence_lexicon import HIGH_CONFIDENCE_LEXICON | |
| from backend.core.notes_keyword_router import classify_note_cascade | |
| # Sample fragments per user-specified group (section_id, note_line). | |
| P2_ROUTING_CASES: list[tuple[str, str]] = [ | |
| # A β About the inspection | |
| ("A4", "Weather dry and overcast during inspection, no raining."), | |
| ("A5", "Property vacant and unoccupied at time of visit."), | |
| ("A1", "Surveyor name John Smith RICS member."), | |
| ("A3", "Related party disclosure noted for vendor."), | |
| # B β Overall | |
| ("B2", "Urgent repair required to roof coverings."), | |
| ("B1", "Condition rating 3 applied to several elements."), | |
| ("B3", "Further investigation recommended by specialist."), | |
| # C β Property | |
| ("C1", "Detached property of traditional brick construction."), | |
| ("C2", "Built around 1930 with later extended rear wing."), | |
| ("C5", "Local amenities and facilities within walking distance."), | |
| ("C4", "Mains gas and mains electric connected."), | |
| # G β Grounds (before D/E/F) | |
| ("G1", "Garage roof pitched with concrete tiles."), | |
| ("G2", "Permanent outbuilding used as workshop."), | |
| ("G3", "Driveway and patio with boundary wall fencing."), | |
| # D β Outside | |
| ("D1", "Chimney stack with defective flaunching and pots."), | |
| ("D2", "Pitched roof with slipped slates and battens visible."), | |
| ("D3", "UPVC gutters and rainwater downpipe to gullies."), | |
| ("D4", "External walls 300mm cavity wall with step cracking and lintel corrosion."), | |
| ("D5", "uPVC windows double glazed with timber frame casement."), | |
| ("D6", "Front door and patio door threshold worn, bifold to rear."), | |
| # E β Inside | |
| ("E1", "Loft conversion with visible rafters and purlins."), | |
| ("E2", "Ceiling cracks to plasterboard lath and plaster."), | |
| ("E3", "Stud wall internal partitions require plastering."), | |
| ("E4", "Suspended timber floor with springy floorboards."), | |
| ("E5", "Chimney breast hearth with woodburner and flue liner."), | |
| # F β Services | |
| ("F1", "Consumer unit fuse board wiring and sockets tested."), | |
| ("F2", "Gas meter and gas supply LPG bottle store."), | |
| ("F4", "Boiler and radiators central heating system."), | |
| ("F5", "Hot water cylinder with immersion heater."), | |
| ("F6", "Manhole and inspection chamber on foul drain soil pipe."), | |
| # I β Risks | |
| ("I3", "Suspected asbestos artex to ceiling."), | |
| ("I1", "Evidence of woodworm and structural movement."), | |
| ("I2", "Japanese knotweed identified in rear garden."), | |
| # J β Energy / insulation disambiguation | |
| ("E1", "Roof insulation between rafters in roof void."), | |
| ("J1", "Cavity insulation below recommended thickness."), | |
| ("J1", "Loft insulation thin at hatch."), | |
| ("J1", "General insulation upgrade recommended throughout."), | |
| ("J3", "Low energy lighting with LED fittings."), | |
| # Original regression cases | |
| ("D4", "External walls: 300mm cavity wall construction with step cracking"), | |
| ("D3", "Rainwater fittings: UPVC gutters and gullies present. Rainwater downpipe discharges below ground."), | |
| ("G1", "G1, garage roof pitched design with concrete tiles"), | |
| ] | |
| def test_p2_high_confidence_routes_globally(expected_section: str, note_line: str): | |
| section_id, score, _ = classify_note_cascade(note_line) | |
| assert section_id == expected_section, f"Expected {expected_section}, got {section_id} for: {note_line!r}" | |
| assert score == 1.0 | |
| def test_insulation_disambiguation_roof_vs_cavity_vs_loft(): | |
| assert classify_note_cascade("Roof insulation between trusses in loft void.")[0] == "E1" | |
| assert classify_note_cascade("Cavity insulation missing to external walls.")[0] == "J1" | |
| assert classify_note_cascade("Loft insulation thin at hatch.")[0] == "J1" | |
| assert classify_note_cascade("Insulation upgrade recommended.")[0] == "J1" | |
| def test_garage_before_roof_coverings(): | |
| sid, _, _ = classify_note_cascade("Garage roof pitched design with concrete tiles") | |
| assert sid == "G1" | |
| def test_chimney_repoint_before_wall_repoint(): | |
| sid, _, _ = classify_note_cascade("Chimney stack: Brick chimney with repointing required.") | |
| assert sid == "D1" | |
| def test_asbestos_in_garage_routes_i3_not_g1(): | |
| sid, _, _ = classify_note_cascade("Suspected chrysotile artex to ceiling in garage.") | |
| assert sid == "I3" | |
| def test_frontend_high_confidence_synced_with_backend(): | |
| """Frontend routing is delegated to POST /route-notes; lexicon lives in Python only.""" | |
| from backend.core.notes_high_confidence_lexicon import HIGH_CONFIDENCE_LEXICON | |
| html = Path("frontend/index.html").read_text(encoding="utf-8") | |
| assert "/route-notes" in html | |
| assert "highConfidence" not in html | |
| assert len(HIGH_CONFIDENCE_LEXICON) >= 50 | |
| def test_lexicon_covers_all_canonical_leaf_groups(): | |
| """Every parent section AβN has at least one P2 entry.""" | |
| parents = {sid[0] for sid, _ in HIGH_CONFIDENCE_LEXICON} | |
| assert parents == set("ABCDEFGHIJKLMN") | |