slice 14i: pin real RdSAP cert as fixture + RED regression test

Currently fails on SapWindow.glazing_gap (first of ~30 fields the dataclass
incorrectly treats as required). Will go GREEN once 14j sweeps Optional.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-16 20:23:29 +00:00
parent 611c07de94
commit ccb654c230
2 changed files with 331 additions and 0 deletions

View file

@ -0,0 +1,309 @@
{
"uprn": 0,
"roofs": [
{
"description": "(another dwelling above)",
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"walls": [
{
"description": "Solid brick, as built, no insulation (assumed)",
"energy_efficiency_rating": 1,
"environmental_efficiency_rating": 1
}
],
"floors": [
{
"description": "Solid, no insulation (assumed)",
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"status": "entered",
"tenure": 1,
"window": {
"description": "Fully double glazed",
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"lighting": {
"description": "Excellent lighting efficiency",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
},
"postcode": "SE22 9QF",
"hot_water": {
"description": "From main system",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"post_town": "LONDON",
"built_form": "NR",
"created_at": "2026-03-10 00:03:32",
"door_count": 1,
"region_code": 17,
"report_type": 2,
"sap_heating": {
"number_baths": 1,
"cylinder_size": 1,
"number_baths_wwhrs": 0,
"water_heating_code": 901,
"water_heating_fuel": 26,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"fan_flue_present": "Y",
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 17973
}
],
"immersion_heating_type": "NA",
"has_fixed_air_conditioning": "false"
},
"sap_version": 10.2,
"sap_windows": [
{
"pvc_frame": "true",
"orientation": 5,
"window_type": 1,
"glazing_type": 2,
"window_width": 1.09,
"window_height": 1.75,
"draught_proofed": "true",
"window_location": 0,
"window_wall_type": 1,
"permanent_shutters_present": "N",
"permanent_shutters_insulated": "N"
},
{
"pvc_frame": "true",
"orientation": 5,
"window_type": 1,
"glazing_type": 2,
"window_width": 0.99,
"window_height": 0.89,
"draught_proofed": "true",
"window_location": 0,
"window_wall_type": 1,
"permanent_shutters_present": "N",
"permanent_shutters_insulated": "N"
},
{
"pvc_frame": "true",
"orientation": 3,
"window_type": 1,
"glazing_type": 2,
"window_width": 0.7,
"window_height": 0.7,
"draught_proofed": "true",
"window_location": 0,
"window_wall_type": 1,
"permanent_shutters_present": "N",
"permanent_shutters_insulated": "N"
}
],
"schema_type": "RdSAP-Schema-21.0.1",
"uprn_source": "Address Matched",
"country_code": "ENG",
"main_heating": [
{
"description": "Boiler and radiators, mains gas",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"air_tightness": {
"description": "(not tested)",
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"dwelling_type": "Ground-floor flat",
"language_code": 1,
"pressure_test": 4,
"property_type": 2,
"address_line_1": "<scrubbed>",
"address_line_2": "<scrubbed>",
"assessment_type": "RdSAP",
"completion_date": "2026-03-10",
"inspection_date": "2026-03-05",
"extensions_count": 0,
"measurement_type": 1,
"sap_flat_details": {
"level": 1,
"top_storey": "N",
"storey_count": 4,
"flat_location": 0,
"heat_loss_corridor": 0
},
"total_floor_area": 27,
"transaction_type": 1,
"conservatory_type": 1,
"heated_room_count": 1,
"registration_date": "2026-03-10",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 2,
"pv_connection": 0,
"photovoltaic_supply": {
"none_or_no_details": {
"percent_roof_area": 0
}
},
"wind_turbines_count": 0,
"gas_smart_meter_present": "false",
"is_dwelling_export_capable": "false",
"wind_turbines_terrain_type": 2,
"electricity_smart_meter_present": "false"
},
"secondary_heating": {
"description": "None",
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"extract_fans_count": 1,
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"floor_heat_loss": 7,
"roof_construction": 3,
"wall_construction": 3,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {
"value": 2.4,
"quantity": "metres"
},
"floor_insulation": 1,
"total_floor_area": {
"value": 26.78,
"quantity": "square metres"
},
"party_wall_length": {
"value": 10.52,
"quantity": "metres"
},
"floor_construction": 1,
"heat_loss_perimeter": {
"value": 10.52,
"quantity": "metres"
}
}
],
"wall_insulation_type": 4,
"construction_age_band": "A",
"party_wall_construction": 0,
"wall_thickness_measured": "N",
"roof_insulation_location": "ND",
"roof_insulation_thickness": "ND",
"wall_insulation_thickness": "NI",
"floor_insulation_thickness": "NI"
}
],
"solar_water_heating": "N",
"habitable_room_count": 1,
"heating_cost_current": {
"value": 355,
"currency": "GBP"
},
"insulated_door_count": 0,
"co2_emissions_current": 1.1,
"energy_rating_average": 60,
"energy_rating_current": 71,
"lighting_cost_current": {
"value": 22,
"currency": "GBP"
},
"main_heating_controls": [
{
"description": "Programmer, room thermostat and TRVs",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"has_hot_water_cylinder": "false",
"heating_cost_potential": {
"value": 228,
"currency": "GBP"
},
"hot_water_cost_current": {
"value": 128,
"currency": "GBP"
},
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {
"value": 91,
"currency": "GBP"
},
"indicative_cost": "\u00a37,500 - \u00a311,000",
"improvement_type": "Q",
"improvement_details": {
"improvement_number": 7
},
"improvement_category": 5,
"energy_performance_rating": 76,
"environmental_impact_rating": 83
},
{
"sequence": 2,
"typical_saving": {
"value": 34,
"currency": "GBP"
},
"indicative_cost": "\u00a35,000 - \u00a310,000",
"improvement_type": "W2",
"improvement_details": {
"improvement_number": 58
},
"improvement_category": 5,
"energy_performance_rating": 77,
"environmental_impact_rating": 85
}
],
"co2_emissions_potential": 0.7,
"energy_rating_potential": 77,
"lighting_cost_potential": {
"value": 22,
"currency": "GBP"
},
"schema_version_original": "21.0.1",
"hot_water_cost_potential": {
"value": 131,
"currency": "GBP"
},
"renewable_heat_incentive": {
"water_heating": 1653.36,
"space_heating_existing_dwelling": 2797.73
},
"draughtproofed_door_count": 1,
"energy_consumption_current": 229,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "5.02r0334",
"energy_consumption_potential": 148,
"environmental_impact_current": 77,
"current_energy_efficiency_band": "C",
"environmental_impact_potential": 85,
"led_fixed_lighting_bulbs_count": 5,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "C",
"co2_emissions_current_per_floor_area": 41,
"incandescent_fixed_lighting_bulbs_count": 0
}

View file

@ -378,3 +378,25 @@ class TestRdSapSchema21_0_1:
def test_incandescent_bulb_count(self, epc: RdSapSchema21_0_1) -> None:
assert epc.incandescent_fixed_lighting_bulbs_count == 0
class TestRdSapSchema21_0_1AgainstRealApiCert:
"""Regression guard: a real cert (PII-scrubbed) from the gov bulk JSON must parse.
Previously the dataclass was driven by the synthetic `21_0_1.json` fixture, which
coincidentally contained every optional field. Real-API certs omit many of them,
so the dataclass annotations have to allow Optional/missing on those fields.
This test fails the moment a now-Optional field is accidentally re-marked required.
"""
def test_real_cert_parses_via_from_dict(self) -> None:
# Arrange
real_doc = load("21_0_1_real.json")
# Act
epc = from_dict(RdSapSchema21_0_1, real_doc)
# Assert
assert epc.schema_type == "RdSAP-Schema-21.0.1"
assert epc.sap_heating is not None
assert len(epc.sap_windows) > 0