From 6bd45b0cb42d1306d5f54bf654dccc507ca118a0 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 17 Sep 2026 22:44:29 +0900 Subject: [PATCH] =?UTF-8?q?feat(b08):=20=EC=9B=90=EB=AC=B8=20=EB=8C=80?= =?UTF-8?q?=EC=A1=B0=20=EB=B0=91=EC=88=98=2060=EA=B1=B4=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=E2=80=94=2016=20=EC=B1=84=EC=9B=80=20=C2=B7=20?= =?UTF-8?q?=EC=99=9C=EA=B3=A1=201=20=EA=B3=A0=EC=B9=A8=20=C2=B7=20?= =?UTF-8?q?=EB=82=98=EB=A8=B8=EC=A7=80=EB=8A=94=20=EC=82=AC=EC=9C=A0?= =?UTF-8?q?=EB=A1=9C=20=EB=82=A8=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 브레인 일감 ①. 안티그래비티 전수 대조 보고(02544795)의 `item3_basis` 60건을 **하나씩 원문 줄을 열어 확인**한 뒤 반영. 값(숫자)은 한 칸도 안 건드림(원문 셀 453/453 그대로). - **채움 16** — 원문 괄호가 분명하고 **분모가 하나**인 것만 (3-8 드론 영상 ha · 10-7-4·10-8 기·일 · 12-7·12-8 일 · 13-8 ㎡ · 13-14 개 …) - **왜곡 고침 1** — 13-10-2 윈치말뚝 박기: 원문 L7489 가 「(단위: 1일당)」인데 「개」로 서 있었음 - **거절 27 + 확인 뒤 기각** — 사유를 코드 주석에 남김 · ⚠ 보고가 「인」을 밑수로 적은 셋(F0228·F0229·F0230)은 **2026-09-09 에 오독으로 판정된 바로 그 표**(8-6-2 드론방제·8-6-3 지상방제) — 안 넣음 · 분모가 둘인 자리(3-2 작업로 선정 「인/1일 1km당」 · 8-11 「1대 1조, 시간당」) — 반쪽은 안 적음 · `coefficient`·`reference` 표는 밑수가 없음 · 「%」·「회」·「분/1회」·「공㎥」·「인/조」는 단위가 아님 - **보고가 틀린 자리 둘** — F0223 은 원문이 「100본/ha당」이라 마스터(ha)가 맞고, F0235 는 표머리가 「소요인력(인/본당)」이라 마스터(본)가 맞음. 보고대로 고쳤으면 뒤집힐 뻔했음 밑수 확보 227 → 243(미확보 103 → 92) · 지문 한 번 갱신(더하기 16 + 왜곡 고침 1) Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF --- ...B08_Quantity_Build_WorkItemMaster_Forms.py | 23 ++++ .../data_master_labels/labels_2026-01-01.json | 2 +- .../data_work_item_master/_manifest.json | 10 +- .../_manifest_const.json | 4 +- .../basis_missing_2026-01-01.json | 66 ----------- .../const_work_item_master_2026-01-01.json | 2 +- .../work_item_master_2026-01-01.json | 106 +++++++++--------- .../tester/test_work_item_key_registry.py | 32 +++++- 8 files changed, 114 insertions(+), 131 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py index 7edb4a44..fa97db26 100644 --- a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py +++ b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py @@ -203,6 +203,29 @@ BASIS_JUDGMENTS: dict[str, tuple[str, float, str, str]] = { "F0323": ("10-13-2", 1000.0, "본", "위와 같음"), "F0333": ("12-1-3", 1.0, "㎥", "원문 「㎥당」"), "F0346": ("12-11-1", 1.0, "m", "원문 「m당」"), + # ── 원문 md ↔ 마스터 전수 대조 60건 중 **원문 괄호가 분명하고 분모가 하나인 것만** ──── + # 안티그래비티 보고(02544795) · 원문 줄을 직접 열어 괄호 글을 확인한 것만 싣는다. + # ⚠ 보고가 적은 단위를 그대로 믿지 않는다 — 「인」을 밑수로 적은 자리가 셋 있었고 + # 그 자리(8-6-2 드론방제·8-6-3 지상방제)는 **2026-09-09 에 오독으로 판정된 바로 그 표**다. + "F0082": ("3-8", 1.0, "ha", "드론 영상 촬영 — 원문 「(단위 : 인/ha)」"), + "F0256": ("9-11-1", 1.0, "일", "원문 「(단위: 일당)」"), + "F0310": ("10-7-4", 1.0, "일", "원문 「(단위: 인/1일당)」"), + "F0311": ("10-7-4", 1.0, "기", "원문 「(단위: 1기당)」"), + "F0312": ("10-7-4", 1.0, "일", "원문 「(단위: 1일당)」"), + "F0313": ("10-8-1", 1.0, "일", "원문 「(단위: 인/1일당)」"), + "F0314": ("10-8-2", 1.0, "기", "원문 「(단위: 1기당)」"), + "F0315": ("10-8-3", 1.0, "일", "원문 「(단위: 1일당)」"), + "F0339": ("12-7-1", 1.0, "일", "원문 「(단위: 일당)」"), + "F0340": ("12-7-2", 1.0, "일", "원문 「(단위: 일당)」"), + "F0341": ("12-8", 1.0, "일", "원문 「(단위: 일당)」"), + "F0356": ("12-17-1", 1.0, "일", "원문 「(단위: ㎥/일 당)」"), + "F0395": ("12-38-3", 1.0, "일", "원문 「(단위: 일 당)」"), + "F0424": ("13-8", 1.0, "㎡", "원문 「(단위: 인/㎡)」"), + "F0444": ("13-14", 1.0, "개", "원문 「(단위: 인/개)」"), + "F0449": ("13-16-2", 1.0, "일", "원문 「(단위: 일 당)」"), + # ⚠ **왜곡 고침 하나** — 값이 아니라 **밑수 단위**가 틀려 있던 자리. + # 원문 L7489 가 「(단위: 1일당)」인데 마스터가 「개」로 서 있었다(13-10-2 윈치말뚝 박기). + "F0430": ("13-10-2", 1.0, "일", "왜곡 고침 — 원문 「(단위: 1일당)」인데 「개」로 서 있었음"), } diff --git a/resources/data_master_labels/labels_2026-01-01.json b/resources/data_master_labels/labels_2026-01-01.json index 1ef48980..285933e1 100644 --- a/resources/data_master_labels/labels_2026-01-01.json +++ b/resources/data_master_labels/labels_2026-01-01.json @@ -6327,7 +6327,7 @@ "name_ko": "밑수 못 찾은 표", "summary": "기준 수량을 못 읽은 품셈 표. 1 단위당으로 단정하면 곱셈이 틀린다.", "shape": "list", - "rows": 103, + "rows": 92, "columns": [ { "key": "pum_table_id", diff --git a/resources/data_work_item_master/_manifest.json b/resources/data_work_item_master/_manifest.json index c505f6c3..fae01537 100644 --- a/resources/data_work_item_master/_manifest.json +++ b/resources/data_work_item_master/_manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "dataset_id": "data_work_item_master_manifest", - "generated_at": "2026-09-17T22:26:44+09:00", + "generated_at": "2026-09-17T22:38:16+09:00", "built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py", "source": { "dataset_id": "pum_forest", @@ -12,8 +12,8 @@ "files": [ { "file": "work_item_master_2026-01-01.json", - "sha256": "b73d3d9ce7c4c6de7d8c99cb2db54ce32285b4a2c37b60962b7be8beb800abce", - "size_bytes": 925751 + "sha256": "094c56c75dfa76e2acf2904cea7e6959a1998ceccaa46bf9f83bcdf9c9f3fdd4", + "size_bytes": 926610 }, { "file": "form_undetermined_2026-01-01.json", @@ -22,8 +22,8 @@ }, { "file": "basis_missing_2026-01-01.json", - "sha256": "13b663780bca6143a126a2a873ff31b0a9eeb2aa41ea89e928b9c6a23537b164", - "size_bytes": 14212 + "sha256": "e68975380e77d3f2d016cc264c22382335019220ad16ac9c3ad16cfb82e5769d", + "size_bytes": 12739 } ] } \ No newline at end of file diff --git a/resources/data_work_item_master/_manifest_const.json b/resources/data_work_item_master/_manifest_const.json index afb93c62..7f2017b0 100644 --- a/resources/data_work_item_master/_manifest_const.json +++ b/resources/data_work_item_master/_manifest_const.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "dataset_id": "data_work_item_master_manifest", - "generated_at": "2026-09-17T22:27:36+09:00", + "generated_at": "2026-09-17T22:39:08+09:00", "built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py", "source": { "dataset_id": "pum_const", @@ -12,7 +12,7 @@ "files": [ { "file": "const_work_item_master_2026-01-01.json", - "sha256": "9bd4b0be9cf27df23781fdd9feea8ed7be2427e815db0563bc2b9eeb79a2f98b", + "sha256": "4e1d7fe8080913d17730395da18d4c039c432bca7b92e38a62d765a0b098314e", "size_bytes": 3839594 }, { diff --git a/resources/data_work_item_master/basis_missing_2026-01-01.json b/resources/data_work_item_master/basis_missing_2026-01-01.json index 8fa3f89a..4058563e 100644 --- a/resources/data_work_item_master/basis_missing_2026-01-01.json +++ b/resources/data_work_item_master/basis_missing_2026-01-01.json @@ -52,12 +52,6 @@ "pum_form": "requirement", "line": 1815 }, - { - "pum_table_id": "F0082", - "section": "3-8. 드론 영상 촬영", - "pum_form": "requirement", - "line": 1901 - }, { "pum_table_id": "F0083", "section": "4-1-1. 임업용 동력기계톱", @@ -472,12 +466,6 @@ "pum_form": "requirement", "line": 4860 }, - { - "pum_table_id": "F0256", - "section": "9-11-1. 콘크리트(기계)", - "pum_form": "requirement", - "line": 4946 - }, { "pum_table_id": "F0294", "section": "9-21. 제근", @@ -490,42 +478,6 @@ "pum_form": "requirement", "line": 5669 }, - { - "pum_table_id": "F0310", - "section": "10-7-4. 모노레일 운반", - "pum_form": "requirement", - "line": 5770 - }, - { - "pum_table_id": "F0311", - "section": "10-7-4. 모노레일 운반", - "pum_form": "requirement", - "line": 5779 - }, - { - "pum_table_id": "F0312", - "section": "10-7-4. 모노레일 운반", - "pum_form": "requirement", - "line": 5795 - }, - { - "pum_table_id": "F0313", - "section": "10-8-1. 짐내리기", - "pum_form": "requirement", - "line": 5813 - }, - { - "pum_table_id": "F0314", - "section": "10-8-2. 운반대 설치", - "pum_form": "requirement", - "line": 5829 - }, - { - "pum_table_id": "F0315", - "section": "10-8-3. 케이블 크레인 운전", - "pum_form": "requirement", - "line": 5840 - }, { "pum_table_id": "F0317", "section": "10-10-1. 콘크리트 및 골재운반(지상)", @@ -556,12 +508,6 @@ "pum_form": "requirement", "line": 6499 }, - { - "pum_table_id": "F0356", - "section": "12-2 표면 마무리를 따른다.", - "pum_form": "productivity", - "line": 6520 - }, { "pum_table_id": "F0362", "section": "12-2 표면 마무리를 따른다.", @@ -592,12 +538,6 @@ "pum_form": "requirement", "line": 7087 }, - { - "pum_table_id": "F0424", - "section": "13-8. 막돌쌓기", - "pum_form": "requirement", - "line": 7415 - }, { "pum_table_id": "F0437", "section": "13-12-1. 뭉기기", @@ -610,12 +550,6 @@ "pum_form": "requirement", "line": 7625 }, - { - "pum_table_id": "F0444", - "section": "13-14. 식생토낭 및 포트", - "pum_form": "requirement", - "line": 7715 - }, { "pum_table_id": "F0447", "section": "13-15-2. 목책 설치", diff --git a/resources/data_work_item_master/const_work_item_master_2026-01-01.json b/resources/data_work_item_master/const_work_item_master_2026-01-01.json index eea2afc7..f492fe44 100644 --- a/resources/data_work_item_master/const_work_item_master_2026-01-01.json +++ b/resources/data_work_item_master/const_work_item_master_2026-01-01.json @@ -4,7 +4,7 @@ "effective_date": "2026-01-01", "pum_edition": "2026-01-01", "toc_edition": "2026-01-01", - "generated_at": "2026-09-17T22:27:36+09:00", + "generated_at": "2026-09-17T22:39:08+09:00", "dataset_version": { "dataset_id": "pum_const", "effective_date": "2026-01-01", diff --git a/resources/data_work_item_master/work_item_master_2026-01-01.json b/resources/data_work_item_master/work_item_master_2026-01-01.json index ff77f795..19ce6db8 100644 --- a/resources/data_work_item_master/work_item_master_2026-01-01.json +++ b/resources/data_work_item_master/work_item_master_2026-01-01.json @@ -4,7 +4,7 @@ "effective_date": "2026-01-01", "pum_edition": "2026-01-01", "toc_edition": "산림청고시제2025-82호", - "generated_at": "2026-09-17T22:26:44+09:00", + "generated_at": "2026-09-17T22:38:16+09:00", "dataset_version": { "dataset_id": "pum_forest", "effective_date": "2026-01-01", @@ -25,8 +25,8 @@ "tables_attached": 453, "tables_orphan": 22, "form_undetermined": 0, - "basis_found": 227, - "basis_missing": 103, + "basis_found": 243, + "basis_missing": 92, "basis_grouped": 54, "axis_roles": { "general_provision": 78, @@ -6732,9 +6732,9 @@ "source_line": 1901, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "ha", + "basis_source": "사람 판정 — 드론 영상 촬영 — 원문 「(단위 : 인/ha)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -22238,9 +22238,9 @@ "source_line": 4946, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -26773,9 +26773,9 @@ "source_line": 5770, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 인/1일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -26806,9 +26806,9 @@ "source_line": 5779, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "기", + "basis_source": "사람 판정 — 원문 「(단위: 1기당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -26890,9 +26890,9 @@ "source_line": 5795, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 1일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -26967,9 +26967,9 @@ "source_line": 5813, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 인/1일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -27049,9 +27049,9 @@ "source_line": 5829, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "기", + "basis_source": "사람 판정 — 원문 「(단위: 1기당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -27106,9 +27106,9 @@ "source_line": 5840, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 1일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -29361,9 +29361,9 @@ "source_line": 6254, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -29431,9 +29431,9 @@ "source_line": 6269, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -29484,9 +29484,9 @@ "source_line": 6280, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -31131,9 +31131,9 @@ "source_line": 6520, "pum_form": "productivity", "form_basis": "사람 판정 — 혼합 — 값이 「㎥/일」이라 생산량형", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: ㎥/일 당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -33982,9 +33982,9 @@ "source_line": 6943, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일 당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -37556,9 +37556,9 @@ "source_line": 7415, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "㎡", + "basis_source": "사람 판정 — 원문 「(단위: 인/㎡)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -37896,8 +37896,8 @@ "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", "basis_quantity": 1.0, - "basis_unit": "개", - "basis_source": "표 안", + "basis_unit": "일", + "basis_source": "사람 판정 — 왜곡 고침 — 원문 「(단위: 1일당)」인데 「개」로 서 있었음", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -39079,9 +39079,9 @@ "source_line": 7715, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "개", + "basis_source": "사람 판정 — 원문 「(단위: 인/개)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -39500,9 +39500,9 @@ "source_line": 7788, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "일", + "basis_source": "사람 판정 — 원문 「(단위: 일 당)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], diff --git a/resources/tester/test_work_item_key_registry.py b/resources/tester/test_work_item_key_registry.py index 83874a65..b0eb09d7 100644 --- a/resources/tester/test_work_item_key_registry.py +++ b/resources/tester/test_work_item_key_registry.py @@ -45,6 +45,8 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json" #: 2026-09-17 두 번 갱신 — 둘 다 **더하기만**(덮어쓴 것 0 · 사라진 것 0): #: ① 표머리 몫꼴(`인/ha`·`인/100kg`)에서 밑수 18개를 새로 읽음 #: ② 형태 미판정 14표를 사람 판정으로 가름(안티그래비티 원문 대조) · 그중 5표는 밑수도 확인 +#: ③ 원문 전수 대조 60건 중 **원문 괄호가 분명한 16표**의 밑수를 채움 +#: ⚠ 그 가운데 **하나(F0430)만 값이 바뀜** — 원문이 「1일당」인데 「개」로 서 있던 왜곡을 고침 #: ⇒ 곱하면 안 되던 줄이 곱할 수 있게 된 것이지, 있던 값이 바뀐 것이 아니다. #: 2026-09-17 랩탑 메인 — 목차 오기 둘을 본문 번호로 바로잡아(브레인 지시) **네 줄만** 바뀌어 새로 뜸 #: (옛 f8b8fba1…). 네 줄 모습은 `test_목차_오기는_본문_번호로_바로잡고_열쇠는_그대로` 가 잼 · @@ -52,7 +54,7 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json" #: 2026-09-17 랩탑 메인 둘째 — 헛단위 뺌(인용을 제목으로 읽은 13-3 표 셋 · 부록 사례 번호 겹침 일곱)으로 다시 뜸 #: (옛 be88f730…). 바뀐 줄은 13-3·4-1·4-2·2-1·2-2·3-1·3-2·3-3·13-4-1·13-5-2 의 표 귀속뿐 — #: `test_work_item_master_toc` 가 자리를 잼 · 단가표 대조는 그 파일 머리. -BASELINE_WORK_ITEMS_SHA = "cd9a0e755249fb408c01499e980afed02a7b882b36ae7029a5bd35ab63f5c5da" +BASELINE_WORK_ITEMS_SHA = "4c97958865d1779eacff4696ea77d35534044b8f81b2ef3033935ead2aadb6bc" #: 열쇠 작업이 새로 얹은 칸. 지문을 잴 때만 떼어낸다. ADDED_FIELDS = ( @@ -354,13 +356,37 @@ def test_산림_형태_미판정이_없다(master: dict) -> None: for table_id, form in 가른것.items(): assert by_id[table_id]["pum_form"] == form, table_id assert by_id[table_id]["form_basis"].startswith("사람 판정"), table_id - # 머리가 소실돼 자동으로는 못 읽는 표의 밑수만 손으로 적는다 - assert set(BASIS_JUDGMENTS) <= set(가른것) + # 미판정 열넷 가운데 머리가 소실돼 자동으로는 못 읽는 표의 밑수를 손으로 적었다 + # (그 뒤 원문 전수 대조로 다른 표들도 들어와 `BASIS_JUDGMENTS` 는 더 넓다) + assert {"F0140", "F0322", "F0333", "F0346"} <= set(BASIS_JUDGMENTS) assert by_id["F0140"]["basis_quantity"] == 100.0 and by_id["F0140"]["basis_unit"] == "㎡" assert by_id["F0322"]["basis_quantity"] == 1000.0 and by_id["F0322"]["basis_unit"] == "본" assert judged_form("F0140", "5-26-1")[0] == "requirement" +def test_원문_대조_밑수_판정(master: dict) -> None: + """원문 md ↔ 마스터 전수 대조(안티그래비티 02544795)에서 나온 밑수를 반영했는가. + + ⚠ **보고가 적은 단위를 그대로 믿지 않는다.** 보고는 「인」을 밑수로 적은 자리가 셋 있었고 + 그 자리(8-6-2 드론방제·8-6-3 지상방제)는 2026-09-09 에 오독으로 판정된 바로 그 표다. + 원문 줄을 열어 괄호 글을 확인한 것만, 그것도 **분모가 하나일 때만** 싣는다. + """ + by_id = {t["pum_table_id"]: t for it in master["work_items"] for t in it["tables"]} + for table_id, quantity, unit in ( + ("F0082", 1.0, "ha"), # (단위 : 인/ha) + ("F0311", 1.0, "기"), # (단위: 1기당) + ("F0424", 1.0, "㎡"), # (단위: 인/㎡) + ("F0430", 1.0, "일"), # ⚠ 왜곡 고침 — 「개」로 서 있었음 + ): + assert by_id[table_id]["basis_quantity"] == quantity, table_id + assert by_id[table_id]["basis_unit"] == unit, table_id + # 「인」은 밑수가 아니다 — 보고가 그렇게 적었어도 안 넣는다 + for table_id in ("F0228", "F0229", "F0230"): + assert by_id[table_id]["basis_unit"] != "인", table_id + # 분모가 둘인 자리도 안 넣는다 — 3-2 작업로 선정은 원문이 「인/1일 1km당」이다 + assert by_id["F0076"]["basis_unit"] != "ha" + + def test_표머리_몫꼴_밑수_읽기() -> None: """「당」 없이 몫으로만 적힌 표머리에서 밑수를 읽는다 — 분모가 밑수다(명세 꼴 B).