[Claude #1] Stage 4: Test-Verify Round #1

Verification Result: PASS (recommend Codex final-verify YES)

Scope Match (vs Stage 2 IMPLEMENTATION_UNITS):
- u1 templates/phase_z2/slide_base.html: `<html lang="ko"{% if embedded_mode == "embedded" %} class="embedded"{% endif %}>` at line 4, CSP-safe auto-mode `<script>` in `<head>` lines 9-20 gated on `embedded_mode == "auto"`, additive `html.embedded body` + `html.embedded .slide` CSS reset in existing `<style>` block lines 35-47. Standalone rules at lines 24-31 untouched.
- u2 src/phase_z2_pipeline.py: `render_slide` signature lines 2022-2024 gains keyword-only `*, embedded_mode: str = "auto"`. ValueError guard lines 2034-2038 for unknown modes. Jinja2 context line 2064 passes `embedded_mode=embedded_mode`. 3 existing call sites (1886, 1998, 4314) use positional args only; default `"auto"` preserves backward-compat. `run_overflow_check` standalone consumer behavior unchanged.
- u3 Front/client/src/components/SlideCanvas.tsx: `embeddedSrc` derivation lines 189-193 preserves any existing query before appending `?embedded=1` / `&embedded=1`. iframe `src={embeddedSrc}` at line 292. Reset CSS injection block removed (former lines 299-316). Comment 293-295 updated to reference IMP-14 backend ownership. `doc` getter, `slideOverrideCss`, zone measurement intact.
- u4 tests/phase_z2/test_slide_base_embedded_mode.py: new file, 6 cases using `__empty__` zone stub triggering `render_slide` short-circuit. All cases anchored to actual template lines.

Test Results:
- Targeted: `pytest -q tests/phase_z2/test_slide_base_embedded_mode.py -v` -> 6 passed in 0.07s
- phase_z2 suite: `pytest -q tests/phase_z2/` -> 87 passed in 0.20s
- Full repo (excluding matching/pipeline experimental dirs): `pytest -q tests/ --ignore=tests/matching --ignore=tests/pipeline` -> 139 passed in 4.21s

Guardrail Compliance:
- G1 (no AI / Phase R-prime regression): static Jinja2 conditionals + literal 3-valued enum only. Zero AI hook inserted.
- G2 (Jinja2 determinism): `test_deterministic` asserts byte-identical twice-render for both `auto` and `embedded`.
- No hardcoded fix to final.html: process layer (template conditional + `render_slide` signature) carries contract.
- No spacing reduction: fix is mode-aware CSS reset (display/min-height/padding/box-shadow), not shrink.
- Scope-lock: only 4 planned files touched (3 modified + 1 new). No drift to other Step 13 templates / frame families / pipeline steps.

Backward-Compat Check:
- `run_overflow_check` (lines 2058-2091 per Stage 1) consumes `file:///` URL without `?embedded=1` query and without explicit `embedded_mode` arg: auto-mode script runs, detects `window.self === window.top` (top-level), does not add `embedded` class: standalone CSS path retained. Behavior unchanged.
- 3 internal `render_slide` callers (line 1886 / 1998 / 4314) omit `embedded_mode` kwarg: default `"auto"` preserves prior output for downstream consumers.

Rewind Risk: none identified.
- No untracked anomaly; no hidden coupling; no regression in 226 cross-suite tests.
- Tests cover both modes + auto-mode + invalid-mode guard + determinism. 6 axes vs Stage 2 plan 6 cases.

=== EVIDENCE ===
```
git diff --stat:
  Front/client/src/components/SlideCanvas.tsx: +6 / -22 (embeddedSrc derivation + injection block removal)
  src/phase_z2_pipeline.py:                    +13 / -1 (signature + guard + context pass-through)
  templates/phase_z2/slide_base.html:          +26 / -1 (conditional class + script + CSS reset)
  tests/phase_z2/test_slide_base_embedded_mode.py (untracked, +69 new)

pytest tests/phase_z2/test_slide_base_embedded_mode.py -v:
  test_auto_script_present              PASSED [ 16%]
  test_css_rules_present                PASSED [ 33%]
  test_embedded_mode_explicit           PASSED [ 50%]
  test_standalone_mode_explicit         PASSED [ 66%]
  test_deterministic                    PASSED [ 83%]
  test_invalid_mode_raises              PASSED [100%]
  6 passed in 0.07s

pytest tests/phase_z2/                  : 87 passed in 0.20s
pytest tests/ (no matching/pipeline)    : 139 passed in 4.21s

render_slide call sites (grep, src/phase_z2_pipeline.py):
  1886: candidate_html = render_slide(... gap_px=gap_px,)     (retry path, positional only)
  1998: base = render_slide(slide_title, slide_footer, ...)   (run_overflow_check standalone path)
  2022: def render_slide(... *, embedded_mode: str = "auto")  (definition)
  4314: html = render_slide(slide_title, ..., layout_css)     (end-of-file caller)

Files anchored:
  templates/phase_z2/slide_base.html:4       <html lang="ko"{% if embedded_mode == "embedded" %} class="embedded"{% endif %}>
  templates/phase_z2/slide_base.html:9-20    {% if embedded_mode == "auto" %}<script>...</script>{% endif %}
  templates/phase_z2/slide_base.html:35-47   html.embedded body { ... } / html.embedded .slide { ... }
  src/phase_z2_pipeline.py:2022-2038         signature + ValueError guard
  src/phase_z2_pipeline.py:2064              embedded_mode=embedded_mode (Jinja2 context)
  Front/client/src/components/SlideCanvas.tsx:189-193  embeddedSrc derivation
  Front/client/src/components/SlideCanvas.tsx:292      iframe src={embeddedSrc}

commit_sha: pending (Stage 5 will commit)
```

Recommendation: PASS -> Codex re-verify Round #2.
