From fc867d32200232bc500b75051026af28257586b6 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 08:35:27 +0900 Subject: [PATCH] =?UTF-8?q?fix(B08):=20=EA=B7=9C=EC=A4=80=ED=8B=80=20?= =?UTF-8?q?=EB=B0=91=EC=88=98=EB=A5=BC=20=ED=91=9C=20=EC=95=84=EB=9E=98=20?= =?UTF-8?q?[=EC=A3=BC]=20=EC=97=90=EC=84=9C=20=EC=9D=BD=EC=9D=8C=20?= =?UTF-8?q?=E2=80=94=20=EA=B8=88=EC=95=A1=EC=9D=B4=20=EB=AA=BB=20=EB=B6=99?= =?UTF-8?q?=EB=8D=98=20=EC=9E=90=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit B09 제보. 규준틀 둘(FP-11-02·FP-11-03)이 in_bill=true 로 서는데 「밑수 미확보」라 금액이 안 붙고 있었음. 개소 수는 이미 닫혔는데 그 표의 밑수 자체가 비어 있던 것. 「원문에 있었음」 아홉 번째 — 이번엔 표 **아래** [주] 였음 [주]③ 「목재의 손율은 **1개소 사용당** 50%로 한다」 뜻으로도 개소가 맞음 — [주]② 가 「본 품은 …한 비탈규준틀의 제작·도색· 가설·철거를 포함한 것」이라 규준틀 하나를 말하고, [주]① 이 「20m마다 설치」 ⚠ 아주 좁게 잡음 — 「N개소 **사용** 당」 표기는 품셈 전문에 딱 두 곳뿐이고 둘 다 규준틀임. 「개소당 평균면적」 같은 흔한 말은 「사용」이 없어 안 걸림 (넓히면 조림 2장이 통째로 걸림 — 실측 19건). 다음 표(|)나 다음 절(###)을 만나면 멈춤 — 남의 [주] 를 물어 오면 조용히 틀림. 효과: 밑수 확보 183 → 185, 미확보 137 → 135. 시험 넷 — 규준틀에서 읽는 것 · 흔한 말에 안 걸리는 것 · 다음 절로 안 넘어가는 것 · 다시 만든 마스터에 실제로 실렸는지 정본 대조. 시험: 685 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관). Co-Authored-By: Claude Opus 5 (1M context) --- .../B08_Quantity_Build_WorkItemMaster.py | 24 +++++++++++++++++++ .../data_work_item_master/_manifest.json | 10 ++++---- .../basis_missing_2026-01-01.json | 12 ---------- .../work_item_master_2026-01-01.json | 18 +++++++------- 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py b/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py index e705ffcc..ba5cb8d7 100644 --- a/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py +++ b/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py @@ -290,6 +290,16 @@ SOURCE_BASIS_RE = re.compile( #: 표 위로 몇 줄까지 거슬러 볼 것인가. 더 올라가면 **앞 표의 밑수**를 잘못 물어 온다. SOURCE_LOOKBACK = 6 +#: 표 **아래 [주]** 에만 밑수가 적힌 자리 — 「목재의 손율은 **1개소 사용당** 50%로 한다」. +#: ⚠ **아주 좁게 잡는다.** 「N개소 **사용** 당」이라는 표기는 품셈 전문에 **딱 두 곳**뿐이고 +#: (11-2 비탈 규준틀 · 11-3 수평 규준틀) 둘 다 개소로 세는 표다. 「개소당 평균면적」 같은 +#: 흔한 말은 「사용」이 없어 안 걸린다 — 넓히면 조림 2장이 통째로 걸린다(실측 19건). +#: ⚠ 뜻으로도 개소가 맞다 — [주]② 가 「본 품은 …한 **비탈규준틀**의 제작·도색·가설·철거를 +#: 포함한 것」이라 **규준틀 하나**를 말하고, [주]① 이 「20m마다 **설치**」라 센다. +SOURCE_BASIS_NOTE_RE = re.compile(r"([\d,]*\.?\d*)\s*개소\s*사용\s*당") +#: 표 아래로 몇 줄까지 볼 것인가. [주] 는 표 바로 밑에 붙는다. +SOURCE_NOTE_LOOKAHEAD = 8 + def basis_from_source(lines: list[str], line_no: int) -> tuple[float | None, str | None]: """표 바로 위 본문에서 밑수를 읽는다. 못 찾으면 `(None, None)` — 1 로 단정하지 않는다. @@ -319,6 +329,20 @@ def basis_from_source(lines: list[str], line_no: int) -> tuple[float | None, str except ValueError: quantity = 1.0 return quantity, unit + + # 표 **아래 [주]** 도 본다 — 위에 아무것도 없을 때만. 규준틀 둘이 그 자리다. + # ⚠ 다음 표(`|`)나 다음 절(`###`)을 만나면 멈춘다 — 남의 [주]를 물어 오면 조용히 틀린다. + for index in range(line_no, min(len(lines), line_no + SOURCE_NOTE_LOOKAHEAD)): + text = lines[index].strip() + if text.startswith("###"): + break + if m := SOURCE_BASIS_NOTE_RE.search(text): + raw = (m.group(1) or "").replace(",", "") + try: + quantity = float(raw) if raw else 1.0 + except ValueError: + quantity = 1.0 + return quantity, "개소" return None, None diff --git a/resources/data_work_item_master/_manifest.json b/resources/data_work_item_master/_manifest.json index 1fa924fb..2abebbdb 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-08T06:00:25+09:00", + "generated_at": "2026-09-08T08:33:10+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": "4d89c1eec7929c39d5adb36547b03f4675205b10f6b629eeb2f246a1d9230dfd", - "size_bytes": 856818 + "sha256": "3752af1e0328a2faf4947268e449e0bc602a0738cc6a29a78ed71d343cf2e583", + "size_bytes": 856832 }, { "file": "form_undetermined_2026-01-01.json", @@ -22,8 +22,8 @@ }, { "file": "basis_missing_2026-01-01.json", - "sha256": "9d7b9ee8df65be1c944a2e0af9efe0742bd9a356b367fc4de8eec47b3ece2147", - "size_bytes": 18627 + "sha256": "244851609c65ba8adbfc318668224cbf3a81032e9271cfda916de435d460dd92", + "size_bytes": 18360 } ] } \ 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 41773cee..a15cf0d1 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 @@ -694,18 +694,6 @@ "pum_form": "requirement", "line": 5894 }, - { - "pum_table_id": "F0326", - "section": "11-2. 토공의 비탈 규준틀", - "pum_form": "requirement", - "line": 6043 - }, - { - "pum_table_id": "F0327", - "section": "11-3. 수평규준틀", - "pum_form": "requirement", - "line": 6056 - }, { "pum_table_id": "F0337", "section": "12-5. 문양거푸집(0~7m)", 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 e718e55b..44658daf 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 @@ -2,7 +2,7 @@ "schema_version": "1.0", "dataset_id": "work_item_master_forest", "effective_date": "2026-01-01", - "generated_at": "2026-09-08T06:00:25+09:00", + "generated_at": "2026-09-08T08:33:10+09:00", "dataset_version": { "dataset_id": "pum_forest", "effective_date": "2026-01-01", @@ -21,8 +21,8 @@ "tables_attached": 456, "tables_orphan": 19, "form_undetermined": 77, - "basis_found": 183, - "basis_missing": 137, + "basis_found": 185, + "basis_missing": 135, "basis_grouped": 36 }, "orphan_tables": [ @@ -34136,9 +34136,9 @@ "source_line": 6043, "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": [], @@ -34185,9 +34185,9 @@ "source_line": 6056, "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": [],