refactor(511-B B-6 옛 server-calc 묶음 걷음): 운영 부름 0 · 시험 대조만이던 옛 묶음 걷음 — 걷기 전용 커밋(되돌리기 = 이 커밋 revert)

걷은 것
- B06_Section/B06_Section_Server_Calc_Node.ts 통째(135 줄 · 입구 · haul_plan_for 갈래 · 면적 · 유토곡선 · 다단 벽)
- package.json:8 build 안 「&& npm run build:server-calc」 · package.json:10 「build:server-calc」 줄
- B06_Section/B06_Section_Server_Calc_Prebuild.py:61 ROOT · :62-63 옛 묶음 주석 · BUNDLE · :66 _NPM_SCRIPT
- 지어진 묶음 config/server_calc_node/B06_Section_Server_Calc_Node.js = git 밖(.gitignore:63-64 그대로) · 폴더마다 찌꺼기 남음

시험 옮김(새 입구 = Prebuild._run_node · 등록부 Node design_calc_node)
- 110 · 120 · 131 · 73_4 · 178_1 · helper_472_1_paths = _run_node
- b06_ground_unlock · height_unlock = design_calc_node.js 판 검사(build:design-calc)
- 472_3 registry · runner = 옛 묶음 대조 → Node 입구 정본 값 · 늘 떠 있는 Node = 새 프로세스
- 511_c = 옛 대 새 대조 → 새 Node = 브라우저 TS(computeHaulPlan · structureAreaRows · extraWallRows)
- haul_plan_quantity_unpruned = 새 입구 · /haul-plan 그림 갈래 글 검사 · server_calc_node.mjs = design_calc_node structure.layouts
- 글만: Schema · HaulPlan · design_calc_node 주석 · B06 CLAUDE.md · 시험 셋 머리

검증: 고친 시험 15 파일 87 통과 · typecheck 0 — 요구 320-4 · 322

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 16:17:45 +09:00
co-authored by Claude Opus 5.5
parent 55f1a7c5cc
commit 210ff06dee
23 changed files with 90 additions and 259 deletions
+6 -9
View File
@@ -2,7 +2,7 @@
stored GET 상세(정본 그대로) → 누가토량(서버 Node 묶음 `computeMassHaul`)
server_save [저장] 서버 재계산 — 정본 상세 → 종단 경고 다시 셈(`refresh_alignment` · 472 덧) →
`enforce_design_lines` → `_enforce_stored_designs` → server-calc
`enforce_design_lines` → `_enforce_stored_designs` → 서버 Node(`_run_node`)
server_route 노선 저장 체인(같은 노선 · DB 없이) — `run_section_generation`(고정 geojson · npz)
→ `_carry_profile` 같은 노선 갈래(옛 base_pvi · 편집) → `_apply_alignment_edits` →
측점 열쇠 이월(`carry_cross_inputs`) → `compute_default_designs` → 상세 읽기 →
@@ -131,12 +131,10 @@ def _save_tail(detail: dict[str, Any], root: Path) -> tuple[list, dict | None]:
from B06_Section.B06_Section_Router_Design import enforce_design_lines
from B06_Section.B06_Section_Server_Calc_Prebuild import (
_AREA_KEYS,
_NPM_SCRIPT,
BUNDLE,
_enforce_stored_designs,
_run_node,
refresh_alignment,
)
from common_util.common_util_node_bundle import run_bundle_json
from common_util.common_util_surface_sampler import build_surface_sampler
longitudinal = detail["longitudinal"]
@@ -151,9 +149,9 @@ def _save_tail(detail: dict[str, Any], root: Path) -> tuple[list, dict | None]:
detail = json.loads(
json.dumps(detail, default=str)
) # 응답 직렬화와 같은 꼴(`model_dump(json)`)
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": detail, "context": _context()})
output = _run_node({"detail": detail, "context": _context()})
if not isinstance(output, dict):
raise RuntimeError("server-calc 묶음 실패")
raise RuntimeError("서버 Node(_run_node) 실패")
sections = detail["cross_sections"]
for row in output.get("areas") or []:
for section in sections:
@@ -261,13 +259,12 @@ def server_route(root: Path) -> dict[str, Any]:
def stored(root: Path) -> dict[str, Any]:
"""정본 그대로 — GET 상세 면적 · 서버 Node 묶음과 같은 누가토량(화면 배지 값)."""
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
detail = read("detail.json")
alignment = detail["longitudinal"].get("profile_alignment") or {}
keys = _keys(detail["longitudinal"], detail["cross_sections"], root)
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": detail, "context": _context()})
output = _run_node({"detail": detail, "context": _context()})
haul = (output or {}).get("mass_haul")
return values_of(
detail["cross_sections"],
+2 -3
View File
@@ -101,10 +101,9 @@ def test_패치가_받는다() -> None:
def _server_rows(sections: list[dict]) -> dict[float, dict]:
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": {"cross_sections": sections}})
output = _run_node({"detail": {"cross_sections": sections}})
assert output, "서버 Node 번들 실행 실패"
return {round(r["chainage_m"], 3): r for r in output["areas"]}
@@ -288,15 +288,14 @@ def test_패치가_박스_길이를_받는다():
@needs_node
def test_서버가_박스_본체_길이를_주인_측점에만():
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
data = json.loads((FIXTURES / "b06_73_4_body_guard_sections.json").read_text("utf-8"))
sections = data["cross_sections"]
box_at = next(s for s in sections if s.get("box"))
neighbour = next(s for s in sections if s["chainage_m"] == 340)
neighbour["box"] = copy.deepcopy(box_at["box"])
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": {"cross_sections": sections}})
output = _run_node({"detail": {"cross_sections": sections}})
rows = {round(r["chainage_m"], 3): r for r in output["areas"]}
assert rows[352.14]["box_length_m"] > 0
assert "box_length_m" not in rows[340]
@@ -145,15 +145,14 @@ def test_세월교_관_길이_없으면_빈칸_알림(tmp_path):
@needs_node
def test_서버가_세월교_관_길이를_주인_측점에만():
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
data = json.loads((FIXTURES / "b06_73_4_body_guard_sections.json").read_text("utf-8"))
sections = data["cross_sections"]
ford_at = next(s for s in sections if s.get("ford"))
neighbour = next(s for s in sections if s["chainage_m"] == 180)
neighbour["ford"] = copy.deepcopy(ford_at["ford"])
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": {"cross_sections": sections}})
output = _run_node({"detail": {"cross_sections": sections}})
rows = {round(r["chainage_m"], 3): r for r in output["areas"]}
length = rows[173.087]["ford_pipe_length_m"]
assert length > 0 and length == int(length) # 1 m 올림
@@ -5,12 +5,11 @@
⇒ 관 링크는 있으나 관 벽이 안 서는 측점에서 카드엔 흙막이가 서고 서버 면적 · B07 엔 없음.
고침: `ownWallsDrawAt` 한 벌을 세 곳이 함께 씀. 서버 면적은 같은 TS 를 Node 로 돌리므로
번들을 새로 빌드해 그 결과로 판정한다.
[저장] 재계산 Node 입구(`_run_node`) 결과로 판정한다.
"""
import copy
import json
import subprocess
from pathlib import Path
import pytest
@@ -32,36 +31,17 @@ SOIL_GUARD = {
@pytest.fixture(scope="module")
def bundle(tmp_path_factory) -> Path:
def bundle():
"""서버 면적 = [저장] 재계산 Node 입구(`_run_node` · 옛 server-calc 묶음 = 511-B B-6 걷음)."""
if not VITE.is_file():
pytest.skip("프론트엔드 의존성 미설치")
out = tmp_path_factory.mktemp("server_calc")
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(VITE),
"build",
"--configLoader",
"runner",
"--ssr",
"../B06_Section/B06_Section_Server_Calc_Node.ts",
"--outDir",
str(out),
"--logLevel",
"error",
],
cwd=str(ROOT),
check=True,
capture_output=True,
)
return out / "B06_Section_Server_Calc_Node.js"
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
return _run_node
def _areas(bundle: Path, sections: list, tmp_path: Path) -> dict[float, tuple]:
src, dst = tmp_path / "in.json", tmp_path / "out.json"
src.write_text(json.dumps({"detail": {"cross_sections": sections}}), encoding="utf-8")
subprocess.run(["node", str(bundle), str(src), str(dst)], check=True, cwd=str(ROOT)) # noqa: S603
rows = json.loads(dst.read_text(encoding="utf-8"))["areas"]
def _areas(bundle, sections: list, tmp_path: Path) -> dict[float, tuple]:
rows = bundle({"detail": {"cross_sections": sections}})["areas"]
return {row["chainage_m"]: (row["cut_area_m2"], row["fill_area_m2"]) for row in rows}
+6 -13
View File
@@ -11,8 +11,8 @@ Node 입구 = `A00_Common/design/logic/design_calc_node.ts`(`build:design-calc`
- 서버 쪽(server_canon · server_only) TS 가 브라우저 import 그래프에 없음 · 등록부는 안 끔.
- Node 입구 도달 집합 = logic · common_util · 자료만 + 「알려진 끌림」(`KNOWN_PULLS`) — 그 밖은
실패 · 안 나타난 알려진 끌림도 실패(목록에서 지움 — 472-2 2-B · 472-4 가 하나씩 걷어 빈 목록).
- Node 입구 값 = 기존 묶음 값(고정 자료 `fixtures/golden_472` · server-calc 면적 · 다단 벽 ·
누가토량 · 배분 · corridor 3D) · 터파기 = 파이썬 짝.
- Node 입구 값(고정 자료 `fixtures/golden_472` · 면적 · 다단 벽 · 누가토량 끝값 · 배분 두 벌 ·
corridor 3D = corridor 묶음) · 터파기 = 파이썬 짝.
./venv/Scripts/python.exe -m pytest resources/tester/test_472_3_calc_registry.py -q
"""
@@ -306,19 +306,12 @@ def golden_run() -> dict:
return out["results"]
def test_server_calc_묶음과_같음(golden_run) -> None:
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT
from B06_Section.B06_Section_Server_Calc_Prebuild import BUNDLE as SC_BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
sc = run_bundle_json(
SC_BUNDLE, _NPM_SCRIPT, {"detail": _fixture("detail.json"), "context": _context()}
)
def test_Node_입구_정본_값(golden_run) -> None:
# 옛 server-calc 묶음 걷음(511-B B-6) — 값은 472-1 기준값 시험(`stored` · `server_save`)
layouts = golden_run["structure.layouts"]
assert layouts["areas"] == sc["areas"] and sc["areas"]
assert layouts["extra_walls"] == sc["extra_walls"]
assert layouts["areas"] and isinstance(layouts["extra_walls"], list)
merged = {**golden_run["masshaul.cumulative"], **golden_run["haul.plan"]}
assert merged == sc["mass_haul"]
assert merged["haul_plan"] and merged["haul_plan_drawing"]
assert merged["final_cumulative_m3"] == -17570.7 # 472-1 화면 참값
+9 -16
View File
@@ -2,8 +2,8 @@
못박는 것
- `NODE_IDS` = 등록부 `node:` 줄 = 입구 표(`available`).
- 고정 자료 `fixtures/golden_472` 로 `run_calc` 값 = [저장] 재계산이 부르는 server-calc 묶음 값
(`Server_Calc_Prebuild` BUNDLE · 면적 · 다단 벽 · 누가토량 · 배분 · 끝값 −17,570.7).
- 고정 자료 `fixtures/golden_472` 로 늘 떠 있는 Node `run_calc` 값 = 같은 묶음 새 프로세스 값
(면적 · 다단 벽 · 누가토량 · 배분 · 끝값 −17,570.7).
- Node 실행기 아닌 id(파이썬 · 브라우저 실행기)는 ValueError.
./venv/Scripts/python.exe -m pytest resources/tester/test_472_3_calc_runner.py -q
@@ -50,21 +50,14 @@ def test_NODE_IDS_등록부_입구와_같음() -> None:
assert set(out["available"]) == runner.NODE_IDS
def test_실행기_값_server_calc_와_같음() -> None:
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
sc = run_bundle_json(
BUNDLE, _NPM_SCRIPT, {"detail": _fixture("detail.json"), "context": _context()}
)
got = runner.run_calc(
["structure.layouts", "masshaul.cumulative", "haul.plan"],
{"detail": _fixture("detail.json"), "context": _context()},
)
assert got["structure.layouts"]["areas"] == sc["areas"] and sc["areas"]
assert got["structure.layouts"]["extra_walls"] == sc["extra_walls"]
def test_늘_떠_있는_Node_새_프로세스와_같음() -> None:
# 옛 server-calc 묶음 걷음(511-B B-6) — 늘 떠 있는 Node(`run_calc`) = 같은 묶음 새 프로세스
ids = ["structure.layouts", "masshaul.cumulative", "haul.plan"]
inputs = {"detail": _fixture("detail.json"), "context": _context()}
got = runner.run_calc(ids, inputs)
fresh = runner.run_bundle_json(runner.BUNDLE, runner.NPM_SCRIPT, {"run": ids, "inputs": inputs})
assert got == fresh["results"] and got["structure.layouts"]["areas"]
merged = {**got["masshaul.cumulative"], **got["haul.plan"]}
assert merged == sc["mass_haul"]
assert merged["final_cumulative_m3"] == -17570.7
+18 -18
View File
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
"""511-C (요구 320-4) — 유토 배분 E2 = 늘 떠 있는 Node(TS 한 벌) · 옛 server-calc 묶음 값과 0 차.
"""511-C (요구 320-4) — 유토 배분 E2 = 늘 떠 있는 Node(TS 한 벌) = 브라우저 자리 TS 0 차.
못박는 것
- /haul-plan 창구 새 길(`_run_view` → 시험 길 `haul.view`) = 옛 server-calc `haul_plan_for` 갈래
- /haul-plan 창구 새 길(`_run_view` → 시험 길 `haul.view`)
= 브라우저 자리 함수(`computeHaulPlan` 바로 부름) — 프로젝트 일곱
(저장 유토곡선 · DB 에서 한 번 뜬 `fixtures/haul_511_c.json`)
× 문맥(기본 · 장비 경계 없음 · 구조물 잔토 · 채집석) × 그림 · 수량.
- 끝 경우 — 측점 하나(배분 없음 null) · 둘 · 전부 0 · 전부 절토 · 전부 성토.
- [저장] 정본 새 길(`Server_Calc_Prebuild._node_output` → 늘 떠 있는 Node 셋) = 옛 server-calc
`{detail, context}` 답(면적 · 다단 벽 · 유토곡선 + 배분 두 벌) — golden_472 · 문맥 셋.
- [저장] 정본 새 길(`Server_Calc_Prebuild._node_output` → 늘 떠 있는 Node 셋) = 브라우저 자리
TS(`structureAreaRows` · `extraWallRows`) · 유토곡선 끝값 · 배분 두 벌 — golden_472 · 문맥 셋
(옛 server-calc 묶음 = 511-B B-6 걷음).
./venv/Scripts/python.exe -m pytest resources/tester/test_511_c_haul_node.py -q
"""
@@ -31,7 +32,6 @@ if str(ROOT) not in sys.path:
from B06_Section import B06_Section_Router_HaulPlan as haul_router # noqa: E402
from B06_Section import B06_Section_Server_Calc_Prebuild as prebuild # noqa: E402
from common_util.common_util_node_bundle import run_bundle_json # noqa: E402
pytestmark = pytest.mark.skipif(
shutil.which("node") is None or not (ROOT / "config" / "node_modules" / "vite").is_dir(),
@@ -106,14 +106,6 @@ def _browser(tmp_path: Path, calls: list[dict]) -> list:
return json.loads(proc.stdout)
def _old_view(result: dict, context: dict):
out = run_bundle_json(
prebuild.BUNDLE, prebuild._NPM_SCRIPT, {"haul_plan_for": result, "context": context}
)
assert isinstance(out, dict), out
return out["haul_plan"]
def _edge_results() -> dict[str, dict]:
conv = PROJECTS["483"]["conversion"]
@@ -147,7 +139,7 @@ def _edge_results() -> dict[str, dict]:
}
def test_창구_새_길_옛_묶음_브라우저_같음(tmp_path):
def test_창구_새_길_브라우저_같음(tmp_path):
cases = [
(f"{rid}·{name}", _result(payload), context)
for rid, payload in PROJECTS.items()
@@ -167,7 +159,6 @@ def test_창구_새_길_옛_묶음_브라우저_같음(tmp_path):
for index, (label, result, context) in enumerate(cases):
new = haul_router._run_view(result, context)
assert new is not None, label
assert new["haul_plan"] == _old_view(result, context), label
assert new["haul_plan"] == browser[2 * index], label
quantity = haul_router.run_calc_served(
["haul.view"],
@@ -189,11 +180,20 @@ def test_창구_새_길_옛_묶음_브라우저_같음(tmp_path):
@pytest.mark.parametrize("name", ["기본", "구조물 잔토", "채집석"])
def test_저장_정본_새_길_옛_묶음_같음(name, monkeypatch):
def test_저장_정본_새_길_브라우저_같음(name, monkeypatch, tmp_path):
monkeypatch.setattr(prebuild, "_NODE_CACHE", {})
detail = json.loads((GOLDEN / "detail.json").read_text(encoding="utf-8"))
node_input = {"detail": detail, "context": _contexts()[name]}
old = run_bundle_json(prebuild.BUNDLE, prebuild._NPM_SCRIPT, copy.deepcopy(node_input))
new = prebuild._node_output(copy.deepcopy(node_input))
assert new == old
layouts = "B06_Section/B06_Section_Structure_Layouts.ts"
sections = detail["cross_sections"]
areas, walls = _browser(
tmp_path,
[
{"mod": layouts, "fn": "structureAreaRows", "args": [sections]},
{"mod": layouts, "fn": "extraWallRows", "args": [sections]},
],
)
assert new["areas"] == areas and areas
assert new["extra_walls"] == walls
assert new["mass_haul"]["haul_plan"] and new["mass_haul"]["haul_plan_drawing"]
+2 -3
View File
@@ -69,11 +69,10 @@ def test_설계선_트림은_흙막이_쪽(screen: dict) -> None:
def test_서버_면적이_화면과_같음(screen: dict) -> None:
from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE
from common_util.common_util_node_bundle import run_bundle_json
from B06_Section.B06_Section_Server_Calc_Prebuild import _run_node
sections = json.loads(FIXTURE.read_text(encoding="utf-8"))["cross_sections"]
output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": {"cross_sections": sections}})
output = _run_node({"detail": {"cross_sections": sections}})
assert output, "서버 Node 번들 실행 실패"
server = {round(r["chainage_m"], 2): r for r in output["areas"]}
for row in screen["areas"]:
@@ -38,7 +38,7 @@ _COMPUTED_FIELDS = {
"cut_soil_area_m2",
"cut_rock_area_m2",
# 배수관 연장(m, 2026-09-08) — 사용자 값이 아니라 **기하가 낸 값**이다. 면적 넷과 **같은
# 다리**(`STRUCTURE_ROW_KEYS` → `B06_Section_Server_Calc_Node` →
# 다리**(`STRUCTURE_ROW_KEYS` → `design_calc_node` `structure.layouts` →
# `recompute_server_side`)로 서버가 다시 내므로 재계산에서 안 사라진다.
"pipe_length_m",
# B08 하상경사 원천(110) — 관 경사 · 박스 원지반 경사(%) · 관 길이와 같은 다리.
+3 -3
View File
@@ -1,7 +1,7 @@
"""원지반 잠금 풀기(54-45) — 흙막이 자리 · 다단 · 높이를 원지반이 막지 않음.
남는 규칙: 벽 윗면 노면 위 금지(d ≥ 0) · 관 보호공 흙막이 m 단위 자리(관 길이 정수).
서버 면적은 같은 TS 를 Node 로 돌림(`B06_Section_Server_Calc_Node.ts`) — 번들도 같은 판인지 봄.
서버 면적은 같은 TS 를 Node 로 돌림(`design_calc_node.ts` `structure.layouts`) — 번들도 같은 판인지 봄.
"""
import json
@@ -14,7 +14,7 @@ import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
B06 = PROJECT_ROOT / "B06_Section"
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
BUNDLE = PROJECT_ROOT / "config" / "server_calc_node" / "B06_Section_Server_Calc_Node.js"
BUNDLE = PROJECT_ROOT / "config" / "design_calc_node" / "design_calc_node.js"
_RUNNER = """
import { writeFileSync } from "node:fs";
@@ -101,5 +101,5 @@ def test_화면_서버_같은_판() -> None:
), "추가 흙막이 매몰 자리 금지가 남음"
bundle = BUNDLE.read_text(encoding="utf-8")
assert "outletReceivable" not in bundle and "requireCrossing" not in bundle, (
"서버 번들이 옛 판 — npm run build:server-calc"
"서버 번들이 옛 판 — npm run build:design-calc"
)
+4 -4
View File
@@ -1,7 +1,7 @@
"""높이 제약 풀기(54-51) — 관 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽 · 집수정 높이를 사용자 값 그대로.
남는 규칙: 그림이 안 서는 값(순수 높이 0 이하)만 0.1 에서 멈춤 · 토스트 없음.
서버 면적은 같은 TS 를 Node 로 돌림(`B06_Section_Server_Calc_Node.ts`) — 번들도 같은 판인지 봄.
서버 면적은 같은 TS 를 Node 로 돌림(`design_calc_node.ts` `structure.layouts`) — 번들도 같은 판인지 봄.
"""
import json
@@ -14,7 +14,7 @@ import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
B06 = PROJECT_ROOT / "B06_Section"
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
BUNDLE = PROJECT_ROOT / "config" / "server_calc_node" / "B06_Section_Server_Calc_Node.js"
BUNDLE = PROJECT_ROOT / "config" / "design_calc_node" / "design_calc_node.js"
_RUNNER = """
import { writeFileSync } from "node:fs";
@@ -92,5 +92,5 @@ def test_높이_토스트_없음_서버_같은_판() -> None:
panel = (B06 / "B06_Section_UI_Cross_Structure_Panel.ts").read_text(encoding="utf-8")
assert "Math.min(\n 2," not in panel, "집수정 내공 2m 상한이 남음"
bundle = BUNDLE.read_text(encoding="utf-8")
assert "EXTRA_WALL_MIN_HEIGHT_M" not in bundle, "서버 번들이 옛 판 — npm run build:server-calc"
assert "WALL_MIN_PURE_HEIGHT_M" in bundle, "서버 번들이 옛 판 — npm run build:server-calc"
assert "EXTRA_WALL_MIN_HEIGHT_M" not in bundle, "서버 번들이 옛 판 — npm run build:design-calc"
assert "WALL_MIN_PURE_HEIGHT_M" in bundle, "서버 번들이 옛 판 — npm run build:design-calc"
+1 -1
View File
@@ -3,7 +3,7 @@
무슨 일이었나 — 관 길이는 횡단 기하가 **m 단위 올림까지** 끝낸 값인데(`CulvertLayout.pipe.lengthM`)
**정본(`design`)에 없었다.** 그래서 수량(B08)이 관 11개를 보고도 **연장을 못 내** 배수관 공종이
막혀 있었다. B08 창은 「계산을 서버로 옮기든가 저장 때 남기든가」 둘로 갈래를 냈는데, 실제로는
**그 계산이 이미 서버 Node 로 돌고 있었다**(`B06_Section_Server_Calc_Node` ←
**그 계산이 이미 서버 Node 로 돌고 있었다**(`design_calc_node` `structure.layouts` ←
`Server_Calc_Prebuild.recompute_server_side`, [저장]·[확정] 때). 그래서 **그 다리에 값 한 줄만**
더 실었다 — 계산을 두 벌로 짜지 않는다(CLAUDE.md 5장).
+11 -4
View File
@@ -13,7 +13,8 @@ import { join, resolve } from "node:path";
import assert from "node:assert/strict";
const ROOT = resolve(import.meta.dirname, "../..");
const BUNDLE = join(ROOT, "config/server_calc_node/B06_Section_Server_Calc_Node.js");
// 옛 server-calc 묶음 걷음(511-B B-6) — 서버 정본 = 등록부 Node 입구 `structure.layouts`
const BUNDLE = join(ROOT, "config/design_calc_node/design_calc_node.js");
/** 평지 위 표준 횡단 한 측점 — 구조물 없음. */
function plainSection(chainage) {
@@ -30,7 +31,10 @@ function plainSection(chainage) {
{ offset_m: -3, elevation_m: 100 },
{ offset_m: 3, elevation_m: 100 },
],
road_edges: { left: { offset_m: -3, elevation_m: 100 }, right: { offset_m: 3, elevation_m: 100 } },
road_edges: {
left: { offset_m: -3, elevation_m: 100 },
right: { offset_m: 3, elevation_m: 100 },
},
cut_area_m2: 1.23,
fill_area_m2: 4.56,
},
@@ -42,10 +46,13 @@ const input = join(work, "input.json");
const output = join(work, "output.json");
writeFileSync(
input,
JSON.stringify({ detail: { cross_sections: [plainSection(0), plainSection(20)] } }),
JSON.stringify({
run: ["structure.layouts"],
inputs: { detail: { cross_sections: [plainSection(0), plainSection(20)] } },
}),
);
execFileSync("node", [BUNDLE, input, output], { cwd: ROOT });
const { areas: rows } = JSON.parse(readFileSync(output, "utf8"));
const { areas: rows } = JSON.parse(readFileSync(output, "utf8")).results["structure.layouts"];
assert.ok(Array.isArray(rows), "결과는 배열이어야 한다");
assert.equal(rows.length, 0, `구조물 없는 측점은 결과에 없어야 한다 (받은 수: ${rows.length})`);
@@ -5,7 +5,7 @@
② 형태별 높이 한도(메 2.0 · 찰 3.0 · 콘크리트 5.0) · 원지반 맞춤 자동 자르기 없음.
③ 벽 윗면은 노면 위로 올라오지 않음(넘으면 노면에서 멈춤).
서버 면적은 같은 TS 를 Node 로 돌리므로(`B06_Section_Server_Calc_Node.ts`) 이 함수가 곧 서버 기하.
서버 면적은 같은 TS 를 Node 로 돌리므로(`design_calc_node.ts` `structure.layouts`) 이 함수가 곧 서버 기하.
"""
import json
@@ -132,11 +132,16 @@ def test_수량_계획은_작은_봉우리도_운반으로_센다(tmp_path: Path
def test_서버_정본은_수량과_그림을_따로_둔다() -> None:
source = (PROJECT_ROOT / "B06_Section" / "B06_Section_Server_Calc_Node.ts").read_text(
# 옛 server-calc 묶음 걷음(511-B B-6) — 저장 정본 = 등록부 Node 입구 · 화면 선반입 = /haul-plan
source = (PROJECT_ROOT / "A00_Common" / "design" / "logic" / "design_calc_node.ts").read_text(
encoding="utf-8"
)
view = (PROJECT_ROOT / "B06_Section" / "B06_Section_Router_HaulPlan.py").read_text(
encoding="utf-8"
)
# ③ 화면 선반입(그림)은 거른 계획, 저장 정본은 둘 다.
assert "drawing: true" in source
assert 'options["drawing"] = True' in view
assert "planFor(false)" in source and "planFor(true)" in source
assert "haul_plan_drawing" in source