Skip to content

Commit 37bef99

Browse files
anth-volkclaude
andcommitted
Merge origin/master into uk-local-area-breakdown
Brings in #4026 (raise the economy cache schema version from 3 to 4) and the 5.7.0 "Update PolicyEngine API" release commit. Conflicts: - tests/unit/services/test_reform_impacts_service.py: both sides added a new test at the end of the file. This branch added test_a_briefly_kept_error_expires_and_leaves_other_records; master added test_impact_cached_under_previous_economy_schema_version_is_not_matched. Kept both, this branch's test first. The imports master added for its test (constants, get_economy_impact_cache_version) merged without conflict. Merged without conflict, checked by hand: - policyengine_api/constants.py: RUNTIME_CACHE_SCHEMA_VERSIONS ["economy_impact"] is 4 (master), and UK_COUNTRY_REGIONS, UK_REGION_REGISTRY_CODES and LOCAL_AREA_BREAKDOWN_REGIONS are kept (this branch). - pyproject.toml: package version 5.7.0 (master) and the policyengine[models]==6.10.0 pin (this branch). - uv.lock: policyengine-api 5.7.0 (master) with this branch's .py 6.10.0 dependency set (policyengine 6.10.0, policyengine-core 3.33.3, policyengine-uk 2.132.6). `uv lock --check` passes. - tests/unit/test_constants.py: both sides' additions kept. - CHANGELOG.md and changelog.d/: master's 5.7.0 entry and its removal of the released remove-economy-comparison fragment, plus master's economy-cache-decile-fractions fragment; this branch's fragments are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 parents 7cdf9f5 + a4bd9d3 commit 37bef99

8 files changed

Lines changed: 95 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## [5.7.0] - 2026-10-22
2+
3+
### Removed
4+
5+
- Removed the unused economy comparison module (`policyengine_api/services/economy_comparison.py`) with its tests and snapshot data. Nothing has called it since the Public API stopped falling back to its own society-wide simulations (#2569); the route-boundary rule now covers the calculation route alone.
6+
7+
18
## [5.6.4] - 2026-10-21
29

310
### Changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Raised the economy result cache schema version from 3 to 4, so economy results cached while the simulation API returned decile and UK wealth decile relative changes as percentages (x100) instead of fractions are no longer served, and are recomputed on the next request. Budget-window results share this cache version, so they are recomputed too.

‎changelog.d/remove-economy-comparison.removed.md‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎policyengine_api/constants.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,13 @@ def get_bundle_default_dataset_option(country_id: str) -> dict:
194194
) or _resolve_distribution_version(_dist_versions, "policyengine-core", "policyengine")
195195

196196
RUNTIME_CACHE_SCHEMA_VERSIONS = {
197-
"economy_impact": 3,
197+
# 4: economy results cached under 3 can hold decile.relative and the UK
198+
# wealth_decile.relative as percentages (x100) instead of fractions, from
199+
# the simulation API (PolicyEngine/policyengine-sim-api#827). Economy cache
200+
# keys do not change when only the simulation API's code changes, so this
201+
# version was raised to stop serving those results. The budget-window
202+
# cache key uses the same version.
203+
"economy_impact": 4,
198204
"report_output": 3,
199205
}
200206
# Runtime cache versions are stored in legacy VARCHAR(10) columns, and keep at

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "policyengine-api"
7-
version = "5.6.4"
7+
version = "5.7.0"
88
description = "PolicyEngine API"
99
readme = "README.md"
1010
license = "AGPL-3.0-only"

‎tests/unit/services/test_reform_impacts_service.py‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import pytest
55

6+
from policyengine_api import constants
7+
from policyengine_api.constants import get_economy_impact_cache_version
68
from policyengine_api.runtime_cache.core import CacheNamespace
79
from policyengine_api.runtime_cache.fake import InMemoryCacheBackend
810
from policyengine_api.runtime_cache.reform_impacts import (
@@ -226,3 +228,58 @@ def test_a_briefly_kept_error_expires_and_leaves_other_records() -> None:
226228
assert [(impact.execution_id, impact.status) for impact in after_expiry] == [
227229
("next-job", "computing")
228230
]
231+
232+
233+
def test_impact_cached_under_previous_economy_schema_version_is_not_matched(
234+
service,
235+
):
236+
# Economy results cached under schema version 3 can hold decile relative
237+
# changes as percentages (x100) from the simulation API
238+
# (PolicyEngine/policyengine-sim-api#827). A lookup built from the
239+
# current cache version must not find them.
240+
current_cache_version = get_economy_impact_cache_version(SCOPE.country_id)
241+
with pytest.MonkeyPatch.context() as schema_version_patch:
242+
schema_version_patch.setitem(
243+
constants.RUNTIME_CACHE_SCHEMA_VERSIONS, "economy_impact", 3
244+
)
245+
percentage_decile_cache_version = get_economy_impact_cache_version(
246+
SCOPE.country_id
247+
)
248+
249+
options_hash = "decile-hash"
250+
stale_identity = ReformImpactIdentity(
251+
scope=SCOPE,
252+
api_version=percentage_decile_cache_version,
253+
options_hash=options_hash,
254+
)
255+
service.set_reform_impact(
256+
stale_identity,
257+
ReformImpactExecution(
258+
execution_id="percentage-decile-job",
259+
start_time=datetime(2026, 7, 1),
260+
),
261+
options={"hash": options_hash},
262+
status="computing",
263+
reform_impact_json={},
264+
)
265+
service.set_complete_reform_impact(
266+
"percentage-decile-job",
267+
reform_impact_json={"decile": {"relative": {"1": 1.5}}},
268+
)
269+
270+
current_identity = ReformImpactIdentity(
271+
scope=SCOPE,
272+
api_version=current_cache_version,
273+
options_hash=options_hash,
274+
)
275+
276+
assert [
277+
impact.execution_id for impact in service.get_all_reform_impacts(stale_identity)
278+
] == ["percentage-decile-job"]
279+
assert service.get_all_reform_impacts(current_identity) == []
280+
assert (
281+
service.get_all_reform_impacts_by_options_hash_prefix(
282+
current_identity, f"{options_hash}%"
283+
)
284+
== []
285+
)

‎tests/unit/test_constants.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
POLICYENGINE_CORE_VERSION,
1010
POLICYENGINE_VERSION,
1111
REGION_PREFIXES,
12+
RUNTIME_CACHE_SCHEMA_VERSIONS,
13+
RUNTIME_CACHE_VERSION_LENGTH,
1214
UK_REGION_TYPES,
1315
US_REGION_TYPES,
1416
_bundle_dataset_display_label,
1517
_load_policyengine_bundle,
1618
_normalize_distribution_name,
1719
_resolve_distribution_version,
20+
get_economy_impact_cache_version,
1821
get_py_manifest,
1922
)
2023

@@ -113,6 +116,24 @@ def test__has_exactly_three_prefixes(self):
113116
assert len(REGION_PREFIXES["us"]) == 3
114117

115118

119+
class TestEconomyImpactCacheVersion:
120+
# Since its move to .py 4.x, the simulation API returned decile.relative
121+
# and the UK wealth_decile.relative as percentages (x100) instead of
122+
# fractions (PolicyEngine/policyengine-sim-api#827). Economy results
123+
# cached under schema version 3 can hold those values, and the cache key
124+
# does not change when the simulation API's code does, so version 4 makes
125+
# every economy cache lookup miss them and recompute.
126+
def test__economy_impact_schema_version_is_4(self):
127+
assert RUNTIME_CACHE_SCHEMA_VERSIONS["economy_impact"] == 4
128+
129+
@pytest.mark.parametrize("country_id", ["us", "uk"])
130+
def test__economy_impact_cache_version_carries_schema_version_4(self, country_id):
131+
cache_version = get_economy_impact_cache_version(country_id)
132+
133+
assert cache_version.startswith("e4")
134+
assert len(cache_version) == RUNTIME_CACHE_VERSION_LENGTH
135+
136+
116137
class TestDistributionVersionHelpers:
117138
def test__normalize_distribution_name(self):
118139
assert _normalize_distribution_name("policyengine_core") == (

‎uv.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)