diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f3bcb9e..cfa949a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and the project (informally) follows [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Dependencies — lift the pypowsybl upper bound + +- **`pypowsybl` is no longer capped below 1.15** (`pyproject.toml`). The earlier + `>=1.13.0,<1.15` pin assumed pypowsybl 1.15 shifted the + `test_independent_actions_simulation` flow deltas beyond the committed + baseline's ±1 MW tolerance (PR #99). Re-verified against pypowsybl 1.14, 1.15 + and 1.16 on the small test grid: all three reproduce + `expert_backend/tests/baseline_scenario.json` within tolerance (max abs delta + 0.0 MW, no COUCHY632 Q sign-flip), so the baseline needs no regeneration and + the constraint is now `pypowsybl>=1.13.0`. The floor stays at 1.13.0 because + the oldest supported pypowsybl also bounds the IIDM schema the shipped game + networks may use (`scripts/game_mode/test_rte7000_game_mode.py`). + ### Game Mode — France THT difficulty-graded scenario family - **New scenario family on the opening screen** — a top-level **Mode** choice diff --git a/pyproject.toml b/pyproject.toml index fe2f40ed..ce811bb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,13 +19,16 @@ classifiers = [ ] dependencies = [ "ExpertOp4Grid>=0.3.2.post1", - # Pinned below 1.15 until the test baseline - # (`expert_backend/tests/baseline_scenario.json`) is regenerated with - # the newer solver. pypowsybl 1.15.0 shifts both P (~±2.6 MW) and Q - # (sign-flipping +1.8 → −10.2 Mvar on COUCHY632) on double-busbar - # node_merging actions, breaking the ±1 MW tolerance of - # `test_independent_actions_simulation`. See PR #99 discussion. - "pypowsybl>=1.13.0,<1.15", + # No upper bound. The earlier `<1.15` cap assumed pypowsybl 1.15 shifted the + # `test_independent_actions_simulation` deltas beyond the ±1 MW tolerance of + # the committed baseline (`expert_backend/tests/baseline_scenario.json`, see + # PR #99). Re-verified since: pypowsybl 1.14 / 1.15 / 1.16 all reproduce that + # baseline within tolerance (max abs delta 0.0 MW on the small test grid, no + # COUCHY632 Q sign-flip), so the drift no longer applies and the cap is + # lifted. Floor kept at 1.13.0 — the oldest supported pypowsybl also bounds + # the IIDM schema the shipped game networks may use (see + # scripts/game_mode/test_rte7000_game_mode.py). + "pypowsybl>=1.13.0", "pypowsybl_jupyter", "pydantic-settings", "uv", diff --git a/scripts/game_mode/test_rte7000_game_mode.py b/scripts/game_mode/test_rte7000_game_mode.py index 6f33e5c8..37ca9842 100644 --- a/scripts/game_mode/test_rte7000_game_mode.py +++ b/scripts/game_mode/test_rte7000_game_mode.py @@ -92,10 +92,11 @@ def test_every_grid_ships_a_decodable_network(): def test_network_iidm_version_is_readable_by_the_pinned_pypowsybl(): - """The networks must serialise at an IIDM schema the deployed pypowsybl can - read. pyproject pins pypowsybl>=1.13,<1.15, and pypowsybl 1.14 rejects - IIDM 1.16 ("Unsupported file format") — so the shipped transports must be - IIDM <= 1.14. Guards against re-shipping a network exported by a newer + """The networks must serialise at an IIDM schema every supported pypowsybl + can read. pyproject floors pypowsybl at >=1.13 (no upper bound), and + pypowsybl 1.13 / 1.14 reject IIDM 1.16 ("Unsupported file format") — so the + shipped transports must be IIDM <= 1.14 to stay readable across the whole + supported range. Guards against re-shipping a network exported by a newer pypowsybl (which defaults to 1.16).""" import re max_major, max_minor = 1, 14 @@ -105,8 +106,8 @@ def test_network_iidm_version_is_readable_by_the_pinned_pypowsybl(): assert m, f"no IIDM version in {enc.parent.name}/network.xiidm" major, minor = int(m.group(1)), int(m.group(2)) assert (major, minor) <= (max_major, max_minor), ( - f"{enc.parent.name}: IIDM {major}.{minor} > 1.14 — the pinned " - f"pypowsybl (<1.15) cannot read it; re-export with " + f"{enc.parent.name}: IIDM {major}.{minor} > 1.14 — the oldest " + f"supported pypowsybl (>=1.13) cannot read it; re-export with " f"parameters={{'iidm.export.xml.version': '1.14'}}")