fix(B09): 산출근거 문구 괄호 정정 · 진행단계 라벨도 「원가계산」으로

화면 실측에서 드러난 표기 오류 셋 (공용 브라우저 5174 조작 확인):
- **이윤 밑수가 뒤바뀌어 읽힘** — `(순공사원가+일반관리비) − 재료비 × 15%` 로 나와
  재료비에만 15 %를 곱하는 것처럼 보였음. 밑수가 합·차면 괄호를 씌우도록 고쳐
  `((순공사원가+일반관리비) − 재료비) × 15.0%` 로 나옴.
- **안전관리비 B 산출근거에 밑수 설명 문장이 통째로 박혀** 식이 안 읽혔음.
  밑수 라벨을 「재료비+직접노무비 (관급 제외)」로 줄이고 ×1.2 는 대괄호로 감쌈.
- **채택 요약 줄에 요율이 한 번 더 붙던 것** 제거 — 산식은 A·B 줄에 이미 있음.
- `WF_Step_Estimation` 라벨도 「설계도서」→「원가계산」 (페이지명과 어긋나 있었음).
- `F402` 정리: 구간 지문 루프 변수가 `dataclasses.field` 를 가리던 것 이름 변경.

자체검증 — 브라우저 실측 29줄 렌더 · 요율 판(2026-04-13 / 지문 250b1e4d…) 표시 ·
안전관리비 A 채택/B 취소선 · 환경보전비 「미확정」 경고 표시 ·
목표 도급공사비 1,192,000,000 입력 시 필요 조정액 **394,456** 제안(적용은 안 함) ·
`(1,192,433,902 − 1,192,000,000) ÷ 1.1 = 394,456` 손검산 일치.
pytest 32 passed · ruff 통과 · tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-07 20:16:22 +09:00
co-authored by Claude Opus 5
parent 2a21f99ba4
commit ec23f87f83
3 changed files with 14 additions and 8 deletions
+12 -6
View File
@@ -130,13 +130,19 @@ class CostLine:
실무 원문은 안전관리비 A 식을 B 줄에 복사해 둔 오류가 있었다(PLAN 8-13).
"""
if self.rate_percent is None:
if self.rate_percent is None or self.key == "safety_management_cost":
# 채택 요약 줄은 요율을 다시 붙이지 않는다 — 산식은 A·B 줄에 이미 있다.
return self.base_label
text = f"{self.base_label} × {self.rate_percent}%"
# 밑수가 합·차로 이루어졌으면 괄호를 씌운다.
# 안 씌우면 「(순공사원가+일반관리비) − 재료비 × 15%」처럼 곱하는 대상이 뒤바뀌어 읽힌다.
base = self.base_label
if any(mark in base for mark in ("+", "", "×")):
base = f"({base})"
text = f"{base} × {self.rate_percent}%"
if self.flat_amount_krw:
text += f" + {self.flat_amount_krw:,.0f}"
if self.key == "safety_management_cost_b":
text = f"({text}) × 1.2"
text = f"[{text}] × 1.2"
return text
@@ -211,7 +217,7 @@ def _scale_signature(dataset: RateDataset, amount: Decimal) -> tuple:
규모(추정가격)로 갈리는 요율만 모은다. 지문이 같으면 더 돌 필요가 없다.
"""
parts: list[str] = []
for variable, field, key in (
for variable, bracket_field, key in (
("rate_overhead", "estimated_price_bracket", "civil_landscape_industrial"),
("rate_profit", "estimated_price_bracket", "brackets"),
("rate_goyong", "estimated_amount_bracket", "brackets"),
@@ -223,7 +229,7 @@ def _scale_signature(dataset: RateDataset, amount: Decimal) -> tuple:
try:
row = select_bracket(
rows,
amount_field=field,
amount_field=bracket_field,
amount=amount,
residual_label="below_official_threshold",
label=variable,
@@ -231,7 +237,7 @@ def _scale_signature(dataset: RateDataset, amount: Decimal) -> tuple:
except Exception: # noqa: BLE001 - 구간 밖이면 지문에서 뺀다
parts.append(f"{variable}:none")
continue
parts.append(f"{variable}:{row.get(field)}")
parts.append(f"{variable}:{row.get(bracket_field)}")
# 적용 하한(추정금액 1억 이상 등)도 구간과 같은 축이다.
for variable in ("rate_environment", "rate_retirement_mutual_aid"):
+1 -1
View File
@@ -217,7 +217,7 @@ def safety_management_cost(
amount_b = emit(
key="safety_management_cost_b",
name="산업안전보건관리비 B(관급 제외 × 1.2)",
base_label="(재료비+직접노무비) × 요율 + 기초액, 그 값의 1.2배",
base_label="재료비+직접노무비 (관급 제외)",
base=base_without,
percent=percent_b,
flat=flat_b,
+1 -1
View File
@@ -82,7 +82,7 @@ export const ui_locales_common = {
WF_Step_ProfileCross: ["횡단설계", "Cross Design"],
WF_Step_DesignDetail: ["상세설계", "Detail Design"],
WF_Step_Quantity: ["수량산출", "Quantity"],
WF_Step_Estimation: ["설계도서", "Design Docs"],
WF_Step_Estimation: ["원가계산", "Cost Estimate"],
WF_State_Stale: ["무효화됨 (하위 단계 변경)", "Stale (invalidated by downstream changes)"],
WF_State_Failed: ["실패", "Failed"],
WF_State_Complete: ["완료", "Complete"],