From 130087a556bf4d2795dc9b280905a3cbb0120a68 Mon Sep 17 00:00:00 2001 From: ctan Date: Sun, 20 Sep 2026 17:15:29 +0200 Subject: [PATCH] fix(map): reject a zones layer without a deployment section The README documents deployment as required when zones exist, but load_map only enforced the reverse direction (deployment without zones). A map with a zones layer and no deployment now fails with MapValidationError instead of loading with unreachable deployment zones. --- src/pf1e_simulator/map.py | 7 +++++++ tests/test_map.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/pf1e_simulator/map.py b/src/pf1e_simulator/map.py index 95f6fe0..444c888 100644 --- a/src/pf1e_simulator/map.py +++ b/src/pf1e_simulator/map.py @@ -131,6 +131,13 @@ def _check_deployment( deployment: dict[str, str], zones: tuple[str, ...] | None, path: Path ) -> None: if not deployment: + if zones is not None: + msg = ( + "zones layer declared but no deployment section (the README " + "requires deployment when zones exist: each zone letter needs " + "a side)" + ) + raise MapValidationError(path, msg) return if zones is None: msg = "deployment declared but no zones layer" diff --git a/tests/test_map.py b/tests/test_map.py index d89793d..51a3cbc 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -111,6 +111,12 @@ def test_rejects_deployment_without_zone(tmp_path: Path) -> None: load_map(_write(tmp_path, body)) +def test_rejects_zones_without_deployment(tmp_path: Path) -> None: + body = _minimal_map() + "zones: |\n ...\n .A.\n ...\n" + with pytest.raises(MapValidationError, match="no deployment section"): + load_map(_write(tmp_path, body)) + + def test_rejects_shared_deployment_zone_letter(tmp_path: Path) -> None: """Two sides bound to the same zone letter would deploy on top of each other (build_states resets its placed set per side): a data error."""