From 8fb1952ba9455c9470032d3cc5bb3f3777be17b4 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 19:24:01 +0900 Subject: [PATCH] =?UTF-8?q?feat(z01):=20=EB=82=B1=EA=B0=92=20=EB=A7=88?= =?UTF-8?q?=EB=94=94=20=EC=9D=B4=EB=A6=84=20=EB=84=B7=20=ED=99=95=EC=A0=95?= =?UTF-8?q?=20=C2=B7=20=EA=B0=92=C2=B7=EC=84=A4=EB=AA=85=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=EB=A5=BC=20`kind`=20=EB=82=B1=EB=A7=90=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 브레인 확정 이름 그대로 — `synthetic_tables["@values"]` 표 이름 「낱값」 · 설명 「표가 아닌 한 값들」 · 열 `@name` 「항목」 · `@value` 「값」 · `@path` 「원문 자리」(숨김) - 값 묶음 표시를 참·거짓이 아니라 **낱말** `kind: "value" | "doc"` 로 둠 — 수식 같은 갈래가 늘면 낱말만 더하면 되고 뜻이 안 뒤집힘 · 갈래(kinds) 말투와도 맞음 - 이름 갈이 — `role` → `kind` · `value_roles` → `value_kinds` · `counts.value_groups_by_kind` · `policy.value_kind_rule` - 셈은 그대로(값 49 · 설명 123) · 시험 26건(2건 늘, 낱값 마디 이름 넷과 낱말 여부를 잡음) Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FFCnEYNH4tsS2MbHvzBhZk --- .../data_master_labels/labels_2026-01-01.json | 383 ++++++++++-------- resources/tester/test_master_labels_cover.py | 34 +- 2 files changed, 229 insertions(+), 188 deletions(-) diff --git a/resources/data_master_labels/labels_2026-01-01.json b/resources/data_master_labels/labels_2026-01-01.json index ae9fbe4b..e7a836e7 100644 --- a/resources/data_master_labels/labels_2026-01-01.json +++ b/resources/data_master_labels/labels_2026-01-01.json @@ -2,7 +2,7 @@ "schema_version": "1.0", "dataset_id": "data_master_labels", "effective_date": "2026-01-01", - "generated_at": "2026-09-15T19:16:20+09:00", + "generated_at": "2026-09-15T19:23:25+09:00", "note": "마스터 자료의 **사람이 읽을 이름표**. 값이 아니라 이름만 담는다 — 여기를 고쳐도 계산은 안 바뀐다. Z01 마스터 관리 화면이 표·열 이름을 여기서 읽는다.", "policy": { "labels_only": "값·수식·단가를 담지 않는다. 마스터 파일은 손대지 않는다.", @@ -13,7 +13,7 @@ "out_of_31": "폴더 지문(_manifest.json) 셋은 브레인 31 밖이다. 부산물이 아니라 **지문** 갈래로 둔다 — 계산이 남긴 기록이 아니라 어느 판으로 셈했는지 못박는 표라 「정본 아님」 딱지가 안 맞는다(2026-09-15 브레인 ②).", "excluded": "강우 IDF 캐시(resources/data_rainfall_idf_cache, 96 파일)는 배수용이라 뺀다.", "row_key_column": "사전 모양(shape=map) 표는 **줄 이름(키) 자체가 한 열**이다. API 가 `@key` 로 내보내므로 열 목록 맨 앞에 `@key`(`is_row_key: true`)를 두고 표마다 제 이름을 붙인다 — 뜻이 표마다 달라 한 이름으로 뭉치지 않는다(2026-09-15 브레인 ①).", - "value_role_rule": "값 묶음은 갈래가 둘이다. **값** = 원가·수량에 그대로 드는 것(한 값짜리 요율·시세·계수·원단위표·잇는 값) — 낱값 마디(`@values`)에 **보인다**. **설명** = 읽으라고 적어 둔 글(방침·출처·비고·읽기 기록·표 머리의 키·단위·기준일) — 낱값 마디에 **안 보인다**. 가름은 「고치면 금액이 움직이나」로 한다. 움직이면 값, 안 움직이면 설명(2026-09-15 브레인 ②)." + "value_kind_rule": "값 묶음마다 `kind` 를 낱말로 적는다. `value`(값) = 원가·수량에 그대로 드는 것(한 값짜리 요율·시세·계수·원단위표·잇는 값) — 낱값 마디(`@values`)에 **보인다**. `doc`(설명) = 읽으라고 적어 둔 글(방침·출처·비고·읽기 기록·표 머리의 키·단위·기준일) — 낱값 마디에 **안 보인다**. 참·거짓이 아니라 낱말이라 수식 같은 갈래가 늘면 낱말만 더하면 된다. 가름은 「고치면 금액이 움직이나」로 한다. 움직이면 값, 안 움직이면 설명(2026-09-15 브레인 ②)." }, "lookup_order": { "column": [ @@ -49,24 +49,51 @@ "summary": "앞으로 늘려 갈 첫 벌. 모양을 잡아 두려고 먼저 놓은 것이다." } }, - "value_roles": { + "value_kinds": { "value": { "name_ko": "값", "summary": "원가·수량에 그대로 드는 값. 낱값 마디에 **보인다** — 여기서 사라지면 트리에서 값이 사라진다." }, - "note": { + "doc": { "name_ko": "설명", "summary": "읽으라고 적어 둔 글(방침·출처·비고·기록). 낱값 마디에 **안 보인다** — 보이면 화면이 흐려진다." } }, + "synthetic_tables": { + "@values": { + "name_ko": "낱값", + "summary": "표가 아닌 한 값들", + "columns": [ + { + "key": "@name", + "name_ko": "항목", + "unit": "", + "visible": true + }, + { + "key": "@value", + "name_ko": "값", + "unit": "", + "visible": true + }, + { + "key": "@path", + "name_ko": "원문 자리", + "unit": "", + "visible": false + } + ], + "note": "`kind: \"value\"` 인 값 묶음만 여기 선다. `kind: \"doc\"` 은 안 보인다." + } + }, "counts": { "files": 34, "tables": 91, "columns": 455, "value_groups": 172, "unknown": 0, - "value_groups_by_role": { - "note": 123, + "value_groups_by_kind": { + "doc": 123, "value": 49 } }, @@ -150,13 +177,13 @@ "key": "variables/pum/normalization_status", "name_ko": "정돈 상태", "summary": "자원 코드 정돈이 끝났는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/pum/representation", "name_ko": "담은 꼴", "summary": "원문 표를 어떤 꼴로 담았는지.", - "role": "note" + "kind": "doc" } ] }, @@ -245,13 +272,13 @@ "key": "variables/pum/normalization_status", "name_ko": "정돈 상태", "summary": "자원 코드 정돈이 끝났는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/pum/representation", "name_ko": "담은 꼴", "summary": "원문 표를 어떤 꼴로 담았는지.", - "role": "note" + "kind": "doc" } ] }, @@ -364,13 +391,13 @@ "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "stats", "name_ko": "집계", "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", - "role": "note" + "kind": "doc" } ] }, @@ -576,67 +603,67 @@ "key": "variables/coef_soil_C/duplicate_note", "name_ko": "원문 중복 비고", "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리.", - "role": "note" + "kind": "doc" }, { "key": "variables/coef_soil_C/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/coef_soil_L/duplicate_note", "name_ko": "원문 중복 비고", "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리.", - "role": "note" + "kind": "doc" }, { "key": "variables/coef_soil_L/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/rate_tool", "name_ko": "공구손료율", "summary": "주요 재료비에 곱하는 공구손료 율(하한·상한). 어느 값을 쓸지는 고름이 필요하다.", - "role": "value" + "kind": "value" }, { "key": "variables/surcharge_labor/application_status", "name_ko": "적용 상태", "summary": "쓰려면 무엇이 더 정해져야 하는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/surcharge_labor/representation", "name_ko": "담은 꼴", "summary": "원문 표를 어떤 꼴로 담았는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/surcharge_labor/unit", "name_ko": "값 단위", "summary": "할증은 %다.", - "role": "note" + "kind": "doc" }, { "key": "variables/surcharge_mat/duplicate_application_prohibited", "name_ko": "중복 적용 금지", "summary": "두 자리에 걸면 두 번 세게 된다는 표시.", - "role": "note" + "kind": "doc" }, { "key": "variables/surcharge_mat/representation", "name_ko": "담은 꼴", "summary": "원문 표를 어떤 꼴로 담았는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/surcharge_mat/unit", "name_ko": "값 단위", "summary": "할증은 %다.", - "role": "note" + "kind": "doc" } ] }, @@ -783,25 +810,25 @@ "key": "candidates_pending_user/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "not_found", "name_ko": "못 찾은 것", "summary": "두 품셈을 다 뒤졌으나 이름이 없는 것.", - "role": "note" + "kind": "doc" }, { "key": "observed_practice", "name_ko": "실무 관측", "summary": "실무 집계에서 본 할증률. 참고이지 기본값이 아니다.", - "role": "value" + "kind": "value" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" } ] }, @@ -944,55 +971,55 @@ "key": "euroform_type/material_unit_note", "name_ko": "자재 밑수 비고", "summary": "자재 환산을 어느 창이 하는지.", - "role": "note" + "kind": "doc" }, { "key": "euroform_type/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "euroform_type/reuse_note", "name_ko": "사용횟수 비고", "summary": "닮은 두 사용횟수를 하나로 잇지 않는 까닭.", - "role": "note" + "kind": "doc" }, { "key": "euroform_type/source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "reuse_ratio_pct", "name_ko": "사용횟수별 기준수량 비율", "summary": "품셈 12-4 — 일위대가 재료비에 걸린다. B08 이 곱하면 이중계상이다.", - "role": "value" + "kind": "value" }, { "key": "shoring", "name_ko": "동바리", "summary": "강관동바리가 어느 구조물에 서는지.", - "role": "value" + "kind": "value" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" } ] }, @@ -1081,25 +1108,25 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "price_hint_krw_per_ton", "name_ko": "단가 참고값", "summary": "표시 전용 — 갈래 차이를 사람이 보라고 둔 값. 계산에 안 들어간다.", - "role": "value" + "kind": "value" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" } ] }, @@ -1194,25 +1221,25 @@ "key": "basis_unit", "name_ko": "밑수", "summary": "값이 무엇 하나당인지.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "pending_user", "name_ko": "사용자 확정 대기", "summary": "아직 사람이 답해야 닫히는 물음.", - "role": "note" + "kind": "doc" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" } ] }, @@ -1250,43 +1277,43 @@ "key": "back_length/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "back_length/option_key", "name_ko": "고르개 키", "summary": "화면 고르개가 쓰는 저장 칸 이름.", - "role": "value" + "kind": "value" }, { "key": "back_length/source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" }, { "key": "bond", "name_ko": "쌓기 방식", "summary": "메쌓기·찰쌓기로 공종코드가 갈린다.", - "role": "value" + "kind": "value" }, { "key": "boulder_diameter", "name_ko": "돌 직경 갈래", "summary": "큰돌쌓기 — 저장 제원 stone_cm 으로 갈린다.", - "role": "value" + "kind": "value" }, { "key": "face_slope", "name_ko": "전면 기울기", "summary": "형식마다 정해진 1:n. 코드 기본 0.3 이 여기서 왔다.", - "role": "value" + "kind": "value" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -1331,31 +1358,31 @@ "key": "not_here", "name_ko": "이 표가 안 다루는 것", "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" }, { "key": "steps_m", "name_ko": "직고 칸", "summary": "표가 갈리는 높이 경계(m).", - "role": "value" + "kind": "value" } ] }, @@ -1371,37 +1398,37 @@ "key": "not_here", "name_ko": "이 표가 안 다루는 것", "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" }, { "key": "steps_m", "name_ko": "직고 칸", "summary": "표가 갈리는 높이 경계(m).", - "role": "value" + "kind": "value" }, { "key": "table_cm", "name_ko": "뒷길이 범위표", "summary": "메·찰마다 직고 칸별 뒷길이 하한·상한(㎝).", - "role": "value" + "kind": "value" } ] }, @@ -1452,79 +1479,79 @@ "key": "back_lengths_cm", "name_ko": "뒷길이 규격", "summary": "표가 값을 주는 뒷길이 일곱 칸.", - "role": "value" + "kind": "value" }, { "key": "backfill_ratio_of_back_length", "name_ko": "뒤채움 몫", "summary": "뒷길이 가운데 뒤채움이 차지하는 비. 나머지가 잡석이다.", - "role": "value" + "kind": "value" }, { "key": "fallback", "name_ko": "미지정일 때", "summary": "사용자가 안 고른 경우 쓰는 한 벌.", - "role": "value" + "kind": "value" }, { "key": "fill_concrete_m3_per_m2", "name_ko": "채움 콘크리트 원단위", "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. 원문이 두 줄뿐이다.", - "role": "value" + "kind": "value" }, { "key": "kinds", "name_ko": "돌 종류", "summary": "야면석·호박돌 / 깬잡석 / 깬돌 / 견치돌 네 줄.", - "role": "value" + "kind": "value" }, { "key": "no_folding", "name_ko": "접지 않음 규칙", "summary": "표에 없는 뒷길이를 가까운 칸으로 접지 않는다 — 접으면 값이 조용히 틀린다.", - "role": "note" + "kind": "doc" }, { "key": "not_here", "name_ko": "이 표가 안 다루는 것", "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "option_key", "name_ko": "고르개 키", "summary": "화면 고르개가 쓰는 저장 칸 이름.", - "role": "value" + "kind": "value" }, { "key": "option_note", "name_ko": "고르개 비고", "summary": "고르개를 만들 때 챙길 것.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "wedge_stone_m3_per_m2", "name_ko": "고임돌 원단위", "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. null 은 원문 「-」다.", - "role": "value" + "kind": "value" }, { "key": "why", "name_ko": "까닭", "summary": "이 벌을 왜 따로 두는지.", - "role": "note" + "kind": "doc" } ] }, @@ -1540,25 +1567,25 @@ "key": "items", "name_ko": "항목", "summary": "이 벌이 담는 항목 묶음.", - "role": "value" + "kind": "value" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "rank", "name_ko": "우선순위", "summary": "원문끼리 어긋날 때 어느 쪽을 먼저 보는지.", - "role": "note" + "kind": "doc" }, { "key": "scope", "name_ko": "걸치는 범위", "summary": "어디까지 쓰는 값인지.", - "role": "note" + "kind": "doc" } ] }, @@ -1834,37 +1861,37 @@ "key": "double_count_rules/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "not_found/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "pending_choices/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "原文_뒷받침/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -2307,67 +2334,67 @@ "key": "composite/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "composite/unit_conversion", "name_ko": "단위 환산", "summary": "단가 단위와 원단위 단위가 달라 맞추는 값.", - "role": "value" + "kind": "value" }, { "key": "concrete_placing", "name_ko": "콘크리트 타설 잇기", "summary": "타설 방식 × 구조물 종류로 공종이 갈리는 자리.", - "role": "value" + "kind": "value" }, { "key": "ground_aliases_moved_to", "name_ko": "갈래 별칭 옮긴 자리", "summary": "갈래 이름 별칭은 별칭표로 옮겼다. 여기 다시 두지 않는다.", - "role": "note" + "kind": "doc" }, { "key": "masonry_class_reference", "name_ko": "돌쌓기 갈래 참고 자리", "summary": "돌쌓기 갈래는 이제 참고용이고 어긋나면 그것이 신호다.", - "role": "note" + "kind": "doc" }, { "key": "master", "name_ko": "마스터 자리", "summary": "공종 코드를 읽어 오는 마스터 파일.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "pending_user/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "pipe", "name_ko": "배수관 잇기", "summary": "관종으로 공종이 갈린다. 관 정본은 pipe_points 다.", - "role": "value" + "kind": "value" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "variant_contract", "name_ko": "갈래 키 계약", "summary": "갈래 키 문자열을 두 창이 각자 조립하지 않기로 한 약속.", - "role": "note" + "kind": "doc" } ] }, @@ -2429,7 +2456,7 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -2491,13 +2518,13 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" } ] }, @@ -2592,19 +2619,19 @@ "key": "variables/aliases", "name_ko": "노임 별칭", "summary": "코드 대신 쓰는 별칭 이름표(labor_1002 = 보통인부).", - "role": "value" + "kind": "value" }, { "key": "variables/labor_rate/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/labor_rate/reliability_note", "name_ko": "신뢰도 기호 뜻풀이", "summary": "노임 표의 * · ** 가 무엇을 뜻하는지.", - "role": "note" + "kind": "doc" } ] }, @@ -2705,7 +2732,7 @@ "key": "variables/labor_mfg/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" } ] }, @@ -3052,61 +3079,61 @@ "key": "parse_audit", "name_ko": "읽기 점검", "summary": "취득가 표에서 못 읽은 줄이 있는지 적어 둔 자리.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_fuel_rate/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_fuel_rate/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_fuel_rate/unit", "name_ko": "값 단위", "summary": "연료량은 L/시간이다.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_loss_coef/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_loss_coef/unit", "name_ko": "값 단위", "summary": "손료계수는 1/시간이다.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_operator_map/note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_price/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_price/unit", "name_ko": "값 단위", "summary": "취득가는 천원 단위다.", - "role": "note" + "kind": "doc" }, { "key": "variables/mach_rock_adj/unit", "name_ko": "값 단위", "summary": "할증은 %다.", - "role": "note" + "kind": "doc" } ] }, @@ -3186,31 +3213,31 @@ "key": "derived_from", "name_ko": "무엇에서 나왔나", "summary": "어느 벌을 풀어 만든 파생본인지.", - "role": "note" + "kind": "doc" }, { "key": "dropped_tables", "name_ko": "못 읽어 버린 표", "summary": "칸 수가 안 맞아 못 읽고 버린 원문 표.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "stats", "name_ko": "집계", "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", - "role": "note" + "kind": "doc" } ] }, @@ -3368,19 +3395,19 @@ "key": "selection_policy", "name_ko": "고르는 방침", "summary": "같은 물품이 여러 번 공고되면 어느 것을 쓰는지.", - "role": "note" + "kind": "doc" }, { "key": "source_row_count", "name_ko": "원천 줄 수", "summary": "걸러 내기 전 원본 줄 수.", - "role": "note" + "kind": "doc" }, { "key": "variables/mat_price/key", "name_ko": "줄을 가르는 칸", "summary": "이 표에서 줄 하나를 집는 칸 이름.", - "role": "note" + "kind": "doc" } ] }, @@ -3567,67 +3594,67 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_diesel/date", "name_ko": "기준일", "summary": "값이 선 날.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_diesel/scope", "name_ko": "걸치는 범위", "summary": "어디까지 쓰는 값인지.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_diesel/source_product_code", "name_ko": "원천 제품코드", "summary": "원천이 쓰는 제품 코드.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_diesel/source_product_name", "name_ko": "원천 제품명", "summary": "원천이 쓰는 제품 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_diesel/unit", "name_ko": "값 단위", "summary": "단가는 원/L 이다.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_gasoline/date", "name_ko": "기준일", "summary": "값이 선 날.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_gasoline/scope", "name_ko": "걸치는 범위", "summary": "어디까지 쓰는 값인지.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_gasoline/source_product_code", "name_ko": "원천 제품코드", "summary": "원천이 쓰는 제품 코드.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_gasoline/source_product_name", "name_ko": "원천 제품명", "summary": "원천이 쓰는 제품 이름.", - "role": "note" + "kind": "doc" }, { "key": "variables/oil_gasoline/unit", "name_ko": "값 단위", "summary": "단가는 원/L 이다.", - "role": "note" + "kind": "doc" } ] }, @@ -4084,175 +4111,175 @@ "key": "processing_rules", "name_ko": "셈 규칙", "summary": "요율만으로는 금액이 안 나온다 — 밑수를 어떻게 만들고 어디서 자르는지 적은 자리. 코드와 어긋나면 거울 시험이 잡는다.", - "role": "note" + "kind": "doc" }, { "key": "variables/rate_asbestos_contribution", "name_ko": "석면피해구제 분담금", "summary": "노무비에 곱하는 율.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_care", "name_ko": "노인장기요양보험료", "summary": "건강보험료 금액에 곱하는 율.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_environment/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_environment/forest_road_selection_status", "name_ko": "임도 줄 고름 상태", "summary": "임도에 어느 줄을 쓸지 고름이 끝났는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/rate_environment/minimum_estimated_amount_krw", "name_ko": "적용 하한 — 추정금액", "summary": "이 금액에 못 미치면 줄이 안 선다(원).", - "role": "value" + "kind": "value" }, { "key": "variables/rate_equipment_payment_guarantee/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_equipment_payment_guarantee/base_note", "name_ko": "밑수 비고", "summary": "밑수를 그렇게 적은 까닭.", - "role": "note" + "kind": "doc" }, { "key": "variables/rate_goyong/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_health", "name_ko": "건강보험료", "summary": "직접노무비에 곱하는 율.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_indirect_labor/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_other_expense/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_overhead/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_pension/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_pension/rate_from_2033_percent", "name_ko": "2033년 이후 요율", "summary": "표 밖으로 나가는 해부터 쓰는 율(%).", - "role": "value" + "kind": "value" }, { "key": "variables/rate_performance_guarantee_fee/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_performance_guarantee_fee/typical_forest_road_applicability", "name_ko": "임도에 걸리는지", "summary": "보통 임도 규모에서 이 항목이 서는지.", - "role": "note" + "kind": "doc" }, { "key": "variables/rate_profit/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_retirement_mutual_aid", "name_ko": "퇴직공제부금비", "summary": "직접노무비에 곱하는 율. 추정금액 하한이 있다.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_base", "name_ko": "산업안전보건관리비 기초액", "summary": "요율표 안에 함께 든 기초액이 걸리는 구간.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_pct/base_rule", "name_ko": "밑수 규칙", "summary": "밑수를 고르는 방식.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_pct/base_with_owner_supplied_material", "name_ko": "대상액 — 관급자재 있을 때", "summary": "고시가 준 두 식 가운데 작은 쪽.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_pct/base_without_owner_supplied_material", "name_ko": "대상액 — 관급자재 없을 때", "summary": "재료비 + 직접노무비.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_pct/manager_thresholds", "name_ko": "안전관리자 선임 기준액", "summary": "안전관리자를 둬야 하는 금액 문턱.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_safety_pct/minimum_total_construction_amount_krw", "name_ko": "적용 하한 — 총공사금액", "summary": "이 금액에 못 미치면 줄이 안 선다(원).", - "role": "value" + "kind": "value" }, { "key": "variables/rate_sanjae", "name_ko": "산재보험료", "summary": "노무비에 곱하는 율.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_subcontract_payment_guarantee/base", "name_ko": "밑수", "summary": "이 요율을 곱하는 대상.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_vat", "name_ko": "부가가치세", "summary": "공급가액에 곱하는 율.", - "role": "value" + "kind": "value" }, { "key": "variables/rate_wage_claim_contribution", "name_ko": "임금채권보장 부담금", "summary": "노무비에 곱하는 율.", - "role": "value" + "kind": "value" } ] }, @@ -4302,7 +4329,7 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -4358,7 +4385,7 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -4462,13 +4489,13 @@ "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" }, { "key": "stats", "name_ko": "집계", "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", - "role": "note" + "kind": "doc" } ] }, @@ -4518,7 +4545,7 @@ "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -4747,49 +4774,49 @@ "key": "code", "name_ko": "항목 코드", "summary": "라이브러리 항목 코드.", - "role": "note" + "kind": "doc" }, { "key": "differs_from_engine", "name_ko": "전개와 다른 자리", "summary": "지금 돌아가는 전개와 이 양식이 갈리는 곳을 적어 둔 자리.", - "role": "note" + "kind": "doc" }, { "key": "item_kind", "name_ko": "항목 갈래", "summary": "양식형(form)인지 고정형인지.", - "role": "note" + "kind": "doc" }, { "key": "library_tier", "name_ko": "라이브러리 단", "summary": "프로그램·회사·개인 가운데 어느 단의 항목인지.", - "role": "note" + "kind": "doc" }, { "key": "name", "name_ko": "항목 이름", "summary": "화면에 보이는 이름.", - "role": "note" + "kind": "doc" }, { "key": "note", "name_ko": "설명", "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", - "role": "note" + "kind": "doc" }, { "key": "type_id", "name_ko": "구조물 종류 키", "summary": "어느 구조물 종류에 붙는 양식인지.", - "role": "note" + "kind": "doc" }, { "key": "unit_price/note", "name_ko": "일위대가 틀 설명", "summary": "일위대가 줄을 어떻게 세우는지 적은 글.", - "role": "note" + "kind": "doc" } ] }, @@ -4932,7 +4959,7 @@ "key": "policy", "name_ko": "방침", "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", - "role": "note" + "kind": "doc" } ] }, @@ -4976,7 +5003,7 @@ "key": "built_by", "name_ko": "만든 자리", "summary": "이 벌을 지은 코드나 사람.", - "role": "note" + "kind": "doc" } ] }, @@ -5020,13 +5047,13 @@ "key": "built_by", "name_ko": "만든 자리", "summary": "이 벌을 지은 코드나 사람.", - "role": "note" + "kind": "doc" }, { "key": "source", "name_ko": "출처", "summary": "어느 원문에서 왔는지.", - "role": "note" + "kind": "doc" } ] } diff --git a/resources/tester/test_master_labels_cover.py b/resources/tester/test_master_labels_cover.py index 250a6672..d13ed374 100644 --- a/resources/tester/test_master_labels_cover.py +++ b/resources/tester/test_master_labels_cover.py @@ -330,26 +330,40 @@ def test_줄_이름_열의_이름이_표마다_제_것이다(labels): assert duplicated <= {"출처 키"}, f"줄 이름이 겹친다: {sorted(duplicated)}" -def test_값_묶음마다_값이냐_설명이냐가_적혀_있다(labels): - known = set(labels["value_roles"]) +def test_값_묶음마다_kind_가_낱말로_적혀_있다(labels): + known = set(labels["value_kinds"]) bad = [] for entry in labels["files"]: for group in entry["value_groups"]: - if group.get("role") not in known: + if group.get("kind") 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"] +def test_값_갈래_잣대와_낱값_마디가_적혀_있다(labels): + rule = labels["policy"]["value_kind_rule"] assert "금액이 움직이나" in rule assert labels["policy"]["row_key_column"] + node = labels["synthetic_tables"]["@values"] + assert node["name_ko"] == "낱값" + assert node["summary"] == "표가 아닌 한 값들" + assert [c["key"] for c in node["columns"]] == ["@name", "@value", "@path"] + assert [c["name_ko"] for c in node["columns"]] == ["항목", "값", "원문 자리"] + assert node["columns"][2]["visible"] is False + + +def test_값_갈래는_참거짓이_아니라_낱말이다(labels): + """수식 같은 갈래가 늘면 낱말만 더하면 된다 — 참·거짓이면 그때 뜻이 뒤집힌다.""" + for entry in labels["files"]: + for group in entry["value_groups"]: + assert isinstance(group["kind"], str), f"{entry['file_id']}::{group['key']}" + assert set(labels["value_kinds"]) == {"value", "doc"} 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"]} + by_key = {g["key"]: g["kind"] for g in rates["value_groups"]} for key in ( "variables/rate_sanjae", "variables/rate_health", @@ -360,12 +374,12 @@ def test_한_값짜리_요율은_값으로_선다(labels): "variables/rate_asbestos_contribution", ): assert by_key.get(key) == "value", f"{key} 가 값으로 안 섰다" - assert by_key.get("processing_rules") == "note" + assert by_key.get("processing_rules") == "doc" -def test_세어_둔_갈래_수가_실제와_같다(labels): +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"] + counted[group["kind"]] = counted.get(group["kind"], 0) + 1 + assert counted == labels["counts"]["value_groups_by_kind"]