feat(z01): 이름표에 줄 이름 열 여덟과 「값·설명」 가름 172 칸
- 사전 모양 표 8 에 **줄 이름 열 `@key`** 를 둠(브레인 ①) — 표마다 제 이름: fx 「통화」 · oil 「유종」 · masonry_slope 「쌓기 방식」 · material_surcharge 「구실」 · stone_kind·structure_unit 「출처 키」 · masonry_wet 「표 이름」·「칸 키」 · `is_row_key` 표시 붙임 - 값 묶음 172 를 **값 49 · 설명 123** 으로 가름(브레인 ②) — 잣대는 「고치면 금액이 움직이나」 · 이름표 `policy.value_role_rule` 에 적음 · 갈래 뜻은 `value_roles` 에 - 값으로 선 것 — 한 값짜리 요율 여덟(산재·건강·요양·부가세·퇴직공제·임금채권·석면·안전관리비 기초액) · 요율마다의 밑수 · 시세 · 계수·원단위표(돌쌓기·거푸집·철근) · 잇는 값(노임 별칭·타설·배수관) - 설명으로 숨는 것 — 방침·출처·비고·읽기 기록과 표 머리의 키·단위·기준일 - 시험 25건(7건 늘) — 줄 이름 열이 빠지거나 한 값짜리 요율이 설명으로 숨으면 빨강 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFCnEYNH4tsS2MbHvzBhZk
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -95,9 +95,13 @@ def _scan(path: Path) -> tuple[list, list]:
|
||||
return tables, values
|
||||
|
||||
|
||||
#: 사전 모양 표의 **줄 이름 열** — API 가 이 이름으로 내보낸다(2026-09-15 브레인 ①).
|
||||
ROW_KEY_COLUMN = "@key"
|
||||
|
||||
|
||||
def _columns_of(node, shape: str) -> list[str]:
|
||||
records = node if shape == "list" else list(node.values())
|
||||
seen: list[str] = []
|
||||
seen: list[str] = [ROW_KEY_COLUMN] if shape == "map" else []
|
||||
for record in records:
|
||||
if not isinstance(record, dict):
|
||||
continue
|
||||
@@ -281,3 +285,87 @@ def test_세어_둔_수가_실제와_같다(labels):
|
||||
|
||||
def test_강우_IDF_캐시는_안_담았다(labels):
|
||||
assert not [f for f in labels["files"] if "rainfall" in f["path"]]
|
||||
|
||||
|
||||
def test_사전_모양_표에는_줄_이름_열이_있다(labels):
|
||||
"""`fx`·`oil` 처럼 사전 모양인 표는 **줄 이름(키) 자체가 한 열**이다.
|
||||
그 열이 없으면 화면에 영문 `@key` 로 뜬다(2026-09-15 브레인 ①)."""
|
||||
bad = []
|
||||
for entry in labels["files"]:
|
||||
for table in entry["tables"]:
|
||||
if table["shape"] != "map":
|
||||
continue
|
||||
first = table["columns"][0] if table["columns"] else None
|
||||
if first is None or first["key"] != ROW_KEY_COLUMN:
|
||||
bad.append(f"{entry['file_id']}::{table['key']} — 줄 이름 열 없음")
|
||||
elif not first["name_ko"].strip():
|
||||
bad.append(f"{entry['file_id']}::{table['key']} — 줄 이름 열에 한글 이름 없음")
|
||||
elif not first.get("is_row_key"):
|
||||
bad.append(f"{entry['file_id']}::{table['key']} — is_row_key 표시 없음")
|
||||
assert not bad, f"줄 이름 열 문제: {bad}"
|
||||
|
||||
|
||||
def test_줄_이름_열은_사전_모양_표에만_있다(labels):
|
||||
stray = [
|
||||
f"{entry['file_id']}::{table['key']}"
|
||||
for entry in labels["files"]
|
||||
for table in entry["tables"]
|
||||
if table["shape"] != "map" and any(c["key"] == ROW_KEY_COLUMN for c in table["columns"])
|
||||
]
|
||||
assert not stray, f"사전 모양이 아닌데 줄 이름 열이 있다: {stray}"
|
||||
|
||||
|
||||
def test_줄_이름_열의_이름이_표마다_제_것이다(labels):
|
||||
"""뜻이 표마다 다르므로 한 이름으로 뭉치면 안 된다 — 같은 이름이 겹치면 살펴볼 것."""
|
||||
names = [
|
||||
column["name_ko"]
|
||||
for entry in labels["files"]
|
||||
for table in entry["tables"]
|
||||
for column in table["columns"]
|
||||
if column["key"] == ROW_KEY_COLUMN
|
||||
]
|
||||
assert names, "줄 이름 열이 하나도 없다"
|
||||
# 「출처 키」만 두 표가 같은 뜻으로 쓴다(출처 사전 둘). 그 밖은 겹치지 않는다.
|
||||
duplicated = {n for n in names if names.count(n) > 1}
|
||||
assert duplicated <= {"출처 키"}, f"줄 이름이 겹친다: {sorted(duplicated)}"
|
||||
|
||||
|
||||
def test_값_묶음마다_값이냐_설명이냐가_적혀_있다(labels):
|
||||
known = set(labels["value_roles"])
|
||||
bad = []
|
||||
for entry in labels["files"]:
|
||||
for group in entry["value_groups"]:
|
||||
if group.get("role") not in known:
|
||||
bad.append(f"{entry['file_id']}::{group['key']} — {group.get('role')!r}")
|
||||
assert not bad, f"값·설명이 안 갈린 값 묶음: {bad}"
|
||||
|
||||
|
||||
def test_값_갈래_잣대가_이름표에_적혀_있다(labels):
|
||||
rule = labels["policy"]["value_role_rule"]
|
||||
assert "금액이 움직이나" in rule
|
||||
assert labels["policy"]["row_key_column"]
|
||||
|
||||
|
||||
def test_한_값짜리_요율은_값으로_선다(labels):
|
||||
"""산재 3.56 % 처럼 원가에 그대로 드는 요율이 설명으로 숨으면 트리에서 사라진다."""
|
||||
rates = next(f for f in labels["files"] if f["file_id"] == "rates")
|
||||
by_key = {g["key"]: g["role"] for g in rates["value_groups"]}
|
||||
for key in (
|
||||
"variables/rate_sanjae",
|
||||
"variables/rate_health",
|
||||
"variables/rate_care",
|
||||
"variables/rate_vat",
|
||||
"variables/rate_retirement_mutual_aid",
|
||||
"variables/rate_wage_claim_contribution",
|
||||
"variables/rate_asbestos_contribution",
|
||||
):
|
||||
assert by_key.get(key) == "value", f"{key} 가 값으로 안 섰다"
|
||||
assert by_key.get("processing_rules") == "note"
|
||||
|
||||
|
||||
def test_세어_둔_갈래_수가_실제와_같다(labels):
|
||||
counted: dict[str, int] = {}
|
||||
for entry in labels["files"]:
|
||||
for group in entry["value_groups"]:
|
||||
counted[group["role"]] = counted.get(group["role"], 0) + 1
|
||||
assert counted == labels["counts"]["value_groups_by_role"]
|
||||
|
||||
Reference in New Issue
Block a user