⚠ **뿌리** — `tmp/` 는 창 사이에 안 건너감(실측 확인: 상대 창이 놓은 `tmp/_sync_probe.txt` 가 시간을 두고 두 번 봐도 안 보임). 그래서 **정본(등록부 스키마)만 건너가고 그것을 읽는 시험은 안 건너가** 오늘 두 번, 같은 시험이 **연 창은 통과·받은 창은 실패**가 됐음. - `tmp/tests/*` 를 `resources/tester/` 로 **복사**(127 파일). 내용은 **한 줄도 안 고침** - `tmp/tests` 는 **남겨 둠** — 되돌릴 자리(사용자 지시) - 실행: `./venv/Scripts/python.exe -m pytest resources/tester/ -q` 옮기기 전과 **같은 수**: 617 통과 / 22 건너뜀 / 실패 0 ⇒ 이제 시험·예외·까닭이 **정본과 함께** 움직임. 오늘 세운 「예외는 정본 스키마에」와 짝임. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
"""사용자 값이 재계산에서 사라지지 않는지 — **키 이름으로** 지킨다.
|
|
|
|
왜 (2026-09-07 전수 조사) — 횡단 `design` 딕셔너리는 사용자 값과 계산 값이 한 칸에 섞여
|
|
있고, 재계산(`enforce_pavement_ranges`·`enforce_ford_surface_drops`)은 결과를 통째로
|
|
갈아 끼운다. 그래서 사용자 값이 살아남는 길은 **둘뿐**이다:
|
|
|
|
① 재계산에 **인자로 되먹여** 결과에 그대로 나오는 것
|
|
(`ground_type`·`section_mode`·`ditch_side`·`ditch_type`·`paved`·
|
|
`two_stage_slope`·`rock_boundary_offset_m`)
|
|
② 계산이 만들지 않아 **목록으로 베껴 넣는** 것 (`USER_TOUCHED_KEYS`)
|
|
|
|
어느 쪽에도 안 걸린 사용자 값은 **저장할 때 조용히 사라진다**. 실제로 그렇게 사라졌던
|
|
것이 `extra_spans` 였다(`b6941bd2`). 이 시험은 그 구멍을 다시 못 나게 못박는다 —
|
|
새 사용자 값을 `CrossSectionPatch` 에 더하면서 ①·② 어느 쪽에도 안 넣으면 여기서 깨진다.
|
|
"""
|
|
|
|
import inspect
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from B06_Section.B06_Section_Engine_Design import compute_cross_design # noqa: E402
|
|
from B06_Section.B06_Section_Router_Design import USER_TOUCHED_KEYS # noqa: E402
|
|
from B06_Section.B06_Section_Schema import CrossSectionPatch # noqa: E402
|
|
|
|
#: 측점을 가리키는 열쇠 — 값이 아니다.
|
|
_KEY_FIELDS = {"chainage_m"}
|
|
|
|
#: 사용자 값이 아니라 **계산 값**이라 재계산이 다시 내는 것이 옳은 필드.
|
|
#: 브라우저가 조작 중 값을 함께 보내지만 정본은 서버가 다시 낸다(CLAUDE.md 5장).
|
|
_COMPUTED_FIELDS = {
|
|
"cut_area_m2",
|
|
"fill_area_m2",
|
|
"cut_soil_area_m2",
|
|
"cut_rock_area_m2",
|
|
# 배수관 연장(m, 2026-09-08) — 사용자 값이 아니라 **기하가 낸 값**이다. 면적 넷과 **같은
|
|
# 다리**(`STRUCTURE_ROW_KEYS` → `B06_Section_Server_Calc_Node` →
|
|
# `recompute_server_side`)로 서버가 다시 내므로 재계산에서 안 사라진다.
|
|
"pipe_length_m",
|
|
}
|
|
|
|
|
|
def _recompute_inputs() -> set[str]:
|
|
"""재계산에 되먹이는 인자 이름 — ① 갈래."""
|
|
return set(inspect.signature(compute_cross_design).parameters)
|
|
|
|
|
|
def test_사용자_값은_되먹임이거나_보존목록이다():
|
|
fed = _recompute_inputs()
|
|
kept = set(USER_TOUCHED_KEYS)
|
|
missing = [
|
|
name
|
|
for name in CrossSectionPatch.model_fields
|
|
if name not in _KEY_FIELDS
|
|
and name not in _COMPUTED_FIELDS
|
|
and name not in fed
|
|
and name not in kept
|
|
]
|
|
assert not missing, (
|
|
"재계산에서 사라질 사용자 값: "
|
|
+ ", ".join(missing)
|
|
+ " — 재계산 인자로 넣거나 USER_TOUCHED_KEYS 에 더할 것"
|
|
)
|
|
|
|
|
|
def test_보존목록에_계산값이_섞이지_않았다():
|
|
"""반대 방향 — 계산 값을 베껴 두면 옛 값이 새 계산을 덮는다."""
|
|
overlap = sorted(set(USER_TOUCHED_KEYS) & _COMPUTED_FIELDS)
|
|
assert not overlap, f"계산 값이 보존 목록에 있음: {overlap}"
|
|
|
|
|
|
def test_되먹임_갈래가_실제로_여덟_가지():
|
|
"""①이 줄면(인자에서 빠지면) 그 값은 조용히 기본값으로 되돌아간다 — 수를 못박는다."""
|
|
fed = _recompute_inputs()
|
|
expected = {
|
|
"ground_type",
|
|
"section_mode",
|
|
"ditch_side",
|
|
"ditch_type",
|
|
"paved",
|
|
"two_stage_slope",
|
|
"ditch_enabled",
|
|
"rock_boundary_offset_m",
|
|
}
|
|
assert expected <= fed, f"재계산 인자에서 빠진 것: {sorted(expected - fed)}"
|