fix(B09): 기종 이름 표기 맞춤 + 공식 계수 줄을 자원으로 안 셈

석재 할증률을 찾으러 12·13장 본문을 훑다 발견한 둘

- 품셈은 같은 기종을 「굴 삭 기」·「굴착기」·「유압식백호우」로 섞어 적음.
  메쌓기 13-6-1 의 「굴 삭 기 (무한궤도)」가 안 붙어 **장비 몫이 통째로
  빠져 있었음**. 이름 안 공백 제거 + 기종 별칭만 맞춤(규격은 안 건드림)
- ⚠ 그 정규화가 새 오독을 열었음 — 측구터파기의 「유압식백호우 … | k | 0.9」
  줄이 자원으로 잡혀 **버킷계수 0.9 를 소요량으로** 읽었음(사용료 0.9시간분
  이중). 공식 기호(K·f·E)를 단 줄은 자원으로 세지 않음 — 그 줄은 시공능력
  공식 쪽에서 씀

결과: 자원 축 256 → 259, 일위대가 145 유지, 최소 233.4 / 최대 5,030,954.6

석재 할증률은 **품셈에 없음을 확인** — 1-3-1 재료 할증률표에 야면석·막자갈·
고임돌이 없고, 13-4~13-7 돌쌓기 본문 [주]에도 할증 문구 없음. 사용자 확정 대기

검증: pytest 183 통과(신규 2 — 공식 줄 제외 + 공백 이름 매칭 짝 시험)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 01:48:47 +09:00
co-authored by Claude Opus 5
parent a8f0248bf7
commit 0728e4bae7
3 changed files with 139 additions and 96 deletions
@@ -437,6 +437,26 @@ class AxisResult:
partial_items: dict[str, str] = field(default_factory=dict)
def _tidy_resource_name(cell: str) -> str:
"""이름 표기를 카탈로그 쪽으로 맞춘다 — **뜻을 바꾸지 않는 표기 차이만.**
① 이름 안 공백 제거 (「굴 삭 기 (무한궤도)」 → 「굴삭기(무한궤도)」)
② 같은 기종의 다른 이름 (「굴삭기」·「유압식백호우」 → 「굴착기」)
⚠ 규격은 안 건드린다 — 규격을 맞추려 들면 엉뚱한 기종이 붙는다.
"""
from B09_Estimation.B09_Estimation_MachineProductivity import MACHINE_NAME_ALIASES
text = str(cell)
head, sep, tail = text.partition("(")
tight = "".join(head.split())
for wrong, right in MACHINE_NAME_ALIASES.items():
if tight == wrong:
tight = right
break
return tight + sep + tail
def _resolve_cell(catalog: ResourceCatalog, name_cell: str, cells: list[str]):
"""셀 하나를 카탈로그 한 줄로 푼다 — 세 가지 모양을 차례로 시도한다.
@@ -444,6 +464,10 @@ def _resolve_cell(catalog: ResourceCatalog, name_cell: str, cells: list[str]):
② 기종 셀 (「굴착기(무한궤도, 0.7㎥)」 → 이름 + 규격)
③ 규격이 **옆 칸**에 있는 표 (「굴착기 (무한궤도)」 | 「0.7㎥」)
"""
# ⚠ **이름 안 공백·표기 차이를 먼저 없앤다.** 품셈은 같은 기종을 「굴 삭 기」·
# 「굴착기」·「유압식백호우」로 섞어 적는다(2026-09-08: 메쌓기 13-6-1 의
# 「굴 삭 기 (무한궤도)」가 안 붙어 그 공종 장비 몫이 통째로 빠졌다).
name_cell = _tidy_resource_name(name_cell)
machine_name, machine_spec = parse_machine_cell(name_cell)
plain_name, plain_spec = split_name_and_spec(name_cell)
@@ -524,6 +548,13 @@ def match_table(
name_cell = cells[1]
value_cells = cells[2:]
# ⚠ **공식 계수를 단 줄은 자원 줄이 아니다.** 「유압식백호우 … | k | 0.9」 처럼
# 같은 줄에 버킷계수가 붙어 오는데, 그 0.9 를 소요량으로 읽으면 **시간당 사용료가
# 0.9시간분** 붙어 이중이 된다(2026-09-08: 이름 표기를 맞추자 측구터파기에
# 「굴착기 0.81」 줄이 새로 생겨 발견). 그 줄은 시공능력 공식 쪽에서 쓴다.
if any(_normalize(c).lower() in ("k", "f", "e") for c in value_cells):
continue
# 숫자 셀이 없는 행은 자원 줄이 아니다(제목·설명 행) — 목록에 안 올린다.
amount_cell = next(
(parse_amount(c) for c in value_cells if parse_amount(c) is not None), None
@@ -1561,6 +1561,20 @@
"variant": "",
"work_item_code": "FP-09-19-02"
},
{
"amount": "0.045",
"amount_unit": "㎡",
"group_ratio_pct": null,
"pum_form": "requirement",
"pum_table_id": "F0290",
"raw_row_index": 1,
"resource_code": "0201-0070",
"resource_kind": "machine",
"resource_name": "굴착기(무한궤도)",
"resource_spec": "0.7",
"variant": "",
"work_item_code": "FP-09-19-02"
},
{
"amount": "0.0328",
"amount_unit": "㎡",
@@ -3045,6 +3059,20 @@
"variant": "",
"work_item_code": "FP-13-06-01"
},
{
"amount": "0.384",
"amount_unit": "㎡",
"group_ratio_pct": null,
"pum_form": "requirement",
"pum_table_id": "F0419",
"raw_row_index": 4,
"resource_code": "0201-0080",
"resource_kind": "machine",
"resource_name": "굴착기(무한궤도)",
"resource_spec": "0.8",
"variant": "",
"work_item_code": "FP-13-06-01"
},
{
"amount": "0.083",
"amount_unit": "㎡",
@@ -3199,6 +3227,20 @@
"variant": "",
"work_item_code": "FP-13-07-02"
},
{
"amount": "0.336",
"amount_unit": "㎡",
"group_ratio_pct": null,
"pum_form": "requirement",
"pum_table_id": "F0423",
"raw_row_index": 4,
"resource_code": "0201-0080",
"resource_kind": "machine",
"resource_name": "굴착기(무한궤도)",
"resource_spec": "0.8",
"variant": "",
"work_item_code": "FP-13-07-02"
},
{
"amount": "0.009",
"amount_unit": "개",
@@ -3604,12 +3646,12 @@
"sha256": "fe454c56c9dc01ad7dae04a8f90d776d08c5ce33badeadb2606b35234bfce7eb"
},
"stats": {
"rows": 256,
"rows": 259,
"skipped_forms": {
"coefficient": 19,
"reference": 92,
"undetermined": 75
},
"unmatched": 316
"unmatched": 311
}
}
@@ -1022,12 +1022,6 @@
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
"work_item_code": "FP-09-10-02"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0258",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-12-01"
},
{
"cell": "대형브레이커(㎥/hr)",
"pum_table_id": "F0259",
@@ -1040,12 +1034,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-12-02"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0259",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-12-02"
},
{
"cell": "대형브레이커(㎥/hr)",
"pum_table_id": "F0260",
@@ -1059,22 +1047,28 @@
"work_item_code": "FP-09-12-03"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0260",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-12-03"
"cell": "장비 (90%) | 유압식백호우 (무한궤도,0.7㎥) | 육상토사(01m)와 동일",
"pum_table_id": "F0262",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-02"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0261",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-01"
"cell": "장비 (90%) | 유압식백호우 (무한궤도,0.7㎥) | 육상토사(01m)와 동일",
"pum_table_id": "F0263",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-03"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0264",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-04"
"cell": "장비 (90%) | 유압식백호우 (무한궤도,0.7㎥) | 용수토사(01m)와 동일",
"pum_table_id": "F0265",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-05"
},
{
"cell": "장비 (90%) | 유압식백호우 (무한궤도,0.7㎥) | 용수토사(01m)와 동일",
"pum_table_id": "F0266",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-06"
},
{
"cell": "깨기",
@@ -1088,12 +1082,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-07"
},
{
"cell": "들어 내기",
"pum_table_id": "F0267",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-07"
},
{
"cell": "깨기",
"pum_table_id": "F0268",
@@ -1106,6 +1094,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-08"
},
{
"cell": "들어내기 | 유압식백호우 (무한궤도,0.7㎥) | 육상 암절취(01m)와 동일",
"pum_table_id": "F0268",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-08"
},
{
"cell": "깨기",
"pum_table_id": "F0269",
@@ -1118,6 +1112,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-09"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 육상 암절취(01m)와 동일",
"pum_table_id": "F0269",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-09"
},
{
"cell": "깨기",
"pum_table_id": "F0270",
@@ -1130,12 +1130,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-10"
},
{
"cell": "들어 내기",
"pum_table_id": "F0270",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-10"
},
{
"cell": "깨기",
"pum_table_id": "F0271",
@@ -1148,6 +1142,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-11"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 용수 암절취(01m)와 동일",
"pum_table_id": "F0271",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-11"
},
{
"cell": "깨기",
"pum_table_id": "F0272",
@@ -1160,6 +1160,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-12"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 용수 암절취(01m)와 동일",
"pum_table_id": "F0272",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-12"
},
{
"cell": "깨기",
"pum_table_id": "F0273",
@@ -1172,12 +1178,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-13"
},
{
"cell": "들어 내기",
"pum_table_id": "F0273",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-13"
},
{
"cell": "깨기",
"pum_table_id": "F0274",
@@ -1190,6 +1190,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-14"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 육상 발파암(12m)와 동일",
"pum_table_id": "F0274",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-14"
},
{
"cell": "깨기",
"pum_table_id": "F0275",
@@ -1202,6 +1208,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-15"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 육상 발파암(12m)와 동일",
"pum_table_id": "F0275",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-15"
},
{
"cell": "깨기",
"pum_table_id": "F0276",
@@ -1214,12 +1226,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-16"
},
{
"cell": "들어 내기",
"pum_table_id": "F0276",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-16"
},
{
"cell": "깨기",
"pum_table_id": "F0277",
@@ -1232,6 +1238,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-13-17"
},
{
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 용수 발파암(01m)와 동일",
"pum_table_id": "F0277",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-17"
},
{
"cell": "깨기",
"pum_table_id": "F0278",
@@ -1245,10 +1257,10 @@
"work_item_code": "FP-09-13-18"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0279",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-14-01"
"cell": "들어 내기 | 유압식백호우 (무한궤도,0.7㎥) | 용수 발파암(01m)와 동일",
"pum_table_id": "F0278",
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-09-13-18"
},
{
"cell": "모래ㆍ사질토ㆍ점토ㆍ점질토",
@@ -1286,12 +1298,6 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-19-01"
},
{
"cell": "유압식백호우 (무한궤도,0.7㎥)",
"pum_table_id": "F0290",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-09-19-02"
},
{
"cell": "공기압축기(3.5㎥/min)",
"pum_table_id": "F0291",
@@ -1580,30 +1586,12 @@
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-12-23"
},
{
"cell": "부설",
"pum_table_id": "F0372",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-12-24-02"
},
{
"cell": "적사",
"pum_table_id": "F0373",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-12-25"
},
{
"cell": "운반 및 설치 (목도운반)",
"pum_table_id": "F0374",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-12-26"
},
{
"cell": "부설",
"pum_table_id": "F0371",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-12-24-01"
},
{
"cell": "접착제",
"pum_table_id": "F0376",
@@ -1694,12 +1682,6 @@
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-13-06-01"
},
{
"cell": "굴 삭 기 (무한궤도)",
"pum_table_id": "F0419",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-13-06-01"
},
{
"cell": "보통인부 | | 〃",
"pum_table_id": "F0420",
@@ -1724,12 +1706,6 @@
"reason": "자원은 알아봤으나 값을 못 읽었습니다 — 단가가 일부만 섭니다.",
"work_item_code": "FP-13-07-02"
},
{
"cell": "굴 삭 기 (무한궤도)",
"pum_table_id": "F0423",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-13-07-02"
},
{
"cell": "보통 인부 (인) | 0.9m 1.2m 1.5m 1.8m 2.1m 2.4m 2.7m 3.0m 3.5m 4.0m 4.5m | 0.022 0.034 0.05 0.07 - - - - - - -",
"pum_table_id": "F0427",
@@ -1880,12 +1856,6 @@
"reason": "같은 갈래 이름이 두 번 나오는 표 — 등급을 단정할 수 없어 버렸습니다.",
"work_item_code": "FP-13-13-01"
},
{
"cell": "굴착기 (0.2㎥)",
"pum_table_id": "F0441",
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
"work_item_code": "FP-13-13-02"
},
{
"cell": "어려운 조건",
"pum_table_id": "F0447",