"""IMP-08 B-3 sub-section drag/drop — schema + V4 alias resolver tests. Fully synthetic per Codex #7 generalization guardrail: NO real catalog template_id / frame_id, NO ``v4_full32_result.yaml`` dependency, NO MDX-specific section ids beyond canonical id format. Locked scope (Stage 3 R8) : A. ``derive_parent_id`` canonical ordinal recognition + legacy decimal fallback. B. ``_resolve_v4_section_key`` exact > alias > None (no parent/sibling promotion). """ from __future__ import annotations from src.phase_z2_composition import derive_parent_id from src.phase_z2_pipeline import _resolve_v4_section_key # ─── A. derive_parent_id ──────────────────────────────────────────────────── def test_derive_parent_id_ordinal_sub(): assert derive_parent_id("03-1-sub-2") == "03-1" assert derive_parent_id("04-2-sub-1") == "04-2" def test_derive_parent_id_decimal_legacy_alias(): # Legacy V4 decimal id retains existing behaviour for alias path. assert derive_parent_id("04-2.1") == "04-2" def test_derive_parent_id_top_level_none(): assert derive_parent_id("04-1") is None assert derive_parent_id("04") is None assert derive_parent_id("nonsense") is None # ─── B. _resolve_v4_section_key ───────────────────────────────────────────── def _fake_v4(*keys): return {"mdx_sections": {k: {"judgments_full32": []} for k in keys}} def test_alias_resolver_exact_match_wins(): v4 = _fake_v4("04-2-sub-1", "04-2.1") assert _resolve_v4_section_key(v4, "04-2-sub-1") == "04-2-sub-1" assert ( _resolve_v4_section_key(v4, "04-2-sub-1", alias_keys=["04-2.1"]) == "04-2-sub-1" ) def test_alias_resolver_decimal_alias_when_metadata_present(): v4 = _fake_v4("04-2.1") assert ( _resolve_v4_section_key(v4, "04-2-sub-1", alias_keys=["04-2.1"]) == "04-2.1" ) def test_alias_resolver_no_parent_promotion(): # parent V4 entry must not be promoted into a sibling sub-section lookup. v4 = _fake_v4("04-2") assert _resolve_v4_section_key(v4, "04-2-sub-1") is None assert ( _resolve_v4_section_key(v4, "04-2-sub-1", alias_keys=["04-2"]) == "04-2" ) # alias is opt-in; only resolves when caller explicitly provides it def test_alias_resolver_no_sibling_promotion(): # sibling sub-section entry must not be auto-promoted without an alias. v4 = _fake_v4("04-2-sub-2") assert _resolve_v4_section_key(v4, "04-2-sub-1") is None def test_alias_resolver_miss_returns_none(): v4 = _fake_v4("99-1") assert _resolve_v4_section_key(v4, "04-2-sub-1") is None assert ( _resolve_v4_section_key(v4, "04-2-sub-1", alias_keys=["04-2.1"]) is None )