Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 22s
u1 KNOWN_AXES tuple gains slide_css entry in src/user_overrides_io.py
(snake_case parity with image_overrides); round-trip test extends
to 6 axes.
u2 src/mdx_normalizer.py surfaces nested slide_overrides.css from the
MDX frontmatter into the normalize_mdx_content return dict; absent
key -> {}, non-string css drops. 4 unit cases in tests/test_mdx_normalizer.py
(present / absent / non-string / title-only).
u3 src/slide_css_injector.py NEW (88 lines) mirrors the
inject_image_overrides_style contract from src/image_id_stamper.py:
marker pair <!--IMP45-SLIDE-CSS:OPEN--> / <!--IMP45-SLIDE-CSS:CLOSE-->,
idempotent re-injection, </head> > <body> > document-start three-tier
fallback, empty/None -> unchanged. 8 fixtures in
tests/test_slide_css_injector.py mirror test_image_id_stamper.py.
u4 run_phase_z2_mvp1 accepts override_slide_css: Optional[str] = None;
None -> frontmatter slide_overrides.css fallback. Step 13 calls
inject_slide_css after image override injection and before the
final.html disk write, so CLI/CI/regression renders observe the same
backend artifact.
u5 argparse adds mutually-exclusive --override-slide-css TEXT (inline
CSS, <style> wrapper optional) and --slide-css-file PATH (UTF-8 read,
fail-closed sys.exit(2) on missing path / decode error / both flags
present). Resolved string is forwarded as override_slide_css kwarg.
6 cases in tests/test_phase_z2_cli_overrides.py (inline / file / both
/ missing / non-utf8 / neither).
u6 samples/mdx_batch/04.mdx frontmatter gains slide_overrides.css
block (verbatim of the former MDX04_DEFAULT_OVERRIDE_CSS constant,
no sample/frame gate). Subprocess smoke in
tests/test_phase_z2_slide_css_smoke.py verifies the marker pair and
CSS substring land in final.html.
u7 Front/client removes the sample/frame-gated frontend-only injection:
Home.tsx drops the MDX04_DEFAULT_OVERRIDE_CSS constant and the
sample==="04"+frame==="process_product_two_way" branch (-28 lines);
SlideCanvas.tsx drops the iframe contentDocument.head injection of
that prop (-14 lines). Live preview now reads backend final.html only.
u8 tests/regression/fixtures/89a_pre_baseline_sha.json 04.mdx entry
resyncs to the live SHA ddb6bf2f... / 28042 bytes (overwrites the
earlier 5-byte-drift d02c76fd... / 28047). Other entries untouched.
Note: 01.mdx baseline drift (ad6f16a3... / 29089 -> live f26a7fac...
/ 29084) predates this branch and is split to a follow-up issue per
the closed-issue fresh validation rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
102 lines
4.1 KiB
Python
102 lines
4.1 KiB
Python
"""IMP-45 (#74) u6 — subprocess smoke for the slide-level CSS override axis.
|
|
|
|
End-to-end guard that the ``slide_overrides.css`` frontmatter axis added
|
|
in u2 propagates through the pipeline (u4) and lands in ``final.html``
|
|
via :func:`src.slide_css_injector.inject_slide_css` (u3).
|
|
|
|
The fixture is the new ``slide_overrides.css`` frontmatter block in
|
|
``samples/mdx_batch/04.mdx`` (u6 migration of the legacy frontend-only
|
|
``MDX04_DEFAULT_OVERRIDE_CSS`` constant). The pipeline is spawned via
|
|
``python -m src.phase_z2_pipeline 04.mdx <run_id>`` so the assertion
|
|
applies to the on-disk artifact CI / CLI / regression all observe, not
|
|
to a live iframe view.
|
|
|
|
The subprocess returncode is intentionally NOT asserted: mdx04 has known
|
|
downstream issues (see ``test_pipeline_smoke_imp85.py`` —
|
|
``test_mdx04_no_longer_emits_imp85_crash_signature``) that are tracked
|
|
on a separate axis. Step 13 runs before the downstream failure surface,
|
|
so ``final.html`` is written with the injected slide CSS marker
|
|
regardless. The test asserts ``final.html`` exists and contains both
|
|
the IMP-45 sentinel marker and a distinctive CSS substring from the
|
|
migrated frontmatter block.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
SAMPLES_DIR = REPO_ROOT / "samples" / "mdx_batch"
|
|
RUNS_DIR = REPO_ROOT / "data" / "runs"
|
|
|
|
# IMP-45 (#74) u3 marker sentinel emitted by
|
|
# :func:`src.slide_css_injector.inject_slide_css` around the injected
|
|
# ``<style>`` block. Match the ``_IMP45_STYLE_MARKER_OPEN`` constant in
|
|
# ``src/slide_css_injector.py`` byte-for-byte.
|
|
IMP45_OPEN_MARKER = "<!--IMP45-SLIDE-CSS:OPEN-->"
|
|
IMP45_CLOSE_MARKER = "<!--IMP45-SLIDE-CSS:CLOSE-->"
|
|
|
|
# Distinctive substring from the migrated frontmatter block in
|
|
# ``samples/mdx_batch/04.mdx``. ``f29b__cell:nth-child(n+3)`` is unique
|
|
# to the MDX04 slide-level override CSS and does not appear elsewhere in
|
|
# the slide_base / partial templates, so its presence in ``final.html``
|
|
# is sufficient evidence that the frontmatter axis fed the injector.
|
|
MDX04_DISTINCTIVE_CSS_SUBSTRING = ".f29b__cell:nth-child(n+3)"
|
|
|
|
|
|
def _run_pipeline(mdx_name: str, run_id: str, timeout: int = 240) -> subprocess.CompletedProcess:
|
|
"""Spawn ``python -m src.phase_z2_pipeline <mdx> <run_id>``."""
|
|
return subprocess.run(
|
|
[
|
|
sys.executable,
|
|
"-m",
|
|
"src.phase_z2_pipeline",
|
|
str(SAMPLES_DIR / mdx_name),
|
|
run_id,
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout,
|
|
cwd=str(REPO_ROOT),
|
|
)
|
|
|
|
|
|
def _unique_run_id(prefix: str) -> str:
|
|
return f"{prefix}_imp45_slide_css_smoke_{uuid.uuid4().hex[:8]}"
|
|
|
|
|
|
def test_mdx04_slide_overrides_css_lands_in_final_html() -> None:
|
|
"""mdx04 ``slide_overrides.css`` frontmatter must reach ``final.html``.
|
|
|
|
Contract pins both the IMP-45 marker sentinel and a distinctive CSS
|
|
substring from the migrated frontmatter block so a regression in
|
|
either the frontmatter extractor (u2), the kwarg forwarding (u4),
|
|
or the injector (u3) is caught by this single smoke.
|
|
"""
|
|
run_id = _unique_run_id("mdx04")
|
|
cp = _run_pipeline("04.mdx", run_id)
|
|
|
|
final_html_path = RUNS_DIR / run_id / "phase_z2" / "final.html"
|
|
assert final_html_path.is_file(), (
|
|
f"final.html not found at {final_html_path}\n"
|
|
f"--- stderr tail ---\n{cp.stderr[-1500:]}\n"
|
|
f"--- stdout tail ---\n{cp.stdout[-1500:]}"
|
|
)
|
|
html = final_html_path.read_text(encoding="utf-8")
|
|
|
|
assert IMP45_OPEN_MARKER in html, (
|
|
f"IMP-45 open marker missing from mdx04 final.html ({final_html_path}).\n"
|
|
f"slide_overrides.css frontmatter axis did not reach the injector."
|
|
)
|
|
assert IMP45_CLOSE_MARKER in html, (
|
|
f"IMP-45 close marker missing from mdx04 final.html ({final_html_path}).\n"
|
|
f"Marker wrap appears unbalanced — check inject_slide_css() output."
|
|
)
|
|
assert MDX04_DISTINCTIVE_CSS_SUBSTRING in html, (
|
|
f"Migrated frontmatter CSS substring "
|
|
f"{MDX04_DISTINCTIVE_CSS_SUBSTRING!r} missing from mdx04 final.html "
|
|
f"({final_html_path}). The slide_overrides.css block did not propagate."
|
|
)
|