feat(#42): IMP-04b catalog extension to 32 frames (u1~u24)
Extends frame_contracts.yaml from 11 to 32 contracts to match V4 evidence
(tests/matching/v4_full32_result.yaml unique template_ids), closing the
IMP-04b gap surfaced in IMP-04 (#4) Track A milestone.
Scope (Stage 2 24-unit plan):
- u3/u4: WIP partial absorb — app_sw_package_vs_solution (F23),
pre_construction_model_info_stacked (F9). Both promoted from
_WIP_FILES.md to frame_contracts.yaml. WIP allowlist now empty.
- u5~u11: Track A 7 frames (index.html present, contract missing).
- u12~u23: Track B 12 frames (visual_pending: true; family partial
authoring deferred — contract-first per Stage 2 plan).
- u24: BT closure gate. Adds
test_imp04b_closure_gate_v4_coverage_and_wip_empty (catalog ↔ V4
set-equal + WIP==0) and test_vp_exempt_keys_are_contracted_and_disk_absent
(vp ∩ disk == ∅). Relaxes test_contracts_set_equals_disk_families_minus_wip
to (disk - wip) ∪ vp. 32 derived from V4 evidence YAML (no hardcoding).
Closure facts (locked):
contracts = 32, v4_unique = 32, missing = [], extra = [],
wip_count = 0, vp_count = 19, vp ∩ disk = [].
Guardrails honored:
- No calculate_fit migration.
- No AI/Kei API call in per-frame work.
- No 1-2 sample hardcoding (Codex #7 generalization guardrail).
- No production refactor for tests (IMP-32 owns helper extract).
- figma_to_html / V4 / Phase Z 3-layer separation preserved.
- 1 commit = 1 IMP-04b decision unit (bundled u1~u24 per Stage 2
plan; CAT+WIP atomicity for u3/u4 preserved).
Tests: tests/test_family_contract_baseline.py 4/4 PASS.
Cross-ref: IMP-04 (#4), IMP-29 (#38), IMP-30 (#39), IMP-31 (#40),
IMP-32 (#41), IMP-33 (#61), IMP-47A (#75).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>