feat(#86): IMP-86 u1~u5 placeholder zones_data + invariant guard
Mapper FitError handler now appends a __empty__ placeholder to zones_data and a matching debug_zone so the surviving cardinality stays in sync with the active layout preset's grid rows. A pre-build_layout_css invariant guard fails fast with preset/positions/count diagnostics if drift recurs. Per-record telemetry (adapter_needed, mapper_fit_error, provisional) is exposed on both placeholder records; authoritative slide_status.adapter_ needed_units schema is unchanged. Closes mdx03 reject override regression: Step 12 AI router now reachable without heights_px ValueError; default-path behavior unaffected. u1 — FitError placeholder zones_data + debug_zone (src/phase_z2_pipeline.py) u2 — pre-build_layout_css invariant guard (src/phase_z2_pipeline.py) u3 — horizontal-2 normal+placeholder helper unit (test_compute_per_zone_geometry.py) u4 — mdx03 reject override → Step 12 integration + default regression u5 — placeholder telemetry surface (adapter_needed/mapper_fit_error/provisional) Tests: - u3 helper: 7 passed (0.06s) - u4+u5 integration: 2 passed (7.87s) - Phase Z2 + AI fallback regression: 544 passed (66.28s) - Broader sweep (excl. matching/pipeline heavy): 1066 passed (96.12s) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,3 +99,63 @@ def test_fr_default_single_returns_full_body():
|
||||
per_zone = _compute_per_zone_geometry(layout_css, debug_zones, GRID_GAP)
|
||||
assert per_zone[0]["zone_height_px"] == SLIDE_BODY_HEIGHT
|
||||
assert per_zone[0]["zone_width_px"] == SLIDE_BODY_WIDTH
|
||||
|
||||
|
||||
def _placeholder_zone(position: str) -> dict:
|
||||
# IMP-86 u3 — mirror the u1 mapper-FitError placeholder zones_data
|
||||
# record shape (`src/phase_z2_pipeline.py:4459-4469`) used to keep the
|
||||
# failed unit's preset position in zones_data so build_layout_css /
|
||||
# _compute_per_zone_geometry observe len(zones_data) == active preset's
|
||||
# css_areas rows (R). content_weight.score == 0 ensures the placeholder
|
||||
# does not steal weight from the surviving normal zone.
|
||||
return {
|
||||
"position": position,
|
||||
"template_id": "__empty__",
|
||||
"slot_payload": {},
|
||||
"content_weight": {"score": 0},
|
||||
"min_height_px": 100,
|
||||
"assignment_source": "imp86_u1_adapter_needed",
|
||||
"section_assignment_override": False,
|
||||
"provisional": False,
|
||||
}
|
||||
|
||||
|
||||
def test_horizontal_2_normal_plus_placeholder_preserves_R2_cardinality():
|
||||
"""IMP-86 u3 — horizontal-2 with one mapper-success zone + one
|
||||
mapper-FitError placeholder (per IMP-86 u1) must keep heights_px /
|
||||
debug_zones / per_zone cardinality locked at R=2.
|
||||
|
||||
Reproduces the bug scenario in the issue body (mdx03 reject override
|
||||
where 03-2 hits adapter_needed) at the helper level: if the FitError
|
||||
path forgets to append a placeholder, heights_px length 1 vs R=2
|
||||
raises ValueError at `_compute_per_zone_geometry`. With the u1
|
||||
placeholder, all three artifacts (heights_px, debug_zones, per_zone)
|
||||
stay at length 2 and the geometry helper succeeds.
|
||||
"""
|
||||
zones = [_zone("top", 1.0), _placeholder_zone("bottom")]
|
||||
layout_css = build_layout_css("horizontal-2", zones)
|
||||
debug_zones = [{"position": "top"}, {"position": "bottom"}]
|
||||
|
||||
# heights_px length is locked to R=2 (parsed from preset css_areas).
|
||||
assert layout_css["areas"] == '"top" "bottom"'
|
||||
assert len(layout_css["heights_px"]) == 2
|
||||
# widths_px length is locked to C=1.
|
||||
assert len(layout_css["widths_px"]) == 1
|
||||
|
||||
# Placeholder zone (score=0) gets its min_height_px (100) and the
|
||||
# surviving normal zone absorbs the remaining body height after gap.
|
||||
assert layout_css["heights_px"][1] == 100
|
||||
assert (
|
||||
layout_css["heights_px"][0] + layout_css["heights_px"][1] + GRID_GAP
|
||||
== SLIDE_BODY_HEIGHT
|
||||
)
|
||||
|
||||
per_zone = _compute_per_zone_geometry(layout_css, debug_zones, GRID_GAP)
|
||||
# per_zone cardinality matches debug_zones (which matches R=2).
|
||||
assert len(per_zone) == 2
|
||||
assert [pz["position"] for pz in per_zone] == ["top", "bottom"]
|
||||
assert per_zone[0]["zone_height_px"] == layout_css["heights_px"][0]
|
||||
assert per_zone[1]["zone_height_px"] == layout_css["heights_px"][1]
|
||||
# Both zones share the single column => width == SLIDE_BODY_WIDTH.
|
||||
assert per_zone[0]["zone_width_px"] == SLIDE_BODY_WIDTH
|
||||
assert per_zone[1]["zone_width_px"] == SLIDE_BODY_WIDTH
|
||||
|
||||
Reference in New Issue
Block a user