From 5cdf30561979a0d231e258cca5d10cf3b4a197ae Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 18 Sep 2026 04:08:13 +0900 Subject: [PATCH] =?UTF-8?q?feat(b08):=20=ED=99=95=EC=9D=B8=20=EB=8C=80?= =?UTF-8?q?=EA=B8=B0=2075=EA=B1=B4=EC=9D=84=20=EC=85=8B=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EA=B0=80=EB=A6=84(=E3=89=AE41=C2=B7=E3=89=AF23=C2=B7?= =?UTF-8?q?=E3=89=B011)=20=C2=B7=20=E3=80=8C=EB=8B=B9=E3=80=8D=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=AA=AB=20=EA=BC=B4=EC=9D=84=20=EC=9D=BD=EC=96=B4?= =?UTF-8?q?=20=EB=B0=91=EC=88=98=20251?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **① 확인 대기 가르기** — 「다 사유 있음」으로 뭉쳐 있던 것을 갈래로 나눠 **무엇이 진짜 할 일인지** 보이게 함 ㉮ **영영 할 일 아님 41** — 「일당」은 품의 단위 · 작업조 표(넣으면 호표가 사라짐) · 「인/조」 · 사람 판정으로 닫힌 표 성격 7 · 비목 구성표 7 따위. **집계에서 갈라 둠**(다음 바퀴에 또 안 세어짐) ㉯ **남이 고쳐야 풀림 23** — [주] 17(코덱스 md 읽기 넓히기) · 밑수 5(마스터가 맞고 md 가 덜 읽음) · F0333 원문 md 의심(코덱스 PDF 대조) ㉰ **사용자 판단 필요 11** — ⚠ 아래 셋이 제근 9-21 같은 자리 · F0046·F0068 마스터 밑수가 「1인」 — 「인」은 밑수가 아니라는 2026-09-09 판정과 어긋남 · F0076 「1km」는 반쪽 — 원문은 「인/1일 1km당」으로 분모가 둘 · 그 밖 부록 표 셋(떼어 낼지) · F0405 증가율표 성격 · 토량환산계수 2 · 이형철근 범위 · rebar 1 **② 「당」 없이 몫으로만 적힌 자리를 읽게 함** — 「(인/100㎡)」·「(인/ha)」·「(인/㎡)」·「(대/ton)」. ⚠ 이 구멍으로 다섯 표가 「원문 부재」로 **잘못 세어지고 있었음**(실은 원문이 적어 둔 것). 가림을 넓히고 그 다섯을 사람 판정으로 채움 ⇒ 밑수 확보 246 → **251** · 미확보 84 → 79 (원문 부재 69 + 미판독 10) 시험 — 장부 비교에서 **사람이 적은 메모 칸**(`why`·`class`·`class_why`)을 빼도록 함(자료가 아니라 설명) Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF --- ...B08_Quantity_Build_WorkItemMaster_Forms.py | 8 + ...B08_Quantity_Build_WorkItemMaster_Table.py | 10 +- .../data_master_labels/labels_2026-01-01.json | 2 +- .../data_work_item_master/_manifest.json | 10 +- .../_manifest_const.json | 8 +- .../basis_missing_2026-01-01.json | 37 +-- .../const_basis_missing_2026-01-01.json | 62 ++-- .../const_work_item_master_2026-01-01.json | 6 +- .../work_item_master_2026-01-01.json | 42 +-- .../fixtures/base_data_source_known.json | 32 +- .../work_item_master_source_known.json | 306 ++++++++++++------ .../tester/test_work_item_key_registry.py | 16 +- .../test_work_item_master_source_match.py | 7 +- 13 files changed, 324 insertions(+), 222 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py index 629a41a2..0c03a98d 100644 --- a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py +++ b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Forms.py @@ -284,6 +284,14 @@ BASIS_JUDGMENTS: dict[str, tuple[str, float, str, str]] = { "F0050": ("2-1-4", 1.0, "ha", "페인트·마킹테이프 — 표머리 「재료비 (ha당 소요량)」"), "F0052": ("2-1-4", 1.0, "ha", "위와 같음(다른 표)"), "F0224": ("8-5", 1.0, "ha", "페르몬 유인트랩 — 표머리 「소요인력(조/ha당)」"), + # ── 「당」 없이 몫으로만 적힌 자리 다섯 (2026-09-18 · 장부에 숨어 있던 것) ────────── + # 원문이 표 바로 위에 「(인/100㎡)」·「(인/ha)」·「(인/㎡)」·「(대/ton)」 로 적어 둔 것. + # ⚠ 「당」 글자가 없어 자동 판정이 못 읽었다 — 규칙을 넓히기보다 표마다 적는다. + "F0089": ("4-4", 100.0, "㎡", "가지정리 — 원문 「(인/100㎡)」"), + "F0090": ("4-5", 1.0, "ha", "벌도 위험목 점검 — 원문 「(인/ha)」"), + "F0117": ("5-12", 100.0, "㎡", "떼붙임(재배잔디) — 원문 「(인/100㎡)」"), + "F0129": ("5-21", 1.0, "㎡", "표토이식 — 원문 「(인/㎡)」"), + "F0191": ("7-11", 1.0, "톤", "동력상하차기 — 원문 「(대/ton)」"), } diff --git a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Table.py b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Table.py index e0b1ef82..258a8bc6 100644 --- a/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Table.py +++ b/B08_Quantity/B08_Quantity_Build_WorkItemMaster_Table.py @@ -244,7 +244,15 @@ def person_basis_ok(raw_quantity: str | None, unit: str | None) -> bool: #: 원문이 **밑수 같은 글을 아예 안 적었나**를 보는 표지. 괄호에 「당」이나 「단위」가 있으면 적은 것이다. -_DECLARES_RE = re.compile(r"[((][^))]*(?:당|단위)[^))]*[))]") +#: ⚠ 「당」·「단위」가 없어도 **몫 꼴**이면 적어 둔 것이다 — 「(인/100㎡)」·「(대/ton)」. +#: 2026-09-18 에 이 구멍으로 다섯 표가 「원문 부재」로 잘못 세어졌다(실은 원문이 적어 둔 것). +#: ⚠ 단위 글자를 여기 직접 적는다 — 아래 `_NUMER`·`_DENOM` 보다 먼저 쓰이는 자리다. +_DECLARES_RE = re.compile( + "[((][^))]*(?:당|단위)[^))]*[))]" + "|[((]\\s*(?:인|공|조|대|ℓ|L|kg|㎏|톤|ton|본|매|개|주|m|㎥|㎡|시간|hr)" + "\\s*/\\s*[\\d,]*\\.?\\d*\\s*" + "(?:㎥|m3|㎡|m2|㏊|ha|㎞|km|m|매|본|개소|개|인|공|kg|㎏|톤|ton|주|식|대|일|시간|hr)\\s*[))]" +) #: 표 위아래로 얼마나 볼 것인가. 머리글 줄도 함께 본다. DECLARE_LOOK = 6 diff --git a/resources/data_master_labels/labels_2026-01-01.json b/resources/data_master_labels/labels_2026-01-01.json index 366ea7a3..ff183818 100644 --- a/resources/data_master_labels/labels_2026-01-01.json +++ b/resources/data_master_labels/labels_2026-01-01.json @@ -6363,7 +6363,7 @@ "name_ko": "밑수 못 찾은 표", "summary": "기준 수량을 못 읽은 품셈 표. 1 단위당으로 단정하면 곱셈이 틀린다.", "shape": "list", - "rows": 84, + "rows": 79, "columns": [ { "key": "pum_table_id", diff --git a/resources/data_work_item_master/_manifest.json b/resources/data_work_item_master/_manifest.json index 4332766d..7d84e25e 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-18T03:43:54+09:00", + "generated_at": "2026-09-18T03:54:25+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": "4e3a9d45776274099c58effe1dec29b4ccc22d7704d6652e4fcda8911807928a", - "size_bytes": 1081560 + "sha256": "4c4e683c96e5eeac8fc0fd23a3a702f34ddaf51971538efaba2bd928f4faab6d", + "size_bytes": 1081872 }, { "file": "form_undetermined_2026-01-01.json", @@ -22,8 +22,8 @@ }, { "file": "basis_missing_2026-01-01.json", - "sha256": "194ccc0066b9b91fdaf91973bb4fe13305c6e073ecf5b99b8d04f3d8350d85e9", - "size_bytes": 19381 + "sha256": "364633582954336f298477ea0229e239b0baca9284d43c2da01e35aac83d2cbe", + "size_bytes": 18207 } ] } \ 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 2f53ba9b..7f0ee2eb 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-18T03:44:44+09:00", + "generated_at": "2026-09-18T03:55:16+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": "91239832a71e6bcf6560a9570dec049fc323ce5630afcc7c986292bfa4dd9e91", + "sha256": "2cae9743b500696485a471905a2338c1547e386baf3de4d34f874a9b86c9adbd", "size_bytes": 4501303 }, { @@ -22,8 +22,8 @@ }, { "file": "const_basis_missing_2026-01-01.json", - "sha256": "ff9b91fd0a605c7268ef5e39d66f06f219b733a8ca1d79d5840af2e436a3642b", - "size_bytes": 111352 + "sha256": "5d90f7894d6306eb493325ef6759116238839a0c6b183073d3f83c452508fe15", + "size_bytes": 110670 } ] } \ No newline at end of file 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 47bf2ad0..9632280e 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 @@ -67,20 +67,6 @@ "line": 1957, "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" }, - { - "pum_table_id": "F0089", - "section": "4-4. 가지정리", - "pum_form": "requirement", - "line": 2041, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" - }, - { - "pum_table_id": "F0090", - "section": "4-5. 벌도 위험목 점검", - "pum_form": "requirement", - "line": 2052, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" - }, { "pum_table_id": "F0091", "section": "4-6. 벌목부 작업안전 보조", @@ -109,13 +95,6 @@ "line": 2355, "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" }, - { - "pum_table_id": "F0117", - "section": "5-12. 떼붙임(재배잔디)", - "pum_form": "requirement", - "line": 2496, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" - }, { "pum_table_id": "F0127", "section": "5-19-2. 표토펴기 및 고르기", @@ -123,13 +102,6 @@ "line": 2668, "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" }, - { - "pum_table_id": "F0129", - "section": "5-21. 표토이식", - "pum_form": "requirement", - "line": 2693, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" - }, { "pum_table_id": "F0154", "section": "6-2-1. 둘레베기", @@ -291,13 +263,6 @@ "line": 3647, "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" }, - { - "pum_table_id": "F0191", - "section": "7-11. 동력상하차기(우드그래플) 집재-수확", - "pum_form": "requirement", - "line": 3761, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" - }, { "pum_table_id": "F0192", "section": "7-12. 동력상하차기(우드그래플) 집적", @@ -443,7 +408,7 @@ "section": "8-3. 소각, 매몰, 훈증, 박피", "pum_form": "productivity", "line": 4364, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "F0228", diff --git a/resources/data_work_item_master/const_basis_missing_2026-01-01.json b/resources/data_work_item_master/const_basis_missing_2026-01-01.json index b3e329b5..ed8cbf1c 100644 --- a/resources/data_work_item_master/const_basis_missing_2026-01-01.json +++ b/resources/data_work_item_master/const_basis_missing_2026-01-01.json @@ -233,7 +233,7 @@ "section": "3-7-5 비탈면 보강공('08년 신설, '14, '20, '25년 보완)", "pum_form": "requirement", "line": 574, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0206", @@ -303,7 +303,7 @@ "section": "2-2-2 주요자재 / 강재류’를 적용한다.5-1-7 어스앵커 공법('20, '26년 보완)", "pum_form": "requirement", "line": 98, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0263", @@ -359,7 +359,7 @@ "section": "5-2-2 고압분사 주입공법('09, '15, '21, '26년 보완)", "pum_form": "requirement", "line": 394, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0281", @@ -394,7 +394,7 @@ "section": "85-3 말뚝5-3-1 기성말뚝 기초('99년 신설, '15, '16, '20, '26년 보완)", "pum_form": "requirement", "line": 555, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0297", @@ -422,7 +422,7 @@ "section": "5-3-2 말뚝박기용 천공('08, '15, '16, '20, '25, '26년 보완)", "pum_form": "requirement", "line": 678, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0308", @@ -548,7 +548,7 @@ "section": "5-3.2-5.5-타 이 어-----3.1-4.0-5.7", "pum_form": "requirement", "line": 182, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0434", @@ -583,7 +583,7 @@ "section": "8-2-19 콘크리트 운반", "pum_form": "requirement", "line": 1062, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0494", @@ -611,7 +611,7 @@ "section": "8-2-23 유압 파일 해머", "pum_form": "requirement", "line": 1162, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0500", @@ -625,14 +625,14 @@ "section": "8-2-24 진동파일 해머('96, '26년 보완)", "pum_form": "requirement", "line": 1238, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0514", "section": "8-2-24 진동파일 해머('96, '26년 보완)", "pum_form": "requirement", "line": 1314, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0518", @@ -646,21 +646,21 @@ "section": "8-2-25 진동파일해머(워터제트 병용 압입공)", "pum_form": "requirement", "line": 1398, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0526", "section": "8-2-25 진동파일해머’를 따른다.8-2-26 유압식 압입 인발기(유압식 압입 인발공)", "pum_form": "requirement", "line": 1449, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0533", "section": "8-2-29 펌프식 준설선('10, '11년 보완)", "pum_form": "requirement", "line": 1539, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0534", @@ -982,91 +982,91 @@ "section": "8-4 운전경비 산정('08, '09, '10, '11, '12, '13, '14, '15, '16, '17년 보완)8-4-1 [00]토공기계", "pum_form": "requirement", "line": 3502, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0728", "section": "8-4 운전경비 산정('08, '09, '10, '11, '12, '13, '14, '15, '16, '17년 보완)8-4-1 [00]토공기계", "pum_form": "requirement", "line": 3508, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0729", "section": "8-4-2 [10]다짐기계", "pum_form": "requirement", "line": 3514, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0730", "section": "8-4-3 [20]운반 및 하역기계('21년 보완)", "pum_form": "requirement", "line": 3520, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0731", "section": "8-4-3 [20]운반 및 하역기계('21년 보완)", "pum_form": "requirement", "line": 3526, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0732", "section": "8-4-4 [30]포장기계", "pum_form": "requirement", "line": 3532, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0733", "section": "8-4-5 [40]콘크리트기계", "pum_form": "requirement", "line": 3538, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0734", "section": "8-4-5 [40]콘크리트기계", "pum_form": "requirement", "line": 3544, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0735", "section": "8-4-6 [50]골재생산기계 등", "pum_form": "requirement", "line": 3550, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0736", "section": "8-4-6 [50]골재생산기계 등", "pum_form": "requirement", "line": 3556, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0737", "section": "8-4-7 [60]기초공사용 기계('21년 보완)", "pum_form": "requirement", "line": 3562, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0738", "section": "8-4-8 [70]기타기계('24년 보완)", "pum_form": "requirement", "line": 3568, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0739", "section": "8-4-8 [70]기타기계('24년 보완)", "pum_form": "requirement", "line": 3574, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C0740", @@ -1913,7 +1913,7 @@ "section": "1-2 철골 세우기 1-2-1 현장 세우기('08, '18년 보완)(ton당)", "pum_form": "requirement", "line": 134, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C1433", @@ -2312,7 +2312,7 @@ "section": "13-4-3 STORAGE TANK", "pum_form": "requirement", "line": 1407, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C1721", @@ -2494,7 +2494,7 @@ "section": "78713-5-14 Heater 및 Tank 설치", "pum_form": "requirement", "line": 1927, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C1760", @@ -2620,14 +2620,14 @@ "section": "82813-7-12 Craft 및 Tomlex Spray 공사(인/㎡)", "pum_form": "requirement", "line": 2788, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C1836", "section": "13-7-13 Castable Spray 공사(인/㎡)", "pum_form": "requirement", "line": 2795, - "why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)" + "why": "미판독 — 원문이 적었는데 우리가 못 읽음" }, { "pum_table_id": "C1837", 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 8294fc63..68fdb9ad 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-18T03:44:44+09:00", + "generated_at": "2026-09-18T03:55:16+09:00", "dataset_version": { "dataset_id": "pum_const", "effective_date": "2026-01-01", @@ -41,8 +41,8 @@ "form_undetermined": 891, "basis_found": 538, "basis_missing": 439, - "basis_absent_in_source": 308, - "basis_unparsed": 131, + "basis_absent_in_source": 277, + "basis_unparsed": 162, "basis_grouped": 54, "axis_roles": { "group": 258, 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 b4c093e2..5ea52542 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-18T03:43:54+09:00", + "generated_at": "2026-09-18T03:54:25+09:00", "dataset_version": { "dataset_id": "pum_forest", "effective_date": "2026-01-01", @@ -25,11 +25,11 @@ "tables_attached": 453, "tables_orphan": 22, "form_undetermined": 0, - "basis_found": 246, - "basis_missing": 84, - "basis_absent_in_source": 75, - "basis_unparsed": 9, - "basis_grouped": 57, + "basis_found": 251, + "basis_missing": 79, + "basis_absent_in_source": 69, + "basis_unparsed": 10, + "basis_grouped": 59, "axis_roles": { "general_provision": 78, "group": 85, @@ -7717,9 +7717,9 @@ "source_line": 2041, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 100.0, + "basis_unit": "㎡", + "basis_source": "사람 판정 — 가지정리 — 원문 「(인/100㎡)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -7770,9 +7770,9 @@ "source_line": 2052, "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": [], @@ -10177,9 +10177,9 @@ "source_line": 2496, "pum_form": "requirement", "form_basis": "직종 표기((인)·인부·공)", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 100.0, + "basis_unit": "㎡", + "basis_source": "사람 판정 — 떼붙임(재배잔디) — 원문 「(인/100㎡)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], @@ -11181,9 +11181,9 @@ "source_line": 2693, "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": [], @@ -16599,9 +16599,9 @@ "source_line": 3761, "pum_form": "requirement", "form_basis": "'소요인력'", - "basis_quantity": null, - "basis_unit": null, - "basis_source": null, + "basis_quantity": 1.0, + "basis_unit": "톤", + "basis_source": "사람 판정 — 동력상하차기 — 원문 「(대/ton)」", "resource_shares": {}, "partial_ratio": false, "expression_cells": [], diff --git a/resources/tester/fixtures/base_data_source_known.json b/resources/tester/fixtures/base_data_source_known.json index dc23bc7b..c3845563 100644 --- a/resources/tester/fixtures/base_data_source_known.json +++ b/resources/tester/fixtures/base_data_source_known.json @@ -20,7 +20,9 @@ 0.95, null ], - "why": "위와 같음" + "why": "위와 같음", + "class": "㉰ 사용자 판단 필요", + "class_why": "토량환산계수 — 원문과 갈려 사람 확인" }, "coef_soil_L/11": { "md": [ @@ -35,7 +37,9 @@ 1.45, null ], - "why": "이름을 「암괴ㆍ호박돌 섞인 모래」로 줄여 적음 — 값은 원문과 같음" + "why": "이름을 「암괴ㆍ호박돌 섞인 모래」로 줄여 적음 — 값은 원문과 같음", + "class": "㉰ 사용자 판단 필요", + "class_why": "위와 같음" } }, "material_surcharge": { @@ -48,7 +52,9 @@ 3, 7 ], - "why": "원문 복잡 구조물 주철근 「6-7」 범위 중 위 끝 7 을 씀 — 범위를 살릴지 사람 확인" + "why": "원문 복잡 구조물 주철근 「6-7」 범위 중 위 끝 7 을 씀 — 범위를 살릴지 사람 확인", + "class": "㉰ 사용자 판단 필요", + "class_why": "원문이 범위 「6~7」 — 위 끝 7 을 쓸지 사람 확인(범위는 자료에 실어 둠)" } }, "formwork_reuse": {}, @@ -58,7 +64,9 @@ "data": [ "교량 슬래브" ], - "why": "원문 「교량의 슬래브」를 줄여 적음" + "why": "원문 「교량의 슬래브」를 줄여 적음", + "class": "㉰ 사용자 판단 필요", + "class_why": "복잡 갈래 값 — 사람 확인" } }, "timber_structure_class": {}, @@ -70,14 +78,26 @@ "dump_material/발파암/truck_efficiency": { "md": [], "data": "0.9", - "why": "10-12-3 운반 식에 E 가 없음 — 토사·암절취의 0.9 를 이어 씀" + "why": "10-12-3 운반 식에 E 가 없음 — 토사·암절취의 0.9 를 이어 씀", + "class": "㉮ 영영 할 일 아님", + "class_why": "원문 식에 E 가 없어 토사·암절취 0.9 를 이어 씀 — 사유 적음" }, "dump_material/토사/loading_efficiency": { "md": [ 0.75 ], "data": "0.60", - "why": "본문 E0=0.75 대신 10-12-1 [주]⑤ 표 「임도 0.60(불량)」 을 씀 — 자료 loading_note 에 사유" + "why": "본문 E0=0.75 대신 10-12-1 [주]⑤ 표 「임도 0.60(불량)」 을 씀 — 자료 loading_note 에 사유", + "class": "㉮ 영영 할 일 아님", + "class_why": "원문 [주]⑤ 표 비고 「임 도」로 0.60 확정 — 사유 적음" + } + }, + "_갈래": { + "센 날": "2026-09-18", + "셈": { + "㉮ 영영 할 일 아님": 2, + "㉯ 남이 고쳐야 풀림": 0, + "㉰ 사용자 판단 필요": 4 } } } diff --git a/resources/tester/fixtures/work_item_master_source_known.json b/resources/tester/fixtures/work_item_master_source_known.json index 57f49f80..8cd6b062 100644 --- a/resources/tester/fixtures/work_item_master_source_known.json +++ b/resources/tester/fixtures/work_item_master_source_known.json @@ -25,17 +25,23 @@ "F0452": { "section": "14-2", "md": "부록 표", - "master": "공종에 붙음" + "master": "공종에 붙음", + "class": "㉰ 사용자 판단 필요", + "class_why": "부록 14-2 표가 공종에 붙음 — 떼어 낼지 승인 대기(같은 식구 넷을 앞서 찾음)" }, "F0453": { "section": "14-2", "md": "부록 표", - "master": "공종에 붙음" + "master": "공종에 붙음", + "class": "㉰ 사용자 판단 필요", + "class_why": "위와 같음" }, "F0454": { "section": "14-2", "md": "부록 표", - "master": "공종에 붙음" + "master": "공종에 붙음", + "class": "㉰ 사용자 판단 필요", + "class_why": "위와 같음" } }, "basis": { @@ -46,7 +52,9 @@ "master": [ 1.0, "인" - ] + ], + "class": "㉰ 사용자 판단 필요", + "class_why": "⚠ 마스터 밑수가 「1인」 — 「인」은 품의 단위지 밑수가 아니라는 2026-09-09 판정과 어긋남" }, "F0068": { "section": "2-2-5", @@ -55,7 +63,9 @@ "master": [ 1.0, "인" - ] + ], + "class": "㉰ 사용자 판단 필요", + "class_why": "⚠ 위와 같음 · 게다가 계수표라 밑수가 없어야 함" }, "F0076": { "section": "3-2", @@ -64,43 +74,9 @@ "master": [ 1.0, "km" - ] - }, - "F0089": { - "section": "4-4", - "md": [ - 100.0, - "㎡" ], - "md_evidence": "(인/100㎡)", - "master": null - }, - "F0090": { - "section": "4-5", - "md": [ - 1.0, - "ha" - ], - "md_evidence": "(인/ha)", - "master": null - }, - "F0117": { - "section": "5-12", - "md": [ - 100.0, - "㎡" - ], - "md_evidence": "(인/100㎡)", - "master": null - }, - "F0129": { - "section": "5-21", - "md": [ - 1.0, - "㎡" - ], - "md_evidence": "(인/㎡)", - "master": null + "class": "㉰ 사용자 판단 필요", + "class_why": "⚠ 마스터 「1km」는 반쪽 — 원문은 「인/1일 1km당」으로 분모가 둘(일·km)" }, "F0132": { "section": "5-22-4", @@ -109,7 +85,9 @@ "일" ], "md_evidence": "(일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "「일당」은 품의 단위(하루에 얼마)라 밑수로 안 받음" }, "F0145": { "section": "5-28-2", @@ -119,7 +97,9 @@ ], "md_evidence": "(일 당)", "master": null, - "why": "작업조 표(시공량 열이 밑수) — 마스터가 일부러 비움(c3da333e 와 같은 까닭) · 원문 「(일 당)」 은 코덱스 복원(61f35108)" + "why": "작업조 표(시공량 열이 밑수) — 마스터가 일부러 비움(c3da333e 와 같은 까닭) · 원문 「(일 당)」 은 코덱스 복원(61f35108)", + "class": "㉮ 영영 할 일 아님", + "class_why": "작업조 표 — 밑수가 시공량 열이라 일부러 비움" }, "F0173": { "section": "7-2", @@ -128,7 +108,9 @@ "master": [ 1.0, "㎥" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스 md 읽기 넓히기" }, "F0188": { "section": "7-10", @@ -137,16 +119,9 @@ "master": [ 1.0, "㎥" - ] - }, - "F0191": { - "section": "7-11", - "md": [ - 1.0, - "톤" ], - "md_evidence": "(대/ton)", - "master": null + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "위와 같음" }, "F0225": { "section": "8-6-1", @@ -155,7 +130,9 @@ "master": [ 160.0, "ha" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "위와 같음(원문 「160ha당」)" }, "F0257": { "section": "9-11-1", @@ -164,7 +141,9 @@ "일" ], "md_evidence": "(단위: 일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "「일당」 · 계수표" }, "F0322": { "section": "10-13-1", @@ -173,7 +152,9 @@ "master": [ 1000.0, "본" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "위와 같음(원문 「묘목 1,000본당」)" }, "F0323": { "section": "10-13-2", @@ -182,7 +163,9 @@ "master": [ 1000.0, "본" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "위와 같음" }, "F0338": { "section": "12-6", @@ -191,7 +174,9 @@ "일" ], "md_evidence": "(단위: 일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "작업조 표(포장공 3인·시공량)" }, "F0339": { "section": "12-7-1", @@ -200,7 +185,9 @@ "일" ], "md_evidence": "(단위: 일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "작업조 표 — 넣으면 호표가 사라짐(2026-09-17 유로폼에서 실증)" }, "F0340": { "section": "12-7-2", @@ -209,7 +196,9 @@ "일" ], "md_evidence": "(단위: 일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "위와 같음" }, "F0341": { "section": "12-8", @@ -218,7 +207,9 @@ "일" ], "md_evidence": "(단위: 일당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "위와 같음" }, "F0395": { "section": "12-38-3", @@ -227,7 +218,9 @@ "일" ], "md_evidence": "(단위: 일 당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "위와 같음" }, "F0447": { "section": "13-15-2", @@ -236,7 +229,9 @@ "조" ], "md_evidence": "(단위: 인/조)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "「인/조」 — 「조」는 세는 단위가 아님" }, "F0449": { "section": "13-16-2", @@ -245,7 +240,9 @@ "일" ], "md_evidence": "(단위: 일 당)", - "master": null + "master": null, + "class": "㉮ 영영 할 일 아님", + "class_why": "위와 같음" } }, "notes": { @@ -254,7 +251,9 @@ "md_only": [], "master_only": [ "- 3. 박피품은 별도 적용하여야 한다. 다만 작업조건에 따라 1일 작업량은 변동 적용한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0104": { "section": "5-3-4", @@ -267,7 +266,9 @@ "- ⑤ 암반식재, 부적기식재 등 특수식재시는 품을 별도 계상할 수 있다.", "- ⑥ 현장의 시공조건, 수목의 성상에 따라 기계 시공이 불가피한 경우는 별도 계상한다.", "- ⑦ 굴착기 규격은 0.4㎥를 기준으로 한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0106": { "section": "5-3-5", @@ -281,7 +282,9 @@ "- ⑥ 암반식재, 부적기식재 등 특수식재시는 품을 별도 계상할 수 있다.", "- ⑦ 현장의 시공조건, 수목의 성상에 따라 기계시공이 불가피한 경우는 별도 계상한다.", "- ⑧ 장비 규격은 다음을 기준으로 한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0189": { "section": "7-11", @@ -291,7 +294,9 @@ "- ② 본 품에는 벌채지의 재해방지 및 산불예방을 위한 산물정리비가 반영된 것으로 본다.", "- ③ 잔존목 본 수가 100본 이상 130본 이하(잔존목간 거리 10~8.8m)인 경우 10%, 71본 이상 100본 미만(잔존목간 거리 12~10m)인 경우 5%를 할증한다.", "- ④ 할인․할증은 경사도(1-4-5), 주행 장애물 상태(1-4-13)를 반영한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0223": { "section": "8-4", @@ -299,7 +304,9 @@ "master_only": [ "- ③ 임업용테이프는 상하 고정이 필요한 경우에 적용하며 본당 소요량이다.", "- ④ 할인․할증은 경사도(1-4-5), 방제 대상목 분포(1-4-17)를 반영한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0251": { "section": "9-8-1", @@ -309,7 +316,9 @@ "- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값 적용한다.", "- 4. 고철공제 : A=1㎥×0.008×7,850kg/㎥×80% = 50.24 kg/㎥ ≒50 kg/㎥", "[주] 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」, 「건설공사 표준품셈 유지관리부문, 3-1-3 철골재 철거(인력)(2025)」, 「건설공사 표준품셈 유지관리부문, 3-1-4 철골재 철거(기계)(2025)」, 「건설공사 표준품셈 공통부문, 1-2-3 토질, 3. 체적환산계수적용(2025)」, 「국토건설 설계실무요령, 수량산출요령(2021)」 참조한다" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0252": { "section": "9-8-2", @@ -322,7 +331,9 @@ "- 4. 고철공제 : A=1㎥×0.008×7,850kg/㎥×80% = 50.24 kg/㎥≒50 kg/㎥", "[주]① 적사 및 운반은 폐기물 상차 및 운반비에서 적용한다.", "- ② 「건설공사 표준품셈 유지관리부문, 3-1-3 철골재 철거(인력)(2025)」, 「건설공사 표준품셈 유지관리부문., 3-1-4 철골재 철거(기계)(2025)」 참조한다" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0254": { "section": "9-10-1", @@ -331,7 +342,9 @@ "- 2. 집토 : Q=3600×q×k×f×E/㎝= ㎥/시간", "[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.", "- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값 적용한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0255": { "section": "9-10-2", @@ -341,28 +354,36 @@ "[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.", "- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값을 적용한다.", "- ③ 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」 참조한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0281": { "section": "9-15-1", "md_only": [], "master_only": [ "- ③ 「건설공사 표준품셈 공통부문, 8-2-3 굴착기(2025)」 참조한다. (불도저작업이 어려운 경우)" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0282": { "section": "9-15-2", "md_only": [], "master_only": [ "- ③ 「건설공사 표준품셈 공통부문, 8-2-1 불도저(2025)」 참조(표토제거 두께 T=0.2m)" - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0285": { "section": "9-16-3", "md_only": [], "master_only": [ "- ④ 토목은 동상방지층, 보조기층, 기층 등 층별 조건이나 본선, 길어깨 등에 따라 임도에는 대형장비(5,500ℓ)를 사용한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0286": { "section": "9-17-2", @@ -370,28 +391,36 @@ "master_only": [ "- ③ 향후 나무심기가 예상되는 곳에 시행한다.", "- ④ 「건설공사 표준품셈 공통부문 8-2-1 불도저(2025)」 참조한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0295": { "section": "9-22", "md_only": [], "master_only": [ "- ④ 0.2㎥ 또는 0.4㎥ 용량의 굴착기를 사용하는 경우에는「건설공사 표준품셈 공통부문, 8-2-3 굴착기(2025)」를 참조하여 적용계수를 달리 적용하도록 한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0319": { "section": "10-11", "md_only": [], "master_only": [ "- ③ 「건설공사 표준품셈 공통부문. 8-2-1 불도저(2025)」 참조한다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0323": { "section": "10-13-2", "md_only": [], "master_only": [ "[주] 위 단가산출은 일본 임야청에서 묘목 5,000본의 운반을 가정하여 현장 검증을 통해 산출한 내용이므로, 묘목 이외의 다른 화물을 운반할 시에는 달라질 수 있다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" }, "F0393": { "section": "12-38-2", @@ -399,107 +428,147 @@ "master_only": [ "[주] ① 재료량에는 재료의 할증 및 손율이 포함되어 있다.", "- ② 플랫 타이(Flat Tie) 대신 폼 타이(Form Tie) 사용 시 소요 수량은 12-4 합판 거푸집 자재수량을 따른다." - ] + ], + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "마스터가 맞고 md 읽기가 덜 읽음 — 코덱스가 md 읽기를 넓히는 중" } }, "form": { "F0002": { "section": "1-2-2", "master": "reference", - "md_mark": "직공인부" + "md_mark": "직공인부", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0007": { "section": "1-2-7", "master": "reference", - "md_mark": "㎥" + "md_mark": "㎥", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0038": { "section": "1-4-26", "master": "reference", - "md_mark": "적용시공량" + "md_mark": "적용시공량", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0227": { "section": "8-6-1", "master": "reference", "md_mark": "유효 살포량/1회", - "why": "사람 판정 reference(Forms.py) — 기종별 희석배수별 1회 살포량 계산표" + "why": "사람 판정 reference(Forms.py) — 기종별 희석배수별 1회 살포량 계산표", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0257": { "section": "9-11-1", "master": "coefficient", - "md_mark": "ℓ" + "md_mark": "ℓ", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0325": { "section": "11-1", "master": "reference", - "md_mark": "비계공" + "md_mark": "비계공", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" }, "F0454": { "section": "14-2", "master": "reference", - "md_mark": "작업량" + "md_mark": "작업량", + "class": "㉮ 영영 할 일 아님", + "class_why": "사람 판정으로 닫힘 — 시험이 md 표지로 가리는 것과 다를 뿐" } }, "form_blind": { "F0046": { "section": "2-1-1", "master": "requirement", - "why": "기계별 연료표(천공기 주연료 3ℓ·잡품 95%) — 품 낱말 없음. 같은 모양 F0044·F0045·F0047 은 사람 판정 reference 인데 이것만 requirement" + "why": "기계별 연료표(천공기 주연료 3ℓ·잡품 95%) — 품 낱말 없음. 같은 모양 F0044·F0045·F0047 은 사람 판정 reference 인데 이것만 requirement", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0062": { "section": "2-1-12", "master": "requirement", - "why": "값 칸이 「층적부피에 따라 별도계산」·「〃」 — 숫자 없음" + "why": "값 칸이 「층적부피에 따라 별도계산」·「〃」 — 숫자 없음", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0140": { "section": "5-26-1", "master": "requirement", - "why": "머리 소실 — 토성×깊이 숫자만 남음(사람 판정: 100㎡당 보통인부)" + "why": "머리 소실 — 토성×깊이 숫자만 남음(사람 판정: 100㎡당 보통인부)", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0141": { "section": "5-26-2", "master": "requirement", - "why": "머리 소실 — 위와 같음" + "why": "머리 소실 — 위와 같음", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0142": { "section": "5-26-3", "master": "requirement", - "why": "머리 소실 — 위와 같음" + "why": "머리 소실 — 위와 같음", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0195": { "section": "7-14", "master": "productivity", - "why": "칸이 뭉침(「㎥ 0.06∼0.07 4.8∼6.0」) — 원문 md 가 병합 칸을 못 풂" + "why": "칸이 뭉침(「㎥ 0.06∼0.07 4.8∼6.0」) — 원문 md 가 병합 칸을 못 풂", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0237": { "section": "8-11", "master": "productivity", - "why": "작업량이 식 글(「Q = 3.5 ㎥/hr」)" + "why": "작업량이 식 글(「Q = 3.5 ㎥/hr」)", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0333": { "section": "12-1-3", "master": "requirement", - "why": "⚠ 원문 md 의심 — 머리는 한중콘크리트 「온도 품종 | 0℃때 …」인데 몸 줄이 앞 표 F0332(시멘트·모래·자갈 kg)와 똑같음 · PDF 대조 필요" + "why": "⚠ 원문 md 의심 — 머리는 한중콘크리트 「온도 품종 | 0℃때 …」인데 몸 줄이 앞 표 F0332(시멘트·모래·자갈 kg)와 똑같음 · PDF 대조 필요", + "class": "㉯ 남이 고쳐야 풀림", + "class_why": "⚠ 원문 md 의심 — 몸 줄이 앞 표와 똑같음 · 코덱스 PDF 대조" }, "F0342": { "section": "12-9-1", "master": "requirement", - "why": "수량 칸이 비어 있음 — 원문에 값 없음(「반중력식 옹벽 참조」)" + "why": "수량 칸이 비어 있음 — 원문에 값 없음(「반중력식 옹벽 참조」)", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0343": { "section": "12-9-2", "master": "requirement", - "why": "수량 칸이 비어 있음 — 원문에 값 없음" + "why": "수량 칸이 비어 있음 — 원문에 값 없음", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0344": { "section": "12-9-3", "master": "requirement", - "why": "수량 칸이 비어 있음 — 원문에 값 없음" + "why": "수량 칸이 비어 있음 — 원문에 값 없음", + "class": "㉮ 영영 할 일 아님", + "class_why": "시험이 못 가리는 자리 — 값 없음·머리 소실 따위로 사람 판정에 둠" }, "F0405": { "section": "13-4-1", "master": "requirement", - "why": "증가율(%) 표(높이별 30·40·60%) — 품이 아니라 할증률 모양 · requirement 가 맞는지 사람 확인" + "why": "증가율(%) 표(높이별 30·40·60%) — 품이 아니라 할증률 모양 · requirement 가 맞는지 사람 확인", + "class": "㉰ 사용자 판단 필요", + "class_why": "증가율(%) 표 — requirement 가 맞는지 사람 확인" } }, "cost_rule": { @@ -514,7 +583,9 @@ "설치비", "재료비의 5%" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0379": { "section": "12-29", @@ -530,7 +601,9 @@ "재료비의 5%" ] ], - "why": "⚠ 같은 꼴 6표는 reference 인데 이것만 requirement — 설치비 = 재료비의 5%" + "why": "⚠ 같은 꼴 6표는 reference 인데 이것만 requirement — 설치비 = 재료비의 5%", + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0382": { "section": "12-31", @@ -543,7 +616,9 @@ "설치비", "주재료비의 5%" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0383": { "section": "12-32", @@ -557,7 +632,9 @@ "설치비", "주재료비의 10%" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0386": { "section": "12-34-2", @@ -571,7 +648,9 @@ "노무비", "1회 기준 47.1%" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0388": { "section": "12-34-4", @@ -581,7 +660,9 @@ "재료비", "JOINT FILLER" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" }, "F0390": { "section": "12-36", @@ -599,7 +680,18 @@ "설치비", "견적처리" ] - ] + ], + "class": "㉮ 영영 할 일 아님", + "class_why": "비목 구성표 — `sub_requirement` 로 판정이 닫힘" + } + }, + "_갈래": { + "잣대": "㉮ 는 집계에서 뺀다 — 영영 할 일이 아닌 것(원문에 없음·거절 자리·판정으로 닫힘). ㉯ 는 남의 몫(코덱스 md 읽기·랩탑 메인 시험). ㉰ 만 사람이 정할 자리다.", + "센 날": "2026-09-18", + "셈": { + "㉮ 영영 할 일 아님": 39, + "㉯ 남이 고쳐야 풀림": 23, + "㉰ 사용자 판단 필요": 7 } } } diff --git a/resources/tester/test_work_item_key_registry.py b/resources/tester/test_work_item_key_registry.py index d45a106f..e51321d5 100644 --- a/resources/tester/test_work_item_key_registry.py +++ b/resources/tester/test_work_item_key_registry.py @@ -61,7 +61,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 = "8d438798609b2a80a269c983448f107a0a176202c5e26c80d84b68116f5fdd66" +BASELINE_WORK_ITEMS_SHA = "803898a371e82c8a66692807af189a646c9b6fb3f077a4054cf6ef6030d8341b" #: 열쇠 작업이 새로 얹은 칸. 지문을 잴 때만 떼어낸다. ADDED_FIELDS = ( @@ -469,12 +469,13 @@ def test_밑수_미확보를_둘로_가른다(master: dict) -> None: from pathlib import Path as _Path stats = master["stats"] - assert stats["basis_missing"] == 84 - assert stats["basis_absent_in_source"] == 75 - # 2026-09-18 미판독 12 → 9 — 분모가 하나로 또렷한 셋(「ha당 소요량」·「조/ha당」)을 채움. + assert stats["basis_missing"] == 79 + assert stats["basis_absent_in_source"] == 69 + # 2026-09-18 「당」 없이 몫으로만 적힌 자리(「(인/100㎡)」·「(대/ton)」)를 가리게 해 다섯을 더 채움. + # 미판독 12 → 9 → 10(가림이 넓어져 새로 드러난 것 포함) · 확보 243 → 251. # ⚠ 남은 아홉은 **거절 자리**다 — 「(단위 : 인)」 셋(2026-09-09 오독 판정) · # 「㎥/1인/1일」·「1ha당, 100본당」·「1대 1조, 시간당」·「인 당」은 분모가 둘 이상이다. - assert stats["basis_unparsed"] == 9 + assert stats["basis_unparsed"] == 10 assert stats["basis_absent_in_source"] + stats["basis_unparsed"] == stats["basis_missing"] items = _json.loads( _Path("resources/data_work_item_master/basis_missing_2026-01-01.json").read_text( @@ -485,8 +486,11 @@ def test_밑수_미확보를_둘로_가른다(master: dict) -> None: # 「공㎥」 처럼 단위 목록에 없던 자리는 사람 판정으로 채웠다 — 목록을 넓히면 규격이 밑수가 된다 by_id = {t["pum_table_id"]: t for it in master["work_items"] for t in it["tables"]} assert by_id["F0366"]["basis_unit"] == "공㎥" - for table_id in ("F0050", "F0052", "F0224"): + for table_id in ("F0050", "F0052", "F0224", "F0090"): assert by_id[table_id]["basis_quantity"] == 1.0 and by_id[table_id]["basis_unit"] == "ha" + # 「당」 글자 없이 몫으로만 적힌 자리도 읽는다 — 「(인/100㎡)」·「(대/ton)」 + assert by_id["F0089"]["basis_quantity"] == 100.0 and by_id["F0089"]["basis_unit"] == "㎡" + assert by_id["F0191"]["basis_unit"] == "톤" def test_원문_대조_밑수_판정(master: dict) -> None: diff --git a/resources/tester/test_work_item_master_source_match.py b/resources/tester/test_work_item_master_source_match.py index 5f97b79b..c8992a4c 100644 --- a/resources/tester/test_work_item_master_source_match.py +++ b/resources/tester/test_work_item_master_source_match.py @@ -329,8 +329,13 @@ def load_known() -> dict[str, dict]: return json.loads(KNOWN.read_text(encoding="utf-8")) +#: 비교에서 뺄 칸 — **사람이 적은 메모**다. 자료가 아니라 설명이라 어긋남 판정에 안 쓴다. +#: `class`·`class_why` 는 2026-09-18 에 붙인 갈래(㉮ 영영 아님 · ㉯ 남의 몫 · ㉰ 사용자 판단). +_MEMO_FIELDS = ("why", "class", "class_why", "was") + + def _without_why(entry: dict) -> dict: - return {k: v for k, v in entry.items() if k != "why"} + return {k: v for k, v in entry.items() if k not in _MEMO_FIELDS} # ── 시험 ────────────────────────────────────────────────────────────────