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_structure_unit/structure_unit_observed_2026-01-01.json b/resources/data_structure_unit/structure_unit_observed_2026-01-01.json index f1898673..a0f8a6e8 100644 --- a/resources/data_structure_unit/structure_unit_observed_2026-01-01.json +++ b/resources/data_structure_unit/structure_unit_observed_2026-01-01.json @@ -308,6 +308,14 @@ "pending_choices": { "note": "값을 바꾸는 **설계 조건**인데 우리 제원에 칸이 없는 것. 기본값과 「정하면 얼마나 달라지는지」를 함께 적어 화면이 보이게 한다.", "items": [ + { + "key": "material_basis_area", + "label": "자재 원단위의 밑수 — 비탈면적인가 정면적인가", + "default": "비탈면적(= 돌쌓기 면적)", + "where": "실무 원단위 라이브러리 두 시트가 다르게 씀 — 돌골막이는 「(돌쌓기+돌붙임)×0.88 ton/㎡」로 **돌쌓기 면적**에, 돌기슭막이는 고임돌 0.15㎥/㎡ × **정면적** 1.5 = 0.225(시트 0.23)로 씀", + "effect": "정면적으로 바꾸면 고임돌·야면석·채움콘크리트·모르터가 **−4.4 %**", + "scope": "⚠ 면적 자체는 닫혔음(2026-09-08) — 돌쌓기 면적 = 정면적 × √(1+n²), 기울기 몫은 한 번만. 남은 물음은 **그 다음 원단위를 어느 면적에 곱하나**임" + }, { "key": "anti_suction_sheet", "label": "흡출방지재·차수시트 시공", 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": [],