- 제외 목록 대신 갈래마다 어디서 왔나를 한 칸: 덤프 운반·적재 10-12 제목 → 그 식(브레인 판정) - 짝 시험: 표에서 온 갈래는 마스터 갈래 키에 있어야 함 · 식이 낸 갈래는 출처가 적혀 있고 마스터엔 없어야 함 - 마스터에는 「식 공종 갈래」 칸을 안 둠(표에서 뽑은 것만 담는 자리) - 전체 1771 통과 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
70 lines
3.3 KiB
Python
70 lines
3.3 KiB
Python
"""공종 마스터 갈래 키 `variant_key` — 표 읽기가 가른 대로 (명세 14장 정정 · 2026-09-13).
|
|
|
|
지키는 것
|
|
① 짝 시험 — 단가표의 `B-<코드>#<갈래>` 제목은 **전부** 그 공종의 마스터 갈래 키에 있다
|
|
(종전 첫 열 24개 방식은 294 중 86). 표 읽기를 고치고 마스터를 안 다시 뽑으면 여기서 걸림
|
|
② 머리행 갈래(벌목)·뭉친 이름 표(찰쌓기 장비)는 머리행에서 · 첫 열이 자원 이름인 표는 빈칸
|
|
③ 합산형 부모는 단계 갈래를 물려받음(흙깎기 리핑암 9-4 = 암질 + [주]① 평균)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from B09_Estimation.B09_Estimation_ResourceAxis import load_work_item_master
|
|
from B09_Estimation.B09_Estimation_UnitPrice import cached_build, normalize_variant_key
|
|
|
|
|
|
def _nodes() -> dict[str, dict]:
|
|
return {node["work_item_code"]: node for node in load_work_item_master()["work_items"]}
|
|
|
|
|
|
def test_단가표_갈래_제목은_전부_마스터_갈래_키에_있다() -> None:
|
|
"""갈래를 **어디서 왔나**로 가름(2026-09-14 브레인 판정) — 표에서 온 갈래만 마스터에 있어야 함.
|
|
|
|
식이 낸 갈래(덤프 운반·적재 10-12)는 마스터가 낼 수 없어 검사 대상이 아니되
|
|
`formula_variants` 에 「식이 냈다」가 적혀 있어야 함(아래 짝 시험).
|
|
"""
|
|
nodes = _nodes()
|
|
missing = []
|
|
build = cached_build(dump_haul_m=("164.23",))
|
|
for code in build.book.titles:
|
|
if not code.startswith("B-") or "#" not in code:
|
|
continue
|
|
if code in build.formula_variants:
|
|
continue
|
|
work_item, variant = code[2:].split("#", 1)
|
|
keys = {
|
|
normalize_variant_key(k) for k in nodes.get(work_item, {}).get("variant_keys") or []
|
|
}
|
|
if variant not in keys:
|
|
missing.append(code)
|
|
assert not missing, f"마스터를 다시 뽑을 것(B08_Quantity_Build_WorkItemMaster): {missing[:5]}"
|
|
|
|
|
|
def test_식이_낸_갈래는_출처가_적히고_마스터엔_없다() -> None:
|
|
build = cached_build(dump_haul_m=("164.23",))
|
|
formula = build.formula_variants
|
|
assert "B-FP-10-12-01#적재" in formula and "B-FP-10-12-02#L164.23m" in formula
|
|
assert all(code in build.book.titles and why for code, why in formula.items())
|
|
nodes = _nodes()
|
|
for code in formula:
|
|
work_item, variant = code[2:].split("#", 1)
|
|
keys = {normalize_variant_key(k) for k in nodes[work_item].get("variant_keys") or []}
|
|
assert variant not in keys # 마스터에 있으면 「표에서 옴」이라 여기 적을 까닭이 없음
|
|
|
|
|
|
def test_표_모양대로_갈래를_가르고_못_가르면_빈칸() -> None:
|
|
nodes = _nodes()
|
|
felling = nodes["FP-04-02-02"]["tables"][0]["variant_key"]
|
|
assert "5m이상~8m미만" in felling # 머리행 갈래 — 첫 열(자원 이름)이 아님
|
|
assert nodes["FP-13-04-05"]["tables"][0]["variant_key"] == [
|
|
"35cm 이하",
|
|
"55cm 이하",
|
|
"75cm 이하",
|
|
]
|
|
finishing = next(t for t in nodes["FP-12-02"]["tables"] if t["pum_table_id"] == "F0334")
|
|
assert finishing["variant_key"] == [] # 첫 열이 자원 이름(미장공)인 표
|
|
|
|
|
|
def test_합산형_부모는_단계_갈래를_물려받는다() -> None:
|
|
assert _nodes()["FP-09-04"]["variant_keys"] == ["연암", "보통암", "경암", "평균"]
|