Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
8 changes: 8 additions & 0 deletions src/bmad_loop/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 18 additions & 0 deletions tests/test_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down