feat(B07): 표준도 제원에 「기초」 칸 + 그림을 새 두께 식에 맞춤

**기초 칸**(`foundation` — 기초유 / 기초버림, 정본 xls 탭 제목 그대로)
터파기 기초 몫이 0.5×(0.7+0.2)=0.45 대 0.1×(0.7+0.0)=0.07 ㎥/m 로 갈리고, 횡단도
터파기 선도 같은 칸을 봄. 고를 자리가 어디에도 없어 비어 있던 값임.
정본에 없는 갈래를 넣으면 **막지 않고 알림**(기존 네 칸과 같은 결). 비우면 키를 지움.

**그림을 새 두께 식에 맞춤** — 데스크탑 메인이 `STONE_MASONRY` 를 갈면서
`thickness_base_m`·`thickness_top_coeff`·`thickness_bottom_coeff` 가 사라져
그림이 `KeyError` 로 죽었음(도면이 「읽지 못했습니다」로 뜸). 실화면에서 잡았음.
  상부 = 뒷길이 + 0.30 · 하부 = 상부 + 0.30 × (H − 1.0)
  H=1.0 ℓ45 → 0.75/0.75 · H=1.5 ℓ35 → 0.65/0.80 · H=2.0 ℓ35 → 0.65/0.95 ·
  H=2.0 ℓ45 → 0.75/1.05 · H=3.0 ℓ45 → 0.75/1.35   ← 실무 원본과 전부 일치

⚠ **뒷길이를 안 정한 장은 두께를 못 내므로 그리지 않음** — 0 으로 때우면 거짓 그림이 됨.

⚠ 배운 것 — 「그림이 상수를 직접 읽으니 저절로 따라온다」가 **키 이름이 바뀌면 깨진다**는
   것으로 드러남. 값은 한 벌이 맞으나 **이름이 바뀌는 것은 예고가 필요함.**

실화면 확인 — 「표준도 3장」에서 기초 「기초유」 저장 → 「2개소에 반영했습니다」,
정본 실측 `[기초유, null, 기초유, null, null]`(그 장의 두 개소에만).

자체검증 — 새 시험 3건 + 회귀 583 통과 · 0 실패, `tsc --noEmit` 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 21:44:28 +09:00
co-authored by Claude Opus 5
parent 2c48ca6b1c
commit e128f651fc
5 changed files with 66 additions and 19 deletions
@@ -25,7 +25,18 @@ from typing import Any
from B05_Profile.B05_Profile_Structures_Schema import StructureInstance
#: 표준도에서 받는 칸 — `키 → (이름, 검사)`. 여기 없는 칸은 표준도가 안 만진다.
EDITABLE_KEYS: tuple[str, ...] = ("stone_kind", "stone_supply", "back_len_cm", "face_slope_ratio")
EDITABLE_KEYS: tuple[str, ...] = (
"stone_kind",
"stone_supply",
"back_len_cm",
"face_slope_ratio",
"foundation",
)
#: 기초 갈래 — 정본 xls 탭 제목 그대로(`04.구조도(기슭막이).xls`).
#: ⚠ **물량과 그림이 같은 칸을 본다** — 터파기 기초 몫이 0.5×(0.7+0.2)=0.45 대
#: 0.1×(0.7+0.0)=0.07 ㎥/m 로 갈리고, 횡단도 터파기 선도 이 값으로 그려진다.
FOUNDATION_CHOICES: tuple[str, ...] = ("기초유", "기초버림")
#: 품셈 13-4-3·13-4-4 [주]① 의 일곱 규격. 그 밖의 값은 계수가 없어 물량이 안 선다.
BACK_LENGTH_CHOICES: tuple[int, ...] = (25, 30, 35, 45, 55, 60, 75)
@@ -39,6 +50,7 @@ FIELD_LABELS: dict[str, str] = {
"stone_supply": "조달",
"back_len_cm": "뒷길이",
"face_slope_ratio": "전면 기울기",
"foundation": "기초",
}
@@ -95,6 +107,15 @@ def clean_spec(spec: dict[str, Any]) -> tuple[dict[str, Any], list[str]]:
"물량이 서지 않습니다."
)
if "foundation" in spec:
found = spec.get("foundation")
cleaned["foundation"] = str(found) if found not in (None, "") else None
if cleaned["foundation"] and cleaned["foundation"] not in FOUNDATION_CHOICES:
notes.append(
f"기초 「{cleaned['foundation']}」는 정본에 없는 갈래입니다 "
f"(있는 것: {' · '.join(FOUNDATION_CHOICES)})."
)
if "face_slope_ratio" in spec:
ratio, note = _clean_slope(spec.get("face_slope_ratio"))
cleaned["face_slope_ratio"] = ratio