Files
C.E.L_Slide_test2/tests/test_phase_z2_mapper_builder_missing.py
kyeongmin cacc5b30db feat(#85): IMP catalog builder invariant + VP runtime gate (u1~u7)
- u1: BuilderMissingError(FitError) — narrow exception aligned with pipeline catch
- u2: load_frame_contracts catalog invariant + VP skip + CatalogInvariantError
- u3a: audit CLI I1~I3 (partial existence / declared builder / registry membership)
- u3b: audit CLI I4 (slot_payload refs vs declared/generated payload keys)
- u4: lookup_v4_candidates VP filter (lookup_v4_all_judgments raw telemetry untouched)
- u5: catalog invariant regression coverage + temp non-VP failure fixtures
- u6: mdx04 VP routing fixture tests (sw_dependency_four_problems excluded from live)
- u7: tests/conftest.py env isolation + mdx03/mdx04/mdx05 subprocess smoke

Targeted 74 PASS (12.31s). Full regression 1063 PASS (87.70s). Audit CLI clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:56:38 +09:00

86 lines
2.7 KiB
Python

"""IMP-#85 u1 — mapper missing-builder dispatch raises BuilderMissingError.
Scope (Stage 2 lock):
- `BuilderMissingError` exists and is a subclass of `FitError`.
- `map_with_contract` raises `BuilderMissingError` when
`contract.payload.builder` references an unknown registry entry, OR
when `payload.builder` is empty/missing.
- Because it subclasses `FitError`, the existing pipeline
`except FitError` route in `src/phase_z2_pipeline.py` continues to
catch the failure and emit an `adapter_needed` record instead of a
hard crash (mdx04 `sw_dependency_four_problems` / `cards_4_grid`
regression evidence).
"""
from __future__ import annotations
from types import SimpleNamespace
import pytest
from src.phase_z2_mapper import (
BuilderMissingError,
FitError,
PAYLOAD_BUILDERS,
map_with_contract,
)
def _make_section(raw_content: str = "- a\n- b\n- c"):
return SimpleNamespace(
section_id="test-sec",
raw_content=raw_content,
title="t",
order=1,
)
def test_builder_missing_error_is_fit_error_subclass():
assert issubclass(BuilderMissingError, FitError)
def test_unknown_builder_raises_builder_missing_error():
unknown = "definitely_not_a_registered_builder"
assert unknown not in PAYLOAD_BUILDERS
contract = {
"template_id": "fake_contract_unknown_builder",
"source_shape": "top_bullets",
"cardinality": {},
"payload": {"builder": unknown},
}
with pytest.raises(BuilderMissingError) as exc:
map_with_contract(_make_section(), contract)
assert unknown in str(exc.value)
assert "fake_contract_unknown_builder" in str(exc.value)
def test_missing_builder_field_raises_builder_missing_error():
contract = {
"template_id": "fake_contract_missing_builder_field",
"source_shape": "top_bullets",
"cardinality": {},
"payload": {},
}
with pytest.raises(BuilderMissingError) as exc:
map_with_contract(_make_section(), contract)
assert "missing payload.builder" in str(exc.value)
def test_builder_missing_error_caught_by_fit_error_handler():
"""Pipeline 의 `except FitError` 경로가 그대로 잡아주는지 검증.
실제 pipeline import 없이 동일 패턴을 재현하여 subclass 의 의도된
routing 효과(adapter_needed) 가 깨지지 않는지 확인.
"""
contract = {
"template_id": "fake_contract_routing_check",
"source_shape": "top_bullets",
"cardinality": {},
"payload": {"builder": "no_such_builder"},
}
caught = False
try:
map_with_contract(_make_section(), contract)
except FitError:
caught = True
assert caught, "BuilderMissingError must propagate through `except FitError`"