feat(#69): IMP-40 u1~u6 frame contract label_default placeholder/fallback role discriminator (BIM/DX leak fix)
Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 26s
Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 26s
- catalog (frame_contracts.yaml): F18 bim_dx_comparison_table col_a/col_b label_default_role=placeholder; F30 industry_current_status_three_col + F31 industry_characteristics_three_col col_a/col_b/col_c forward-compat placeholder; F33 engn_sw_three_types untouched (no label_default). - mapper (_build_compare_table_2col): generic _resolve_label_default(col_key) branches on <col>_label_default_role — placeholder -> '' (Figma placeholder suppressed at runtime), fallback -> catalog literal (legacy default), unknown -> ValueError with template_id + role_key + value. Absent role defaults to fallback (backward compat for contracts without discriminator). - tests (tests/phase_z2/test_imp40_label_default_role.py): u4 generic matrix (placeholder / fallback / absent / unknown / 3-col axis) + u5 F18-reuse non-BIM/DX synthetic rows asserting placeholder labels emit '' and BIM/DX literal tokens do not leak. - snapshot (tests/integration/__snapshots__/slot_payload.json): mdx 01 F18 string_slot_nonempty.col_a_label/col_b_label True -> False (u6 expected drift from u3 placeholder -> empty string flip). slot_names + rows + title preserved. Verification: - imp40_label_default_role: 6/6 PASSED - phase_z2 sweep: 608/608 PASSED - multi_mdx_regression: 50/50 PASSED - cross-suite sweep: 662/662 PASSED - BIM/DX literal grep on mapper + new test: 0 hits - No mdx-specific branches (mdx 03/04/05 grep on mapper: 0 hits) Guardrails: no MDX 03/04/05 hardcoding (catalog policy only); no spacing shrink; no auto frame swap on reject; no AI call at Step 12; F33 untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -579,12 +579,23 @@ def _build_compare_table_2col(section, units, contract) -> dict:
|
||||
|
||||
builder_options :
|
||||
item_parser : ITEM_PARSERS key (예: `compare_row_2col_item`)
|
||||
col_a_label_default : col_a header (MDX 미명시 시 fallback. F1-a fix)
|
||||
col_b_label_default : col_b header (MDX 미명시 시 fallback)
|
||||
col_a_label_default : col_a header literal in catalog.
|
||||
Semantics depend on col_a_label_default_role.
|
||||
col_a_label_default_role : "placeholder" | "fallback" (IMP-40 #69).
|
||||
placeholder = Figma visual placeholder; suppressed
|
||||
at runtime → col_a_label emitted as "".
|
||||
fallback = MDX 미명시 시 catalog literal 사용.
|
||||
absent = legacy contracts default to fallback.
|
||||
col_b_label_default : col_b header literal (same policy as col_a).
|
||||
col_b_label_default_role : same role discriminator for col_b (IMP-40 #69).
|
||||
strip_col_prefix_aliases : list[str] — col_a/col_b 값의 prefix `<alias>:`
|
||||
를 strip (Codex round 43 §F1-b — narrow alias).
|
||||
예 : ["BIM", "DX"]. default [] (no stripping).
|
||||
max_rows : N (default 999 — practical 한계).
|
||||
|
||||
NOTE: MDX 측 col_a_label / col_b_label inflow 경로 없음
|
||||
(compare_row_2col_item parser → {label,col_a,col_b}, _resolve_title → title only).
|
||||
placeholder role 은 col_*_label 을 빈 문자열로 확정 — 정책 결정점은 catalog 한 곳뿐.
|
||||
"""
|
||||
options = contract["payload"]["builder_options"]
|
||||
parser_name = options["item_parser"]
|
||||
@@ -595,8 +606,21 @@ def _build_compare_table_2col(section, units, contract) -> dict:
|
||||
f"but ITEM_PARSERS has no such entry."
|
||||
)
|
||||
|
||||
col_a_label = options.get("col_a_label_default", "")
|
||||
col_b_label = options.get("col_b_label_default", "")
|
||||
def _resolve_label_default(col_key: str) -> str:
|
||||
default_key = f"{col_key}_label_default"
|
||||
role_key = f"{col_key}_label_default_role"
|
||||
role = options.get(role_key, "fallback")
|
||||
if role == "placeholder":
|
||||
return ""
|
||||
if role == "fallback":
|
||||
return options.get(default_key, "")
|
||||
raise ValueError(
|
||||
f"Contract '{contract['template_id']}' builder_options.{role_key}='{role}' "
|
||||
f"is invalid; expected 'placeholder' or 'fallback' (IMP-40 #69)."
|
||||
)
|
||||
|
||||
col_a_label = _resolve_label_default("col_a")
|
||||
col_b_label = _resolve_label_default("col_b")
|
||||
strip_aliases = options.get("strip_col_prefix_aliases", []) or []
|
||||
max_rows = options.get("max_rows", 999)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user