Capture the Simplified RIR 'Roof room type' label from the survey 🟥

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-15 08:25:11 +00:00
parent 948704d7b0
commit 600262819c
2 changed files with 90 additions and 0 deletions

View file

@ -985,6 +985,92 @@ class TestRoofSpaceRoomInRoof:
assert rir.flat_ceilings is not None
assert [f.insulation_known for f in rir.flat_ceilings] == [False]
# The Simplified-approach RIR block ("Are details of the room in roof
# known? No" → "Roof room type: RR type 2"), gables + common walls only,
# no slopes/flat ceilings. Verbatim from accuracy fixture 499538003156
# (78 North Road), including the mid-block "Page 8" break and the noise
# lines the surveyor tool interleaves between a key and its value.
_RIR_SIMPLIFIED_TYPE2_BLOCK = [
"Are there rooms in the roof?",
"Yes",
"Roof room age range:",
"C: 1930 - 1949",
"Floor area of room in roof:",
"25.43 m²",
"Are details of the room in roof known?",
"No",
"Roof room type:",
"RR type 2 (With the Accessible areas of continuous common walls)",
"Gable wall 1 length:",
"5.82 m",
"Gable wall 1 height:",
"2.72 m",
"Gable wall 1 type:",
"Party",
"Gable wall 2 length:",
"5.82 m",
"Gable wall 2 height:",
"2.72 m",
"Gable wall 2 type:",
"Party",
"Common wall 1 length:",
"4.37 m",
"Page 8",
"",
"Common wall 1 height:",
"2.34 m",
"Common wall 2 length:",
"4.37 m",
"Common wall 2 height:",
"2.34 m",
]
def test_roof_room_type_label_is_captured(self) -> None:
# Arrange — fixture 1's roof space with the Simplified RIR block
# spliced in place of its "rooms in the roof? No" lodging.
lines = load_text_fixture()
idx = lines.index("Are there rooms in the roof?")
spliced = lines[:idx] + self._RIR_SIMPLIFIED_TYPE2_BLOCK + lines[idx + 2 :]
# Act
rir = (
PasHubRdSapSiteNotesExtractor(spliced)
.extract_roof_space()
.main_building.room_in_roof
)
# Assert
assert rir is not None
assert (
rir.roof_room_type
== "RR type 2 (With the Accessible areas of continuous common walls)"
)
# Simplified lodgement: gables + common walls, no roof-going surfaces.
assert rir.slopes is None
assert rir.flat_ceilings is None
assert rir.common_walls == [
RoomInRoofSurfaceDetail(length_m=4.37, height_m=2.34),
RoomInRoofSurfaceDetail(length_m=4.37, height_m=2.34),
]
def test_detailed_lodgement_has_no_roof_room_type(self) -> None:
# Arrange — the Detailed §3.10 block (slopes/flat ceilings lodged)
# never carries a "Roof room type:" line.
lines = load_text_fixture()
idx = lines.index("Are there rooms in the roof?")
spliced = lines[:idx] + self._RIR_BLOCK + lines[idx + 2 :]
# Act
rir = (
PasHubRdSapSiteNotesExtractor(spliced)
.extract_roof_space()
.main_building.room_in_roof
)
# Assert
assert rir is not None
assert rir.roof_room_type is None
def test_no_rooms_in_roof_leaves_detail_absent(self) -> None:
# Arrange / Act — fixture 1 as lodged ("No").
detail = PasHubRdSapSiteNotesExtractor(

View file

@ -138,6 +138,10 @@ class RoomInRoofDetail:
slopes: Optional[List[RoomInRoofSurfaceDetail]] = None
common_walls: Optional[List[RoomInRoofSurfaceDetail]] = None
flat_ceilings: Optional[List[RoomInRoofSurfaceDetail]] = None
# The "Roof room type:" label, lodged only on the Simplified approach
# ("Are details of the room in roof known? No" → RdSAP §3.9.2 Type 1/2/3).
# None on a Detailed §3.10 lodgement (per-surface slopes/flat ceilings).
roof_room_type: Optional[str] = None
@dataclass