feat(B08): B군 종단배수를 공종에 이음 — 연장이 금액까지 감 (V-3)

랩탑이 「연장은 나오는데 그 뒤가 안 봤다」고 해서 세 걸음을 한 번에 봤음.
끊긴 자리가 둘이었음.

① 매핑에 B군이 하나도 없었음 — 연장 40.0m 은 인계까지 오는데
   공종코드가 비어 있었음. 품셈에 있는 셋을 이었음
     산마루측구 FP-12-09-02 · 소단측구 FP-12-09-03 · 맹암거 FP-12-10
     셋 다 밑수 1 m — 구조물 연장이 그대로 수량
   도수로·절토사면 배수로는 품셈에 그 공종이 없어 pending_user 로 남김
   (마스터 전수: 「수로」로 찾아도 나오는 것은 위 셋뿐)

② ⚠ 「전개식이 없다」로 단정해 B09 가 금액을 안 붙이고 있었음
   B군은 연장이 곧 수량이라 원단위 전개가 필요 없는데,
   blocked_of 가 「성분이 없으면 formula_missing」으로 봤음
   ⇒ 공종코드가 붙었고 수량이 있으면 막힌 것이 아님

실측(맹암거 40m): 0원 → 1,019,685원. 산마루·소단측구는 B09 일위대가 대기.

⚠ 그 김에 확인된 것 — verify_bill_flags 가 「코드 없이 내역에 서는 줄」을
제대로 잡고 있었음(도수로·절토사면 배수로 둘).

시험 셋 — 연장으로 서는 공종은 안 막힘 · ⚠ 코드 없으면 여전히 막힘 ·
⚠ 연장 0 이면 코드가 있어도 막힘 (둘 다 0원 줄을 막는 짝).
시험: 704 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 10:13:16 +09:00
co-authored by Claude Opus 5
parent 1ad40fa2fb
commit cbf991d5be
2 changed files with 42 additions and 2 deletions
+12 -2
View File
@@ -583,13 +583,23 @@ def _haul_rows(
return rows, unmatched
def blocked_of(structure: dict[str, Any], class_basis: str = "") -> tuple[str | None, str]:
def blocked_of(
structure: dict[str, Any], class_basis: str = "", has_code: bool = False
) -> tuple[str | None, str]:
"""(막힌 갈래, 사유). 안 막혔으면 `(None, "")`.
⚠ 사유 문구는 **`B08_Quantity_Wording` 것을 그대로** 쓴다 — 두 벌로 짜면 갈린다.
전개 알림(`notes`)에 이미 사람 말로 적혀 있으므로 그것을 그대로 옮긴다.
⚠⚠ **전개식이 없다고 다 막힌 것이 아니다** (2026-09-08 V-3 에서 드러남).
B군 종단배수(산마루측구 12-9-2 · 소단측구 12-9-3 · 맹암거 12-10)는 품셈 밑수가
**1 m** 라 **연장이 곧 수량**이다 — 원단위 전개가 필요 없다. 그런데 「성분이 없으면
전개식 없음」으로 단정해 B09 가 **「우리가 만들 것」으로 빼 금액이 0** 이었다.
**공종코드가 붙었고 수량이 있으면 막힌 것이 아니다.**
"""
notes = [str(note) for note in structure.get("notes") or []]
if has_code and float(structure.get("length_m") or 0.0) > 0:
return None, ""
if structure.get("components"):
# 물량은 섰는데 **단가 갈래**를 못 고른 자리(돌쌓기 뒷길이 등).
if class_basis and "입력되지 않았습니다" in class_basis:
@@ -647,7 +657,7 @@ def _structure_rows(
parts_missing: list[dict[str, Any]] = []
if composite:
parts, parts_missing = composite_quantities(structure, composite, mapping)
blocked_kind, blocked_reason = blocked_of(structure, class_basis)
blocked_kind, blocked_reason = blocked_of(structure, class_basis, has_code=bool(code))
# 갈래 축과 **저장 제원 원본값**. 가공하지 않는다.
variant_axis = str(entry.get("variant_axis") or "") or None
variant_value = (structure.get("options") or {}).get(variant_axis) if variant_axis else None
@@ -150,6 +150,24 @@
},
"class_note": "메/찰(`bond`)은 **공종 자체가 갈리는 의미 판정**이라 여기서 고른다. 직경 갈래는 `variant_value` 로 원본값만 보낸다 — 원문이 물결표를 섞어 써서.",
"variant_axis": "stone_cm"
},
{
"type_id": "ditch_ridge",
"work_item_code": "FP-12-09-02",
"master_name": "측구 > 산마루 측구",
"note": "품셈 12-9-2 · 밑수 1 m — 구조물 연장(m)이 그대로 수량이다. 2026-09-08 V-3 확인에서 이었다(그전에는 매핑이 없어 연장은 오는데 공종코드가 비어 있었다)."
},
{
"type_id": "ditch_berm",
"work_item_code": "FP-12-09-03",
"master_name": "측구 > 소단 측구",
"note": "품셈 12-9-3 · 밑수 1 m"
},
{
"type_id": "underdrain",
"work_item_code": "FP-12-10",
"master_name": "맹암거",
"note": "품셈 12-10 · 밑수 1 m"
}
],
"pending_user": {
@@ -171,6 +189,18 @@
"FP-09-05 발파암"
],
"why": "설계자가 넣는 암 갈래 이름(풍화암·연암·보통암·경암)이 리핑이냐 발파냐를 말하지 않음. 갈래마다 시공법을 지정하는 칸이 필요함"
},
{
"type_id": "chute",
"name": "도수로·산비탈수로",
"why": "품셈 12장 측구 계열(12-9-1 L형 · 12-9-2 산마루 · 12-9-3 소단)과 12-10 맹암거에 **해당 공종이 없음**(2026-09-08 마스터 전수). 「수로」로 검색해도 나오는 것은 그 셋뿐임.",
"needs": "어느 공종으로 볼지 사용자 확정 — 또는 별도 표준도·일위대가"
},
{
"type_id": "slope_drain",
"name": "절토사면 배수로",
"why": "위와 같음 — 품셈에 그 이름의 공종이 없음.",
"needs": "어느 공종으로 볼지 사용자 확정"
}
]
},