Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 25s
u1 argparse --reuse-from PREV_RUN_ID + post-merge fail-closed guard (rejects
layout/zone_geometry/zone_section/image override axes by name; only
--override-frame is preserved).
u2 src/phase_z2_reuse_snapshot.py — JSON-only Step 6 snapshot with mdx_sha256
integrity key and {value, source_path, upstream_step} provenance per axis
(pickle forbidden per Stage 2 guardrail).
u3 _write_reuse_snapshot at the Step 6 boundary; soft-fails to stderr without
aborting the seed run.
u4 prev_run_dir RO copy of step00/01/02/05/06 + _reuse_snapshot.json into
new run_dir, state rehydration, reuse marker, frame-override application on
restored units, Step 7+ resume.
u4b fail-closed for missing prev_run_dir / missing/corrupt/invalid snapshot /
mdx_sha256 mismatch / accidental new==prev write, with value+path+upstream
diagnostics per axis.
u5 reuse_from Optional[str] threaded through run_phase_z2_mvp1 signature and
CLI dispatch; default None preserves byte-identical pre-IMP-43 behavior.
u6 Front /api/run optional reuseFromRunId forwarding (vite.config.ts +
designAgentApi.ts + run_pipeline_reuse_from.test.ts).
u7a fast CI equivalence (1 mdx × 1 layout × 2 frames); step13 whitelist =
run_id/timestamps/prev_run_id only. u7b 3 layouts × 3 mdx × 32 frames
sweep gated by pytest.mark.sweep (registered in pyproject.toml; default CI
must use -m 'not sweep').
u8 scripts/measure_reuse_savings.py argv-driven A/B/C harness with frame
pin self-discovery + seed-time exclusion; status board §8 TBD anchor
(issue-body 50-70% / 10-20s→3-8s claim explicitly unverified, not mirrored).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
384 lines
13 KiB
Python
384 lines
13 KiB
Python
"""IMP-43 (#72) u1 + u5 — focused tests for the ``--reuse-from`` CLI surface.
|
|
|
|
u1 scope (per the Stage 2 Exit Report):
|
|
|
|
- argparse flag ``--reuse-from PREV_RUN_ID`` parses without error.
|
|
- Fail-closed precondition guard runs AFTER the ``user_overrides.json``
|
|
merge and BEFORE dispatch. With ``--reuse-from`` set, the guard
|
|
must:
|
|
* accept frame-only overrides (or no overrides at all);
|
|
* reject layout / zone-geometry / zone-section / image overrides
|
|
with ``sys.exit(2)`` whose stderr names every rejected axis.
|
|
|
|
u5 scope (added 2026-05-24):
|
|
|
|
- ``reuse_from`` is keyword-only on ``run_phase_z2_mvp1`` and defaults
|
|
to ``None`` so the absent-flag path preserves pre-u5 behaviour.
|
|
- The CLI dispatch forwards ``args.reuse_from`` verbatim — both
|
|
``None`` (flag absent) and ``"PREV_RUN_ID"`` (flag present) reach
|
|
the kwarg unchanged.
|
|
- The fake ``run_phase_z2_mvp1`` stub below mirrors the production
|
|
signature so the forwarding lock would fail loudly on any
|
|
forwarding regression.
|
|
|
|
The harness mirrors ``tests/test_phase_z2_cli_overrides.py`` — the
|
|
``if __name__ == "__main__"`` block of ``src.phase_z2_pipeline`` is
|
|
exec'd inside the module's namespace after monkeypatching
|
|
``run_phase_z2_mvp1`` with a recording stub. The persistence fallback
|
|
is silenced by redirecting ``src.user_overrides_io.DEFAULT_OVERRIDES_ROOT``
|
|
to a clean tmp directory so persisted state from prior runs cannot bleed
|
|
into the parser-only assertions here.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
import src.phase_z2_pipeline as _pz2
|
|
import src.user_overrides_io as _io
|
|
|
|
|
|
# -- harness ---------------------------------------------------------------
|
|
|
|
|
|
def _exec_main_block(
|
|
captured: dict[str, Any], argv: list[str], monkeypatch
|
|
) -> None:
|
|
"""Run the ``__main__`` body of phase_z2_pipeline.py with a fake
|
|
``run_phase_z2_mvp1`` so its kwargs are observable. Captures the
|
|
presence of the call (``called=True``) so guard-driven early exits
|
|
can be distinguished from a successful parse + dispatch."""
|
|
|
|
def _fake_run(
|
|
mdx_path,
|
|
run_id,
|
|
*,
|
|
override_layout=None,
|
|
override_frames=None,
|
|
override_zone_geometries=None,
|
|
override_section_assignments=None,
|
|
override_image_overrides=None,
|
|
reuse_from=None,
|
|
):
|
|
captured["called"] = True
|
|
captured["mdx_path"] = mdx_path
|
|
captured["run_id"] = run_id
|
|
captured["override_layout"] = override_layout
|
|
captured["override_frames"] = override_frames
|
|
captured["override_zone_geometries"] = override_zone_geometries
|
|
captured["override_section_assignments"] = override_section_assignments
|
|
captured["override_image_overrides"] = override_image_overrides
|
|
captured["reuse_from"] = reuse_from
|
|
|
|
monkeypatch.setattr(_pz2, "run_phase_z2_mvp1", _fake_run)
|
|
monkeypatch.setattr(sys, "argv", argv)
|
|
|
|
src_path = Path(_pz2.__file__)
|
|
source = src_path.read_text(encoding="utf-8")
|
|
tree = ast.parse(source)
|
|
for node in tree.body:
|
|
if (
|
|
isinstance(node, ast.If)
|
|
and isinstance(node.test, ast.Compare)
|
|
and isinstance(node.test.left, ast.Name)
|
|
and node.test.left.id == "__name__"
|
|
):
|
|
block = ast.Module(body=node.body, type_ignores=[])
|
|
exec(compile(block, str(src_path), "exec"), _pz2.__dict__)
|
|
return
|
|
raise AssertionError("no `if __name__ == '__main__'` block found")
|
|
|
|
|
|
def _redirect_overrides_root(tmp_path: Path, monkeypatch) -> None:
|
|
"""Isolate the persistence fallback so file state never leaks in."""
|
|
monkeypatch.setattr(_io, "DEFAULT_OVERRIDES_ROOT", tmp_path)
|
|
|
|
|
|
# -- success paths --------------------------------------------------------
|
|
|
|
|
|
def test_reuse_from_alone_parses_and_dispatches(tmp_path, monkeypatch):
|
|
"""``--reuse-from`` with no other overrides must parse cleanly and
|
|
fall through to dispatch (frame-only / empty override is allowed).
|
|
u5 (2026-05-24): also asserts the CLI threads ``args.reuse_from``
|
|
verbatim into the ``reuse_from`` kwarg."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert captured.get("called") is True
|
|
# u5 — verbatim threading.
|
|
assert captured["reuse_from"] == "03__DX_20260508025134"
|
|
|
|
|
|
def test_reuse_from_with_frame_override_dispatches(tmp_path, monkeypatch):
|
|
"""Frame overrides ARE preserved across Step 0/1/2/5/6 reuse, so
|
|
``--reuse-from`` + ``--override-frame`` must reach dispatch.
|
|
u5: forwards both ``reuse_from`` and ``override_frames`` in the
|
|
same call."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-frame",
|
|
"03-1=frame_foo",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert captured.get("called") is True
|
|
assert captured["override_frames"] == {"03-1": "frame_foo"}
|
|
# u5 — frame override + reuse_from reach the kwarg simultaneously.
|
|
assert captured["reuse_from"] == "03__DX_20260508025134"
|
|
|
|
|
|
# -- u5 — flag-absent default + signature surface ------------------------
|
|
|
|
|
|
def test_no_reuse_from_threads_none_kwarg(tmp_path, monkeypatch):
|
|
"""u5 — when ``--reuse-from`` is absent, the kwarg must reach
|
|
``run_phase_z2_mvp1`` as ``None`` (not omitted, not ``""``). This
|
|
locks the "default None preserves current behavior" requirement
|
|
from the Stage 2 plan §u5."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
_exec_main_block(
|
|
captured,
|
|
["src.phase_z2_pipeline", "03.mdx"],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert captured.get("called") is True
|
|
assert captured["reuse_from"] is None
|
|
|
|
|
|
def test_run_phase_z2_mvp1_signature_includes_reuse_from():
|
|
"""Production signature lock — ``reuse_from`` must be a keyword-only
|
|
parameter with default ``None``. Mirror of the entry-tests
|
|
invariant; kept here so the CLI-surface test file fails loudly if
|
|
the production signature drifts away from the dispatch contract."""
|
|
import inspect
|
|
|
|
sig = inspect.signature(_pz2.run_phase_z2_mvp1)
|
|
assert "reuse_from" in sig.parameters, list(sig.parameters)
|
|
param = sig.parameters["reuse_from"]
|
|
assert param.kind is inspect.Parameter.KEYWORD_ONLY, param.kind
|
|
assert param.default is None, param.default
|
|
|
|
|
|
# -- fail-closed (single-axis rejection) ----------------------------------
|
|
|
|
|
|
def test_reuse_from_with_layout_override_exits(tmp_path, monkeypatch, capsys):
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-layout",
|
|
"horizontal-2",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "--reuse-from incompatible with override axes" in err
|
|
assert "layout" in err
|
|
assert captured.get("called") is not True
|
|
|
|
|
|
def test_reuse_from_with_zone_geometry_override_exits(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-zone-geometry",
|
|
"top=0,0,1,0.3",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "--reuse-from incompatible with override axes" in err
|
|
assert "zone_geometry" in err
|
|
assert captured.get("called") is not True
|
|
|
|
|
|
def test_reuse_from_with_zone_section_override_exits(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-section-assignment",
|
|
"top=03-1",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "--reuse-from incompatible with override axes" in err
|
|
assert "zone_section" in err
|
|
assert captured.get("called") is not True
|
|
|
|
|
|
def test_reuse_from_with_image_override_exits(tmp_path, monkeypatch, capsys):
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-image",
|
|
"img-abc=10,15,30,25",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "--reuse-from incompatible with override axes" in err
|
|
assert "image" in err
|
|
assert captured.get("called") is not True
|
|
|
|
|
|
# -- fail-closed (multi-axis aggregation) ---------------------------------
|
|
|
|
|
|
def test_reuse_from_with_multiple_rejected_axes_lists_all(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
"""Stderr must enumerate every rejected axis (not stop at first)."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
"--override-layout",
|
|
"horizontal-2",
|
|
"--override-zone-geometry",
|
|
"top=0,0,1,0.3",
|
|
"--override-image",
|
|
"img-abc=10,15,30,25",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "layout" in err
|
|
assert "zone_geometry" in err
|
|
assert "image" in err
|
|
assert captured.get("called") is not True
|
|
|
|
|
|
# -- guard inactive when --reuse-from absent ------------------------------
|
|
|
|
|
|
def test_no_reuse_from_layout_override_still_dispatches(
|
|
tmp_path, monkeypatch
|
|
):
|
|
"""Without ``--reuse-from``, the guard must be silent — existing
|
|
override behaviour is preserved end-to-end."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
captured: dict[str, Any] = {}
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--override-layout",
|
|
"horizontal-2",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert captured.get("called") is True
|
|
assert captured["override_layout"] == "horizontal-2"
|
|
|
|
|
|
# -- fail-closed honours persisted overrides ------------------------------
|
|
|
|
|
|
def test_reuse_from_with_persisted_layout_override_exits(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
"""The guard runs AFTER the user_overrides.json merge, so a layout
|
|
persisted on disk (not on the CLI) must still reject when
|
|
``--reuse-from`` is set. This locks the Stage 2 placement rule."""
|
|
_redirect_overrides_root(tmp_path, monkeypatch)
|
|
# Persist a layout override keyed by the MDX stem ``03``.
|
|
overrides_dir = tmp_path
|
|
overrides_dir.mkdir(parents=True, exist_ok=True)
|
|
(overrides_dir / "03.json").write_text(
|
|
'{"layout": "vertical-2"}', encoding="utf-8"
|
|
)
|
|
captured: dict[str, Any] = {}
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
_exec_main_block(
|
|
captured,
|
|
[
|
|
"src.phase_z2_pipeline",
|
|
"03.mdx",
|
|
"--reuse-from",
|
|
"03__DX_20260508025134",
|
|
],
|
|
monkeypatch,
|
|
)
|
|
|
|
assert excinfo.value.code == 2
|
|
err = capsys.readouterr().err
|
|
assert "--reuse-from incompatible with override axes" in err
|
|
assert "layout" in err
|
|
assert captured.get("called") is not True
|