From da2238505c6643c6142073c5af35242d85754b45 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 19:17:28 +0900 Subject: [PATCH] =?UTF-8?q?feat(z01):=20=EC=9D=B4=EB=A6=84=ED=91=9C?= =?UTF-8?q?=EC=97=90=20=EC=A4=84=20=EC=9D=B4=EB=A6=84=20=EC=97=B4=20?= =?UTF-8?q?=EC=97=AC=EB=8D=9F=EA=B3=BC=20=E3=80=8C=EA=B0=92=C2=B7=EC=84=A4?= =?UTF-8?q?=EB=AA=85=E3=80=8D=20=EA=B0=80=EB=A6=84=20172=20=EC=B9=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사전 모양 표 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) Claude-Session: https://claude.ai/code/session_01FFCnEYNH4tsS2MbHvzBhZk --- .../data_master_labels/labels_2026-01-01.json | 596 ++++++++++++------ resources/tester/test_master_labels_cover.py | 90 ++- 2 files changed, 509 insertions(+), 177 deletions(-) diff --git a/resources/data_master_labels/labels_2026-01-01.json b/resources/data_master_labels/labels_2026-01-01.json index 4e79b5b9..ae9fbe4b 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-15T18:59:13+09:00", + "generated_at": "2026-09-15T19:16:20+09:00", "note": "마스터 자료의 **사람이 읽을 이름표**. 값이 아니라 이름만 담는다 — 여기를 고쳐도 계산은 안 바뀐다. Z01 마스터 관리 화면이 표·열 이름을 여기서 읽는다.", "policy": { "labels_only": "값·수식·단가를 담지 않는다. 마스터 파일은 손대지 않는다.", @@ -11,7 +11,9 @@ "counting_rule": "표 = 화면이 표로 그릴 마디(줄이 여럿인 마디). 값 묶음 = 표가 아닌 마디(설명·방침·한 값짜리 요율 따위).", "brain_kind_table": "갈래는 2026-09-15 브레인 갈래 나눔표를 그대로 따른다(로직 17 · 기초값 9 · 부산물 4 · 씨앗 1).", "out_of_31": "폴더 지문(_manifest.json) 셋은 브레인 31 밖이다. 부산물이 아니라 **지문** 갈래로 둔다 — 계산이 남긴 기록이 아니라 어느 판으로 셈했는지 못박는 표라 「정본 아님」 딱지가 안 맞는다(2026-09-15 브레인 ②).", - "excluded": "강우 IDF 캐시(resources/data_rainfall_idf_cache, 96 파일)는 배수용이라 뺀다." + "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 브레인 ②)." }, "lookup_order": { "column": [ @@ -47,12 +49,26 @@ "summary": "앞으로 늘려 갈 첫 벌. 모양을 잡아 두려고 먼저 놓은 것이다." } }, + "value_roles": { + "value": { + "name_ko": "값", + "summary": "원가·수량에 그대로 드는 값. 낱값 마디에 **보인다** — 여기서 사라지면 트리에서 값이 사라진다." + }, + "note": { + "name_ko": "설명", + "summary": "읽으라고 적어 둔 글(방침·출처·비고·기록). 낱값 마디에 **안 보인다** — 보이면 화면이 흐려진다." + } + }, "counts": { "files": 34, "tables": 91, - "columns": 447, + "columns": 455, "value_groups": 172, - "unknown": 0 + "unknown": 0, + "value_groups_by_role": { + "note": 123, + "value": 49 + } }, "files": [ { @@ -133,12 +149,14 @@ { "key": "variables/pum/normalization_status", "name_ko": "정돈 상태", - "summary": "자원 코드 정돈이 끝났는지." + "summary": "자원 코드 정돈이 끝났는지.", + "role": "note" }, { "key": "variables/pum/representation", "name_ko": "담은 꼴", - "summary": "원문 표를 어떤 꼴로 담았는지." + "summary": "원문 표를 어떤 꼴로 담았는지.", + "role": "note" } ] }, @@ -226,12 +244,14 @@ { "key": "variables/pum/normalization_status", "name_ko": "정돈 상태", - "summary": "자원 코드 정돈이 끝났는지." + "summary": "자원 코드 정돈이 끝났는지.", + "role": "note" }, { "key": "variables/pum/representation", "name_ko": "담은 꼴", - "summary": "원문 표를 어떤 꼴로 담았는지." + "summary": "원문 표를 어떤 꼴로 담았는지.", + "role": "note" } ] }, @@ -343,12 +363,14 @@ { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "stats", "name_ko": "집계", - "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", + "role": "note" } ] }, @@ -553,57 +575,68 @@ { "key": "variables/coef_soil_C/duplicate_note", "name_ko": "원문 중복 비고", - "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리." + "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리.", + "role": "note" }, { "key": "variables/coef_soil_C/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/coef_soil_L/duplicate_note", "name_ko": "원문 중복 비고", - "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리." + "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리.", + "role": "note" }, { "key": "variables/coef_soil_L/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/rate_tool", "name_ko": "공구손료율", - "summary": "주요 재료비에 곱하는 공구손료 율(하한·상한). 어느 값을 쓸지는 고름이 필요하다." + "summary": "주요 재료비에 곱하는 공구손료 율(하한·상한). 어느 값을 쓸지는 고름이 필요하다.", + "role": "value" }, { "key": "variables/surcharge_labor/application_status", "name_ko": "적용 상태", - "summary": "쓰려면 무엇이 더 정해져야 하는지." + "summary": "쓰려면 무엇이 더 정해져야 하는지.", + "role": "note" }, { "key": "variables/surcharge_labor/representation", "name_ko": "담은 꼴", - "summary": "원문 표를 어떤 꼴로 담았는지." + "summary": "원문 표를 어떤 꼴로 담았는지.", + "role": "note" }, { "key": "variables/surcharge_labor/unit", "name_ko": "값 단위", - "summary": "할증은 %다." + "summary": "할증은 %다.", + "role": "note" }, { "key": "variables/surcharge_mat/duplicate_application_prohibited", "name_ko": "중복 적용 금지", - "summary": "두 자리에 걸면 두 번 세게 된다는 표시." + "summary": "두 자리에 걸면 두 번 세게 된다는 표시.", + "role": "note" }, { "key": "variables/surcharge_mat/representation", "name_ko": "담은 꼴", - "summary": "원문 표를 어떤 꼴로 담았는지." + "summary": "원문 표를 어떤 꼴로 담았는지.", + "role": "note" }, { "key": "variables/surcharge_mat/unit", "name_ko": "값 단위", - "summary": "할증은 %다." + "summary": "할증은 %다.", + "role": "note" } ] }, @@ -717,6 +750,13 @@ "shape": "map", "rows": 2, "columns": [ + { + "key": "@key", + "name_ko": "구실", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "doc", "name_ko": "문서", @@ -742,22 +782,26 @@ { "key": "candidates_pending_user/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "not_found", "name_ko": "못 찾은 것", - "summary": "두 품셈을 다 뒤졌으나 이름이 없는 것." + "summary": "두 품셈을 다 뒤졌으나 이름이 없는 것.", + "role": "note" }, { "key": "observed_practice", "name_ko": "실무 관측", - "summary": "실무 집계에서 본 할증률. 참고이지 기본값이 아니다." + "summary": "실무 집계에서 본 할증률. 참고이지 기본값이 아니다.", + "role": "value" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" } ] }, @@ -899,47 +943,56 @@ { "key": "euroform_type/material_unit_note", "name_ko": "자재 밑수 비고", - "summary": "자재 환산을 어느 창이 하는지." + "summary": "자재 환산을 어느 창이 하는지.", + "role": "note" }, { "key": "euroform_type/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "euroform_type/reuse_note", "name_ko": "사용횟수 비고", - "summary": "닮은 두 사용횟수를 하나로 잇지 않는 까닭." + "summary": "닮은 두 사용횟수를 하나로 잇지 않는 까닭.", + "role": "note" }, { "key": "euroform_type/source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "reuse_ratio_pct", "name_ko": "사용횟수별 기준수량 비율", - "summary": "품셈 12-4 — 일위대가 재료비에 걸린다. B08 이 곱하면 이중계상이다." + "summary": "품셈 12-4 — 일위대가 재료비에 걸린다. B08 이 곱하면 이중계상이다.", + "role": "value" }, { "key": "shoring", "name_ko": "동바리", - "summary": "강관동바리가 어느 구조물에 서는지." + "summary": "강관동바리가 어느 구조물에 서는지.", + "role": "value" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" } ] }, @@ -1027,22 +1080,26 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "price_hint_krw_per_ton", "name_ko": "단가 참고값", - "summary": "표시 전용 — 갈래 차이를 사람이 보라고 둔 값. 계산에 안 들어간다." + "summary": "표시 전용 — 갈래 차이를 사람이 보라고 둔 값. 계산에 안 들어간다.", + "role": "value" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" } ] }, @@ -1136,22 +1193,26 @@ { "key": "basis_unit", "name_ko": "밑수", - "summary": "값이 무엇 하나당인지." + "summary": "값이 무엇 하나당인지.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "pending_user", "name_ko": "사용자 확정 대기", - "summary": "아직 사람이 답해야 닫히는 물음." + "summary": "아직 사람이 답해야 닫히는 물음.", + "role": "note" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" } ] }, @@ -1188,37 +1249,44 @@ { "key": "back_length/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "back_length/option_key", "name_ko": "고르개 키", - "summary": "화면 고르개가 쓰는 저장 칸 이름." + "summary": "화면 고르개가 쓰는 저장 칸 이름.", + "role": "value" }, { "key": "back_length/source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" }, { "key": "bond", "name_ko": "쌓기 방식", - "summary": "메쌓기·찰쌓기로 공종코드가 갈린다." + "summary": "메쌓기·찰쌓기로 공종코드가 갈린다.", + "role": "value" }, { "key": "boulder_diameter", "name_ko": "돌 직경 갈래", - "summary": "큰돌쌓기 — 저장 제원 stone_cm 으로 갈린다." + "summary": "큰돌쌓기 — 저장 제원 stone_cm 으로 갈린다.", + "role": "value" }, { "key": "face_slope", "name_ko": "전면 기울기", - "summary": "형식마다 정해진 1:n. 코드 기본 0.3 이 여기서 왔다." + "summary": "형식마다 정해진 1:n. 코드 기본 0.3 이 여기서 왔다.", + "role": "value" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -1236,6 +1304,13 @@ "shape": "map", "rows": 2, "columns": [ + { + "key": "@key", + "name_ko": "쌓기 방식", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "성토", "name_ko": "성토부 경사", @@ -1255,27 +1330,32 @@ { "key": "not_here", "name_ko": "이 표가 안 다루는 것", - "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" }, { "key": "steps_m", "name_ko": "직고 칸", - "summary": "표가 갈리는 높이 경계(m)." + "summary": "표가 갈리는 높이 경계(m).", + "role": "value" } ] }, @@ -1290,32 +1370,38 @@ { "key": "not_here", "name_ko": "이 표가 안 다루는 것", - "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" }, { "key": "steps_m", "name_ko": "직고 칸", - "summary": "표가 갈리는 높이 경계(m)." + "summary": "표가 갈리는 높이 경계(m).", + "role": "value" }, { "key": "table_cm", "name_ko": "뒷길이 범위표", - "summary": "메·찰마다 직고 칸별 뒷길이 하한·상한(㎝)." + "summary": "메·찰마다 직고 칸별 뒷길이 하한·상한(㎝).", + "role": "value" } ] }, @@ -1333,6 +1419,13 @@ "shape": "map", "rows": 4, "columns": [ + { + "key": "@key", + "name_ko": "출처 키", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "doc", "name_ko": "문서", @@ -1358,67 +1451,80 @@ { "key": "back_lengths_cm", "name_ko": "뒷길이 규격", - "summary": "표가 값을 주는 뒷길이 일곱 칸." + "summary": "표가 값을 주는 뒷길이 일곱 칸.", + "role": "value" }, { "key": "backfill_ratio_of_back_length", "name_ko": "뒤채움 몫", - "summary": "뒷길이 가운데 뒤채움이 차지하는 비. 나머지가 잡석이다." + "summary": "뒷길이 가운데 뒤채움이 차지하는 비. 나머지가 잡석이다.", + "role": "value" }, { "key": "fallback", "name_ko": "미지정일 때", - "summary": "사용자가 안 고른 경우 쓰는 한 벌." + "summary": "사용자가 안 고른 경우 쓰는 한 벌.", + "role": "value" }, { "key": "fill_concrete_m3_per_m2", "name_ko": "채움 콘크리트 원단위", - "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. 원문이 두 줄뿐이다." + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. 원문이 두 줄뿐이다.", + "role": "value" }, { "key": "kinds", "name_ko": "돌 종류", - "summary": "야면석·호박돌 / 깬잡석 / 깬돌 / 견치돌 네 줄." + "summary": "야면석·호박돌 / 깬잡석 / 깬돌 / 견치돌 네 줄.", + "role": "value" }, { "key": "no_folding", "name_ko": "접지 않음 규칙", - "summary": "표에 없는 뒷길이를 가까운 칸으로 접지 않는다 — 접으면 값이 조용히 틀린다." + "summary": "표에 없는 뒷길이를 가까운 칸으로 접지 않는다 — 접으면 값이 조용히 틀린다.", + "role": "note" }, { "key": "not_here", "name_ko": "이 표가 안 다루는 것", - "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "option_key", "name_ko": "고르개 키", - "summary": "화면 고르개가 쓰는 저장 칸 이름." + "summary": "화면 고르개가 쓰는 저장 칸 이름.", + "role": "value" }, { "key": "option_note", "name_ko": "고르개 비고", - "summary": "고르개를 만들 때 챙길 것." + "summary": "고르개를 만들 때 챙길 것.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "wedge_stone_m3_per_m2", "name_ko": "고임돌 원단위", - "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. null 은 원문 「-」다." + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. null 은 원문 「-」다.", + "role": "value" }, { "key": "why", "name_ko": "까닭", - "summary": "이 벌을 왜 따로 두는지." + "summary": "이 벌을 왜 따로 두는지.", + "role": "note" } ] }, @@ -1433,22 +1539,26 @@ { "key": "items", "name_ko": "항목", - "summary": "이 벌이 담는 항목 묶음." + "summary": "이 벌이 담는 항목 묶음.", + "role": "value" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "rank", "name_ko": "우선순위", - "summary": "원문끼리 어긋날 때 어느 쪽을 먼저 보는지." + "summary": "원문끼리 어긋날 때 어느 쪽을 먼저 보는지.", + "role": "note" }, { "key": "scope", "name_ko": "걸치는 범위", - "summary": "어디까지 쓰는 값인지." + "summary": "어디까지 쓰는 값인지.", + "role": "note" } ] }, @@ -1670,6 +1780,13 @@ "shape": "map", "rows": 2, "columns": [ + { + "key": "@key", + "name_ko": "출처 키", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "doc", "name_ko": "문서", @@ -1716,32 +1833,38 @@ { "key": "double_count_rules/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "not_found/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "pending_choices/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "原文_뒷받침/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -2183,57 +2306,68 @@ { "key": "composite/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "composite/unit_conversion", "name_ko": "단위 환산", - "summary": "단가 단위와 원단위 단위가 달라 맞추는 값." + "summary": "단가 단위와 원단위 단위가 달라 맞추는 값.", + "role": "value" }, { "key": "concrete_placing", "name_ko": "콘크리트 타설 잇기", - "summary": "타설 방식 × 구조물 종류로 공종이 갈리는 자리." + "summary": "타설 방식 × 구조물 종류로 공종이 갈리는 자리.", + "role": "value" }, { "key": "ground_aliases_moved_to", "name_ko": "갈래 별칭 옮긴 자리", - "summary": "갈래 이름 별칭은 별칭표로 옮겼다. 여기 다시 두지 않는다." + "summary": "갈래 이름 별칭은 별칭표로 옮겼다. 여기 다시 두지 않는다.", + "role": "note" }, { "key": "masonry_class_reference", "name_ko": "돌쌓기 갈래 참고 자리", - "summary": "돌쌓기 갈래는 이제 참고용이고 어긋나면 그것이 신호다." + "summary": "돌쌓기 갈래는 이제 참고용이고 어긋나면 그것이 신호다.", + "role": "note" }, { "key": "master", "name_ko": "마스터 자리", - "summary": "공종 코드를 읽어 오는 마스터 파일." + "summary": "공종 코드를 읽어 오는 마스터 파일.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "pending_user/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "pipe", "name_ko": "배수관 잇기", - "summary": "관종으로 공종이 갈린다. 관 정본은 pipe_points 다." + "summary": "관종으로 공종이 갈린다. 관 정본은 pipe_points 다.", + "role": "value" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "variant_contract", "name_ko": "갈래 키 계약", - "summary": "갈래 키 문자열을 두 창이 각자 조립하지 않기로 한 약속." + "summary": "갈래 키 문자열을 두 창이 각자 조립하지 않기로 한 약속.", + "role": "note" } ] }, @@ -2294,7 +2428,8 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -2355,12 +2490,14 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" } ] }, @@ -2454,17 +2591,20 @@ { "key": "variables/aliases", "name_ko": "노임 별칭", - "summary": "코드 대신 쓰는 별칭 이름표(labor_1002 = 보통인부)." + "summary": "코드 대신 쓰는 별칭 이름표(labor_1002 = 보통인부).", + "role": "value" }, { "key": "variables/labor_rate/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/labor_rate/reliability_note", "name_ko": "신뢰도 기호 뜻풀이", - "summary": "노임 표의 * · ** 가 무엇을 뜻하는지." + "summary": "노임 표의 * · ** 가 무엇을 뜻하는지.", + "role": "note" } ] }, @@ -2564,7 +2704,8 @@ { "key": "variables/labor_mfg/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" } ] }, @@ -2910,52 +3051,62 @@ { "key": "parse_audit", "name_ko": "읽기 점검", - "summary": "취득가 표에서 못 읽은 줄이 있는지 적어 둔 자리." + "summary": "취득가 표에서 못 읽은 줄이 있는지 적어 둔 자리.", + "role": "note" }, { "key": "variables/mach_fuel_rate/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/mach_fuel_rate/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "variables/mach_fuel_rate/unit", "name_ko": "값 단위", - "summary": "연료량은 L/시간이다." + "summary": "연료량은 L/시간이다.", + "role": "note" }, { "key": "variables/mach_loss_coef/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/mach_loss_coef/unit", "name_ko": "값 단위", - "summary": "손료계수는 1/시간이다." + "summary": "손료계수는 1/시간이다.", + "role": "note" }, { "key": "variables/mach_operator_map/note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "variables/mach_price/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" }, { "key": "variables/mach_price/unit", "name_ko": "값 단위", - "summary": "취득가는 천원 단위다." + "summary": "취득가는 천원 단위다.", + "role": "note" }, { "key": "variables/mach_rock_adj/unit", "name_ko": "값 단위", - "summary": "할증은 %다." + "summary": "할증은 %다.", + "role": "note" } ] }, @@ -3034,27 +3185,32 @@ { "key": "derived_from", "name_ko": "무엇에서 나왔나", - "summary": "어느 벌을 풀어 만든 파생본인지." + "summary": "어느 벌을 풀어 만든 파생본인지.", + "role": "note" }, { "key": "dropped_tables", "name_ko": "못 읽어 버린 표", - "summary": "칸 수가 안 맞아 못 읽고 버린 원문 표." + "summary": "칸 수가 안 맞아 못 읽고 버린 원문 표.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "stats", "name_ko": "집계", - "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", + "role": "note" } ] }, @@ -3211,17 +3367,20 @@ { "key": "selection_policy", "name_ko": "고르는 방침", - "summary": "같은 물품이 여러 번 공고되면 어느 것을 쓰는지." + "summary": "같은 물품이 여러 번 공고되면 어느 것을 쓰는지.", + "role": "note" }, { "key": "source_row_count", "name_ko": "원천 줄 수", - "summary": "걸러 내기 전 원본 줄 수." + "summary": "걸러 내기 전 원본 줄 수.", + "role": "note" }, { "key": "variables/mat_price/key", "name_ko": "줄을 가르는 칸", - "summary": "이 표에서 줄 하나를 집는 칸 이름." + "summary": "이 표에서 줄 하나를 집는 칸 이름.", + "role": "note" } ] }, @@ -3266,6 +3425,13 @@ "shape": "map", "rows": 2, "columns": [ + { + "key": "@key", + "name_ko": "유종", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "value", "name_ko": "단가", @@ -3400,57 +3566,68 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "variables/oil_diesel/date", "name_ko": "기준일", - "summary": "값이 선 날." + "summary": "값이 선 날.", + "role": "note" }, { "key": "variables/oil_diesel/scope", "name_ko": "걸치는 범위", - "summary": "어디까지 쓰는 값인지." + "summary": "어디까지 쓰는 값인지.", + "role": "note" }, { "key": "variables/oil_diesel/source_product_code", "name_ko": "원천 제품코드", - "summary": "원천이 쓰는 제품 코드." + "summary": "원천이 쓰는 제품 코드.", + "role": "note" }, { "key": "variables/oil_diesel/source_product_name", "name_ko": "원천 제품명", - "summary": "원천이 쓰는 제품 이름." + "summary": "원천이 쓰는 제품 이름.", + "role": "note" }, { "key": "variables/oil_diesel/unit", "name_ko": "값 단위", - "summary": "단가는 원/L 이다." + "summary": "단가는 원/L 이다.", + "role": "note" }, { "key": "variables/oil_gasoline/date", "name_ko": "기준일", - "summary": "값이 선 날." + "summary": "값이 선 날.", + "role": "note" }, { "key": "variables/oil_gasoline/scope", "name_ko": "걸치는 범위", - "summary": "어디까지 쓰는 값인지." + "summary": "어디까지 쓰는 값인지.", + "role": "note" }, { "key": "variables/oil_gasoline/source_product_code", "name_ko": "원천 제품코드", - "summary": "원천이 쓰는 제품 코드." + "summary": "원천이 쓰는 제품 코드.", + "role": "note" }, { "key": "variables/oil_gasoline/source_product_name", "name_ko": "원천 제품명", - "summary": "원천이 쓰는 제품 이름." + "summary": "원천이 쓰는 제품 이름.", + "role": "note" }, { "key": "variables/oil_gasoline/unit", "name_ko": "값 단위", - "summary": "단가는 원/L 이다." + "summary": "단가는 원/L 이다.", + "role": "note" } ] }, @@ -3495,6 +3672,13 @@ "shape": "map", "rows": 5, "columns": [ + { + "key": "@key", + "name_ko": "통화", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "value", "name_ko": "환율", @@ -3899,147 +4083,176 @@ { "key": "processing_rules", "name_ko": "셈 규칙", - "summary": "요율만으로는 금액이 안 나온다 — 밑수를 어떻게 만들고 어디서 자르는지 적은 자리. 코드와 어긋나면 거울 시험이 잡는다." + "summary": "요율만으로는 금액이 안 나온다 — 밑수를 어떻게 만들고 어디서 자르는지 적은 자리. 코드와 어긋나면 거울 시험이 잡는다.", + "role": "note" }, { "key": "variables/rate_asbestos_contribution", "name_ko": "석면피해구제 분담금", - "summary": "노무비에 곱하는 율." + "summary": "노무비에 곱하는 율.", + "role": "value" }, { "key": "variables/rate_care", "name_ko": "노인장기요양보험료", - "summary": "건강보험료 금액에 곱하는 율." + "summary": "건강보험료 금액에 곱하는 율.", + "role": "value" }, { "key": "variables/rate_environment/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_environment/forest_road_selection_status", "name_ko": "임도 줄 고름 상태", - "summary": "임도에 어느 줄을 쓸지 고름이 끝났는지." + "summary": "임도에 어느 줄을 쓸지 고름이 끝났는지.", + "role": "note" }, { "key": "variables/rate_environment/minimum_estimated_amount_krw", "name_ko": "적용 하한 — 추정금액", - "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + "summary": "이 금액에 못 미치면 줄이 안 선다(원).", + "role": "value" }, { "key": "variables/rate_equipment_payment_guarantee/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_equipment_payment_guarantee/base_note", "name_ko": "밑수 비고", - "summary": "밑수를 그렇게 적은 까닭." + "summary": "밑수를 그렇게 적은 까닭.", + "role": "note" }, { "key": "variables/rate_goyong/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_health", "name_ko": "건강보험료", - "summary": "직접노무비에 곱하는 율." + "summary": "직접노무비에 곱하는 율.", + "role": "value" }, { "key": "variables/rate_indirect_labor/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_other_expense/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_overhead/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_pension/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_pension/rate_from_2033_percent", "name_ko": "2033년 이후 요율", - "summary": "표 밖으로 나가는 해부터 쓰는 율(%)." + "summary": "표 밖으로 나가는 해부터 쓰는 율(%).", + "role": "value" }, { "key": "variables/rate_performance_guarantee_fee/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_performance_guarantee_fee/typical_forest_road_applicability", "name_ko": "임도에 걸리는지", - "summary": "보통 임도 규모에서 이 항목이 서는지." + "summary": "보통 임도 규모에서 이 항목이 서는지.", + "role": "note" }, { "key": "variables/rate_profit/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_retirement_mutual_aid", "name_ko": "퇴직공제부금비", - "summary": "직접노무비에 곱하는 율. 추정금액 하한이 있다." + "summary": "직접노무비에 곱하는 율. 추정금액 하한이 있다.", + "role": "value" }, { "key": "variables/rate_safety_base", "name_ko": "산업안전보건관리비 기초액", - "summary": "요율표 안에 함께 든 기초액이 걸리는 구간." + "summary": "요율표 안에 함께 든 기초액이 걸리는 구간.", + "role": "value" }, { "key": "variables/rate_safety_pct/base_rule", "name_ko": "밑수 규칙", - "summary": "밑수를 고르는 방식." + "summary": "밑수를 고르는 방식.", + "role": "value" }, { "key": "variables/rate_safety_pct/base_with_owner_supplied_material", "name_ko": "대상액 — 관급자재 있을 때", - "summary": "고시가 준 두 식 가운데 작은 쪽." + "summary": "고시가 준 두 식 가운데 작은 쪽.", + "role": "value" }, { "key": "variables/rate_safety_pct/base_without_owner_supplied_material", "name_ko": "대상액 — 관급자재 없을 때", - "summary": "재료비 + 직접노무비." + "summary": "재료비 + 직접노무비.", + "role": "value" }, { "key": "variables/rate_safety_pct/manager_thresholds", "name_ko": "안전관리자 선임 기준액", - "summary": "안전관리자를 둬야 하는 금액 문턱." + "summary": "안전관리자를 둬야 하는 금액 문턱.", + "role": "value" }, { "key": "variables/rate_safety_pct/minimum_total_construction_amount_krw", "name_ko": "적용 하한 — 총공사금액", - "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + "summary": "이 금액에 못 미치면 줄이 안 선다(원).", + "role": "value" }, { "key": "variables/rate_sanjae", "name_ko": "산재보험료", - "summary": "노무비에 곱하는 율." + "summary": "노무비에 곱하는 율.", + "role": "value" }, { "key": "variables/rate_subcontract_payment_guarantee/base", "name_ko": "밑수", - "summary": "이 요율을 곱하는 대상." + "summary": "이 요율을 곱하는 대상.", + "role": "value" }, { "key": "variables/rate_vat", "name_ko": "부가가치세", - "summary": "공급가액에 곱하는 율." + "summary": "공급가액에 곱하는 율.", + "role": "value" }, { "key": "variables/rate_wage_claim_contribution", "name_ko": "임금채권보장 부담금", - "summary": "노무비에 곱하는 율." + "summary": "노무비에 곱하는 율.", + "role": "value" } ] }, @@ -4088,7 +4301,8 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -4143,7 +4357,8 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -4246,12 +4461,14 @@ { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" }, { "key": "stats", "name_ko": "집계", - "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것.", + "role": "note" } ] }, @@ -4300,7 +4517,8 @@ { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" } ] }, @@ -4393,6 +4611,13 @@ "shape": "map", "rows": 3, "columns": [ + { + "key": "@key", + "name_ko": "표 이름", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "note", "name_ko": "비고", @@ -4459,6 +4684,13 @@ "shape": "map", "rows": 15, "columns": [ + { + "key": "@key", + "name_ko": "칸 키", + "unit": "", + "visible": true, + "is_row_key": true + }, { "key": "label", "name_ko": "칸 이름", @@ -4514,42 +4746,50 @@ { "key": "code", "name_ko": "항목 코드", - "summary": "라이브러리 항목 코드." + "summary": "라이브러리 항목 코드.", + "role": "note" }, { "key": "differs_from_engine", "name_ko": "전개와 다른 자리", - "summary": "지금 돌아가는 전개와 이 양식이 갈리는 곳을 적어 둔 자리." + "summary": "지금 돌아가는 전개와 이 양식이 갈리는 곳을 적어 둔 자리.", + "role": "note" }, { "key": "item_kind", "name_ko": "항목 갈래", - "summary": "양식형(form)인지 고정형인지." + "summary": "양식형(form)인지 고정형인지.", + "role": "note" }, { "key": "library_tier", "name_ko": "라이브러리 단", - "summary": "프로그램·회사·개인 가운데 어느 단의 항목인지." + "summary": "프로그램·회사·개인 가운데 어느 단의 항목인지.", + "role": "note" }, { "key": "name", "name_ko": "항목 이름", - "summary": "화면에 보이는 이름." + "summary": "화면에 보이는 이름.", + "role": "note" }, { "key": "note", "name_ko": "설명", - "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글.", + "role": "note" }, { "key": "type_id", "name_ko": "구조물 종류 키", - "summary": "어느 구조물 종류에 붙는 양식인지." + "summary": "어느 구조물 종류에 붙는 양식인지.", + "role": "note" }, { "key": "unit_price/note", "name_ko": "일위대가 틀 설명", - "summary": "일위대가 줄을 어떻게 세우는지 적은 글." + "summary": "일위대가 줄을 어떻게 세우는지 적은 글.", + "role": "note" } ] }, @@ -4691,7 +4931,8 @@ { "key": "policy", "name_ko": "방침", - "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것.", + "role": "note" } ] }, @@ -4734,7 +4975,8 @@ { "key": "built_by", "name_ko": "만든 자리", - "summary": "이 벌을 지은 코드나 사람." + "summary": "이 벌을 지은 코드나 사람.", + "role": "note" } ] }, @@ -4777,12 +5019,14 @@ { "key": "built_by", "name_ko": "만든 자리", - "summary": "이 벌을 지은 코드나 사람." + "summary": "이 벌을 지은 코드나 사람.", + "role": "note" }, { "key": "source", "name_ko": "출처", - "summary": "어느 원문에서 왔는지." + "summary": "어느 원문에서 왔는지.", + "role": "note" } ] } diff --git a/resources/tester/test_master_labels_cover.py b/resources/tester/test_master_labels_cover.py index 3e9ec49a..250a6672 100644 --- a/resources/tester/test_master_labels_cover.py +++ b/resources/tester/test_master_labels_cover.py @@ -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"]