Enforce population estimate wording
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-16 04:00:20 +02:00
parent d0210b9a3c
commit a280de8838
4 changed files with 45 additions and 1 deletions
+2
View File
@@ -26,6 +26,8 @@
- Added deterministic semantic rounding for model context and normalized model - Added deterministic semantic rounding for model context and normalized model
Markdown to the existing plain-text renderer so hectare, population and Markdown to the existing plain-text renderer so hectare, population and
score answers remain readable without exposing raw floating-point tails. score answers remain readable without exposing raw floating-point tails.
- Prevented an area-weighted population estimate from retaining model phrases
such as "official count" when its persisted metric is marked as estimated.
## Sprint 213-214 Cross-domain area profile (2026-07-16) ## Sprint 213-214 Cross-domain area profile (2026-07-16)
+15 -1
View File
@@ -108,13 +108,27 @@ class GeoAssistantService:
answer: str, answer: str,
metrics: list[AssistantContextMetric], metrics: list[AssistantContextMetric],
) -> str: ) -> str:
estimated_themes = {metric.theme for metric in metrics if metric.is_estimate}
if "population" in estimated_themes:
answer = re.sub(
r"\bde officiële telling\b",
"de van de officiële bron afgeleide schatting",
answer,
flags=re.IGNORECASE,
)
answer = re.sub(
r"\bofficieel geteld aantal inwoners\b",
"uit een officiële bron afgeleid aantal inwoners",
answer,
flags=re.IGNORECASE,
)
normalized = answer.casefold() normalized = answer.casefold()
if "schat" in normalized: if "schat" in normalized:
return answer return answer
disclosed_themes = { disclosed_themes = {
metric.theme metric.theme
for metric in metrics for metric in metrics
if metric.is_estimate if metric.theme in estimated_themes
and any( and any(
term in normalized term in normalized
for term in cls.ESTIMATE_TOPIC_TERMS.get(metric.theme, (metric.label.casefold(),)) for term in cls.ESTIMATE_TOPIC_TERMS.get(metric.theme, (metric.label.casefold(),))
@@ -144,6 +144,28 @@ def test_geo_assistant_discloses_estimated_population_values() -> None:
) )
def test_geo_assistant_never_labels_area_weighted_population_as_official_count() -> None:
metrics = [
AssistantContextMetric(
theme="population",
label="Geraamd aantal inwoners",
value=38_675,
unit="inwoners",
source="Statbel",
dataset_id=uuid4(),
is_estimate=True,
)
]
answer = GeoAssistantService.ensure_estimate_disclosure(
"De officiële telling uit januari 2025 bedraagt 38.675 inwoners. Deze waarde is een schatting.",
metrics,
)
assert "officiële telling" not in answer.casefold()
assert answer.startswith("de van de officiële bron afgeleide schatting")
def test_geo_assistant_does_not_add_irrelevant_estimate_disclosure() -> None: def test_geo_assistant_does_not_add_irrelevant_estimate_disclosure() -> None:
metrics = [ metrics = [
AssistantContextMetric( AssistantContextMetric(
+6
View File
@@ -20,6 +20,10 @@ Changed:
Markdown and raw floating-point tails in the plain-text chat renderer. Added Markdown and raw floating-point tails in the plain-text chat renderer. Added
deterministic Markdown normalization and unit-aware context rounding while deterministic Markdown normalization and unit-aware context rounding while
retaining the unrounded metrics in the canonical API response. retaining the unrounded metrics in the canonical API response.
- The next live answer still called an area-weighted Statbel population value
an official count before acknowledging it as an estimate. The deterministic
estimate guard now removes that contradictory label whenever persisted
population context is estimated.
Validation evidence: Validation evidence:
- A read-only live production-chain probe with the 1,200-token setting - A read-only live production-chain probe with the 1,200-token setting
@@ -33,6 +37,8 @@ Validation evidence:
shell gates. shell gates.
- After plain-text normalization and semantic prompt rounding, the final - After plain-text normalization and semantic prompt rounding, the final
readiness rerun passed 725 backend tests and the same complete gate set. readiness rerun passed 725 backend tests and the same complete gate set.
- After hardening estimated-population wording, the final complete readiness
rerun passed 726 backend tests and all remaining gates unchanged.
- The regional thematic operator dry-run resolved exactly 28 official - The regional thematic operator dry-run resolved exactly 28 official
municipality Areas. The live Mol run in `Kempen Regional Workbench` imported municipality Areas. The live Mol run in `Kempen Regional Workbench` imported
all five products with complete source coverage; the DOV operator imported all five products with complete source coverage; the DOV operator imported