From 149d957248a85cf20cac2e8c2dd576f354a5e646 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 21 Jul 2026 10:02:44 +0000 Subject: [PATCH] =?UTF-8?q?Publish=20a=20half-point=20SAP=20rating=20round?= =?UTF-8?q?ed=20up=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- domain/sap10_calculator/worksheet/rating.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/domain/sap10_calculator/worksheet/rating.py b/domain/sap10_calculator/worksheet/rating.py index ca132479a..6ed2e73fd 100644 --- a/domain/sap10_calculator/worksheet/rating.py +++ b/domain/sap10_calculator/worksheet/rating.py @@ -20,6 +20,7 @@ Table 12 (page 191). from __future__ import annotations +from decimal import ROUND_HALF_UP, Decimal from math import log10 from typing import Final @@ -59,8 +60,14 @@ def sap_rating_integer(*, ecf: float) -> int: """SAP 10.2 §13: round the continuous SAP rating to the nearest integer and clamp to a minimum of 1 ("if the result of the calculation is less than 1 the rating should be quoted as 1"). The integer value is the - one published on the EPC.""" - return max(1, round(sap_rating(ecf=ecf))) + one published on the EPC. + + "Nearest" is half-UP, as everywhere else the spec rounds (see the mapper's + `_round_half_up_2dp`). Python's built-in `round` is half-to-EVEN and would + drop an exact x.5 to x for even x — at a band floor that publishes a whole + band low (a continuous 68.5 as SAP 68 / band D rather than 69 / band C).""" + rating: Decimal = Decimal(sap_rating(ecf=ecf)) + return max(1, int(rating.quantize(Decimal("1"), rounding=ROUND_HALF_UP))) def environmental_impact_rating(