From 90b95652f013fbcd113da8597f5506bd58cbacbe Mon Sep 17 00:00:00 2001 From: Guillermo Montero Date: Thu, 17 Sep 2026 19:04:01 +0200 Subject: [PATCH] fix(policy): warn when scm.max_parallel is silently clamped to 1 --- CHANGELOG.md | 3 +++ src/bmad_loop/policy.py | 8 ++++++++ tests/test_policy.py | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5259aee07..fdf3dbbc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -167,6 +167,9 @@ breaking changes may land in a minor release. ### Changed +- bmad-loop now warns when scm.max_parallel > 1 is configured, since parallel fan-out + is not yet built and the value is clamped to 1. + - **`bmad-loop diagnose --json` reports `schema_version: 4`.** Journal `path` values become `path_present`; stale-restore and merge filename lists become counts. diff --git a/src/bmad_loop/policy.py b/src/bmad_loop/policy.py index 63c10f99f..55a2322e5 100644 --- a/src/bmad_loop/policy.py +++ b/src/bmad_loop/policy.py @@ -1061,6 +1061,14 @@ def loads(text: str, plugin_schemas: dict[str, Any] | None = None) -> Policy: requested_parallel = _typed_int(scm_d, "scm", "max_parallel", ScmPolicy.max_parallel) if requested_parallel < 1: raise PolicyError(f"scm.max_parallel must be >= 1: got {requested_parallel}") + if requested_parallel > 1: + warnings.warn( + f"scm.max_parallel = {requested_parallel} is configured, but parallel " + "fan-out (Phase 5) is not built yet: the value is clamped to 1 and has " + "no effect (see #229).", + UserWarning, + stacklevel=3, + ) # This one was strict before its sibling int knobs were (a TOML `true`, with # int(True) == 1, or a `1.9` coercing through int() would silently shrink a # safety-net budget); `_typed_int` is that same guard, message included. diff --git a/tests/test_policy.py b/tests/test_policy.py index b3321724d..5a24bb18c 100644 --- a/tests/test_policy.py +++ b/tests/test_policy.py @@ -1132,6 +1132,24 @@ def test_scm_max_parallel_clamped_to_one(tmp_path): policy.load(p) +def test_scm_max_parallel_above_one_warns(): + """Phase 5 parallel fan-out (#229) is unbuilt, so a configured value > 1 is + still silently inert without this warning -- an operator setting + ``max_parallel = 4`` would otherwise get no signal that it has no effect. + + Ablation: delete the ``requested_parallel > 1`` warning block in ``loads()``; + this test fails because no warning fires while the clamp still applies.""" + with pytest.warns(UserWarning, match=r"scm\.max_parallel"): + loaded = policy.loads("[scm]\nmax_parallel = 4\n") + assert loaded.scm.max_parallel == 1 + + +def test_scm_max_parallel_equal_to_one_does_not_warn(recwarn): + loaded = policy.loads("[scm]\nmax_parallel = 1\n") + assert loaded.scm.max_parallel == 1 + assert len(recwarn) == 0 + + def test_scm_preserve_keep_settings(tmp_path): p = tmp_path / "policy.toml" p.write_text("[scm]\npreserve_keep = 5\n")