RICS / app /tests /test_notes_router.py
StormShadow308's picture
Speed up generation and ingestion; add live report progress on /status.
c893230
Raw
History Blame Contribute Delete
2.82 kB
"""Tests for messy-notes routing into per-section RICS buckets.
These tests pin the deterministic keyword router (no LLM). The router has
to be reliable offline because the front-end calls it on every upload, and
the LLM refinement pass is opt-in.
"""
from __future__ import annotations
import pytest
from app.generator.notes_router import route_notes
@pytest.mark.asyncio
async def test_route_explicit_section_code_wins() -> None:
lines = ["E2: tiles slipped on north pitch"]
out = await route_notes(lines, survey_level=3)
assert out.bullets_by_section.get("E2") == ["E2: tiles slipped on north pitch"]
@pytest.mark.asyncio
async def test_route_roof_keywords_to_E2() -> None:
lines = ["several roof tiles slipped at the ridge"]
out = await route_notes(lines, survey_level=3)
assert "E2" in out.bullets_by_section
assert any("tiles slipped" in b for b in out.bullets_by_section["E2"])
@pytest.mark.asyncio
async def test_route_boiler_to_G2() -> None:
lines = ["boiler 18 years old, no recent service certificate"]
out = await route_notes(lines, survey_level=3)
assert "G2" in out.bullets_by_section
@pytest.mark.asyncio
async def test_route_damp_to_F9() -> None:
lines = ["rising damp visible at rear hallway skirting"]
out = await route_notes(lines, survey_level=3)
# damp is the F9 primary signal; skirting also touches F7 — confirm damp wins
assert "F9" in out.bullets_by_section
@pytest.mark.asyncio
async def test_route_unmatched_line_returned_in_unrouted() -> None:
lines = ["[surveyor signature on file]"]
out = await route_notes(lines, survey_level=3)
# Generic chatter that doesn't map cleanly to any section
assert out.unrouted_lines == lines or "__unrouted__" not in out.bullets_by_section
@pytest.mark.asyncio
async def test_route_mixed_dump_splits_across_sections() -> None:
lines = [
"tile slipped on rear pitch",
"gutters overflowing at front elevation",
"consumer unit pre-2008, no RCD",
"rising damp at rear hallway",
]
out = await route_notes(lines, survey_level=3)
codes = set(out.bullets_by_section.keys())
# Each of these should land in a distinct section
assert "E2" in codes # roof tile
assert "E3" in codes # gutters
assert "G1" in codes # consumer unit / RCD
assert "F9" in codes # damp
@pytest.mark.asyncio
async def test_route_respects_survey_level() -> None:
lines = ["roof tiles slipped"]
out_l1 = await route_notes(lines, survey_level=1)
out_l3 = await route_notes(lines, survey_level=3)
# Both packs have an E2-like roof section; the routing should succeed for both.
assert any(k.startswith("E") for k in out_l1.bullets_by_section)
assert any(k.startswith("E") for k in out_l3.bullets_by_section)