feat(b06,b08): 다단 벽 몸이 성토 폐회로에도 든 겹침을 줄 사유로 드러냄 — 고치지 않음(2026-09-06 확정 「구조물 면적 안 뺌」 · 판정은 사용자)

서버 Node 가 벽 몸 ∩ 성토 폐회로 넓이를 재 design.extra_walls[].fill_overlap_m2 로 남기고 B08 다단 줄 비고에 「벽 몸 N㎡ × 연장 ≈ ㎥ 두 번 셈」 · 258.12 1단 1.335㎡ × 10m ≈ 13.3㎥ · 금액 변화 0 · 미확정 단은 안 붙임

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
2026-09-14 14:47:38 +09:00
co-authored by Claude Opus 5
parent df547a90f8
commit eb79091e00
5 changed files with 188 additions and 21 deletions
@@ -0,0 +1,73 @@
"""벽 몸 중 **성토 폐회로 안에 든 넓이** — `wallBodyInFillM2` (2026-09-14 브레인 「사유로 드러낼 것」).
폐회로 면적은 구조물 면적을 안 뺌(2026-09-06 사용자 확정)이라 벽 몸이 성토에도 들어감.
그 겹침을 재서 B08 줄 사유로 올림 — 고치지 않음. 실제 코드를 컴파일해 Node 로 돌림.
"""
import json
import subprocess
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
MODULE = PROJECT_ROOT / "common_util" / "common_util_cross_structure_areas.ts"
# 지반 0 · 트림 밖(offset 5~20)은 표고 1.0 수평 성토선 · 벽 몸 offset 10~11 · 표고 −0.5~1.5
# ⇒ 성토 안(지반 0 ~ 선 1.0)에 든 몸 = 1 × 1 = 1.0㎡ · 지반 아래·선 위는 안 셈.
_RUNNER = """
const { wallBodyInFillM2 } = require(process.argv[3]);
const { writeFileSync } = require("node:fs");
const line = [];
for (let o = -20; o <= 20; o += 1) line.push({ offset: o, elevation: 0 });
const input = {
designLine: line.map((p) => ({ offset_m: p.offset, elevation_m: 0 })),
ground: line,
trim: { minOffset: -5, maxOffset: 5, maxSlope: { points: [{ offset: 5, elevation: 1 }, { offset: 20, elevation: 1 }] } },
};
const body = [
{ offset: 10, elevation: -0.5 },
{ offset: 10, elevation: 1.5 },
{ offset: 11, elevation: 1.5 },
{ offset: 11, elevation: -0.5 },
];
const outside = body.map((p) => ({ offset: p.offset - 30, elevation: p.elevation }));
writeFileSync(process.argv[2], JSON.stringify({ inFill: wallBodyInFillM2(body, input), outside: wallBodyInFillM2(outside, input) }));
"""
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_벽_몸_중_성토_안_넓이만_잰다(tmp_path: Path) -> None:
out = tmp_path / "out"
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
"--ignoreConfig",
"--target",
"es2022",
"--module",
"commonjs",
"--skipLibCheck",
"--outDir",
str(out),
str(MODULE),
],
cwd=str(PROJECT_ROOT),
check=False,
capture_output=True,
)
compiled = next(out.rglob("common_util_cross_structure_areas.js"), None)
assert compiled is not None, "tsc 실패"
(out / "runner.cjs").write_text(_RUNNER, encoding="utf-8")
result = tmp_path / "result.json"
subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(out / "runner.cjs"), str(result), str(compiled)],
cwd=str(PROJECT_ROOT),
check=True,
capture_output=True,
)
produced = json.loads(result.read_text(encoding="utf-8"))
assert produced["inFill"] == pytest.approx(1.0, abs=1e-3)
assert produced["outside"] == pytest.approx(0.0, abs=1e-9) # 설계선이 지반 그대로인 자리
+14
View File
@@ -125,6 +125,20 @@ def test_미확정_단은_성토를_안_깎는다() -> None:
assert "applied.h == null" in geom
def test_벽_몸이_성토에도_든_겹침을_사유로_드러냄() -> None:
"""2026-09-14 브레인 — 폐회로는 구조물 면적을 안 뺌(2026-09-06 확정)이라 벽 몸이 성토에도 셈.
고치지 않고 사유로: 258.12 실측 1단 벽 몸 1.335㎡ 가 성토 폐회로 안."""
walls = [dict(WALLS[0], fill_overlap_m2=1.336, before_m=5.0, after_m=5.0)]
note = " ".join(_tiers(facility_structures([POINT], {85.0: walls}))[0]["notes"])
assert "성토 면적에도" in note and "1.34㎡" in note and "13.4㎥" in note
bare = " ".join(_tiers(facility_structures([POINT], {85.0: WALLS[:1]}))[0]["notes"])
assert "성토 면적에도" not in bare # 값이 없으면(옛 저장본) 지어내지 않음
def test_서버가_벽_몸_겹침을_잰다() -> None:
assert "wallBodyInFillM2(" in LAYOUTS and "fill_overlap_m2" in LAYOUTS
def test_목록이_없으면_종전과_같다() -> None:
assert not _tiers(facility_structures([POINT]))
assert not _tiers(facility_structures([POINT], {}))