diff --git a/tests/domain/modelling/test_solar_config_selection.py b/tests/domain/modelling/test_solar_config_selection.py index 53b6dca18..6aae14dd9 100644 --- a/tests/domain/modelling/test_solar_config_selection.py +++ b/tests/domain/modelling/test_solar_config_selection.py @@ -304,3 +304,47 @@ def test_sub_ladder_rungs_fill_from_the_highest_yield_segment_first() -> None: (225.0, 2), (135.0, 1), } + + +def test_sub_ladder_rungs_never_take_from_north_planes() -> None: + # ADR-0058 — derivation starts from the north-dropped remainder: a north + # plane never contributes panels to a Sub-Ladder rung, even when its + # per-panel yield would win the fill-by-generation ordering. + + # Arrange — smallest rung = a due-north panel (900/panel, best yield) plus + # a south plane (4 panels, 1278); max 5 → cap 3.5; after the north drop + # the 4-panel south remainder still exceeds the cap → Sub-Ladder fires. + north = SolarRoofSegment( + segment_index=0, + panels_count=1, + azimuth_degrees=2.0, + pitch_degrees=30.0, + yearly_energy_dc_kwh=900.0, + ) + south = SolarRoofSegment( + segment_index=1, + panels_count=4, + azimuth_degrees=180.0, + pitch_degrees=30.0, + yearly_energy_dc_kwh=1278.0, + ) + potential = SolarPotential( + panel_capacity_watts=400.0, + max_array_panels_count=5, + configurations=( + SolarPanelConfiguration( + panels_count=5, + yearly_energy_dc_kwh=2178.0, + segments=(north, south), + ), + ), + ) + + # Act + configs = select_conservative_configs(potential) + + # Assert — rungs 2 and 3 built from the south plane alone, pro-rata off + # its 1278 (639 / 958.5); the 900-yield north panel never appears. + assert [c.panels_count for c in configs] == [2, 3] + assert [c.yearly_energy_dc_kwh for c in configs] == [639.0, 958.5] + assert all(s.azimuth_degrees == 180.0 for c in configs for s in c.segments)