Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
65 lines
2.8 KiB
Python
65 lines
2.8 KiB
Python
"""공종 축 — **이름과 붙은 표의 절이 어긋나면 빨강** (2026-09-17 브레인 · 코덱스 원문 대조).
|
|
|
|
이 병은 한 번 나면 아무도 못 알아챔: 품셈 목차가 같은 번호를 두 번 적자(12-17-2 · 12-24-1)
|
|
뒤 줄(「무근진동기 제외」)이 앞 표(F0363 「철근, 펌프카 0-15m」)를 물고, 진짜 표(F0364)는 orphan 으로 사라졌음.
|
|
표 번호로는 안 잡힘(번호는 같았음) — **표 절 제목의 이름이 다른 줄 이름과 똑같은데 그 줄이 아닌 데 붙음**이 그 꼴.
|
|
⚠ 이름 글자만 조금 다른 자리(목차 「깍기」 · 본문 「깎기」)는 판정하지 않음 — 번호·이름이 딴 줄을 가리킬 때만.
|
|
⚠ 부록 사례 표 7(F0455·F0456·F0472~F0476)은 번호가 본문 절과 겹쳐 그 절에 붙어 있으나 모두 참조형 —
|
|
일위대가로 안 읽혀 금액 무관(브레인 전수 판정). 자리 판정은 데스크탑 서브 몫.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
MASTER = ROOT / "resources" / "data_work_item_master" / "work_item_master_2026-01-01.json"
|
|
_TITLE = re.compile(r"^\s*(\d+(?:-\d+){0,3})\.\s+(.+)$")
|
|
|
|
|
|
def _squeeze(text: str) -> str:
|
|
return "".join(str(text).split())
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def master() -> dict:
|
|
return json.loads(MASTER.read_text(encoding="utf-8"))
|
|
|
|
|
|
def test_목차_번호가_안_겹침(master: dict) -> None:
|
|
numbers = [it["number"] for it in master["work_items"]]
|
|
assert len(set(numbers)) == len(numbers)
|
|
|
|
|
|
def test_표_절_제목이_다른_줄을_가리키지_않음(master: dict) -> None:
|
|
items = master["work_items"]
|
|
by_name: dict[str, set[str]] = {} # 이름 → 그 이름 줄의 열쇠(번호가 겹친 줄도 갈림)
|
|
for it in items:
|
|
by_name.setdefault(_squeeze(it["name"]), set()).add(it["work_item_key"])
|
|
bad = []
|
|
for it in items:
|
|
for table in it["tables"]:
|
|
title = _TITLE.match(table["section"])
|
|
if title is None:
|
|
continue
|
|
number, name = title.group(1), _squeeze(title.group(2))
|
|
others = by_name.get(name, set()) - {it["work_item_key"]}
|
|
if number != it["number"] or (others and name != _squeeze(it["name"])):
|
|
bad.append(
|
|
f"{table['pum_table_id']} 「{table['section']}」 → {it['number']} {it['name']}"
|
|
)
|
|
assert not bad, bad
|
|
|
|
|
|
def test_사라진_표는_목록으로_남음(master: dict) -> None:
|
|
"""orphan 을 조용히 버리지 않음 — 목록 수와 집계가 같아야 함."""
|
|
assert master["stats"]["tables_orphan"] == len(master["orphan_tables"])
|
|
assert (
|
|
master["stats"]["tables_attached"] + len(master["orphan_tables"])
|
|
== master["stats"]["tables_total"]
|
|
)
|