fix(종횡단): 342-1 계획선 한 벌 · 남은 낡음 표시 · 흙 배분 열쇠
- 횡단 다시 셈이 화면이 쥔 선(측점 한 벌 · 관 지점 · 옮긴 꼭짓점)을 받음 — 종단도가 선을 맡기고 B06 진입 정합 · 3D [업데이트] 앞 다시 셈도 같은 선 · 낡음 판정도 그 선 기준(staleAgainstScreen) - 다시 셈 뒤에도 낡은 측점이 남으면 유토곡선은 그리고 그 측점만 표시 · 콘솔 경고 한 줄 · 흙 배분도 건너뛰지 않음(09-03 「새 값만 보여주기」 바꿈 · 사용자 확정 10-16) - 흙 배분: 실패한 열쇠 다시 보냄 · 받은 열쇠(누가토량 결과 전체)는 다시 안 물음 · 서버도 같은 열쇠 기억 · 묶음 실패는 500 - 옛 시험 셋 새 동작으로 맞춤 · 서버 열쇠 시험 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy
This commit is contained in:
@@ -15,6 +15,7 @@ const STUBS = {
|
||||
refreshCalls += 1;
|
||||
return [];
|
||||
},
|
||||
holdScreenAlignment: () => () => {}, // 화면 선 맡김(342-1) — 이 시험 몫 아님
|
||||
},
|
||||
};
|
||||
globalThis.window = { setTimeout: (fn) => (fn(), 1), clearTimeout: () => {} };
|
||||
@@ -63,6 +64,7 @@ const fordFresh = { ...fordStale, design: { ...fordStale.design, tilted: true }
|
||||
detail: () => detailOf([fordStale]),
|
||||
routeId: () => 1,
|
||||
edits: () => ({ station_offsets: {}, curve_radii: {} }),
|
||||
alignment: () => null,
|
||||
debounceMs: () => 0,
|
||||
onApplied: () => {},
|
||||
});
|
||||
|
||||
@@ -56,8 +56,9 @@ def test_draw_and_button_wiring() -> None:
|
||||
panel = _read("A00_Common", "design", "design_profile.ts")
|
||||
assert "onStaleDesigns: crossPreview.scheduleIfStale" in panel
|
||||
render = _read("B05_Profile", "B05_Profile_UI_Profile_Render.ts")
|
||||
assert "ctx.onStaleDesigns?.(stale);" in render
|
||||
assert 'pendingRecalc: stale !== ""' in render
|
||||
# 다시 셈 뒤에도 남은 낡음은 기다림 끝 — 곡선은 그리고 그 측점만 표시(342-1)
|
||||
assert 'const pending = ctx.onStaleDesigns?.(stale) ?? stale !== "";' in render
|
||||
assert "pendingRecalc: pending," in render
|
||||
corridor = _read("B05_Profile", "B05_Profile_UI_Corridor.ts")
|
||||
body = corridor.split("export async function refreshCorridor", 1)[1].split("\n}\n", 1)[0]
|
||||
assert "await refreshStaleDesigns({ projectId, routeId, detail })" in body
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""342-1 흙 배분 서버 — 같은 열쇠(누가토량 결과 + 계수 · 장비 경계)면 Node 를 다시 안 띄움.
|
||||
|
||||
묶음 실패는 500 — 성공 + 빈 배분으로 주면 화면이 그 열쇠를 다시 안 물었음.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
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 import B06_Section_Router_HaulPlan as router # noqa: E402
|
||||
|
||||
|
||||
def _patch(monkeypatch, outputs: list) -> list:
|
||||
calls: list = []
|
||||
|
||||
async def _none(_project_id):
|
||||
return {}
|
||||
|
||||
def _run(_bundle, _script, payload):
|
||||
calls.append(payload)
|
||||
return outputs.pop(0)
|
||||
|
||||
monkeypatch.setattr(router, "haul_inputs_for", _none)
|
||||
monkeypatch.setattr(router, "conversion_factors_for", _none)
|
||||
monkeypatch.setattr(router, "haul_limits_for", _none)
|
||||
monkeypatch.setattr(router, "_mass_haul_context", lambda *_: {"limits": []})
|
||||
monkeypatch.setattr(router, "run_bundle_json", _run)
|
||||
router._KEPT.clear()
|
||||
return calls
|
||||
|
||||
|
||||
def _post(result: dict):
|
||||
response = asyncio.run(router.compute_haul_plan(uuid4(), 7, {"result": result}))
|
||||
return response.status_code, json.loads(response.body)
|
||||
|
||||
|
||||
def test_같은_열쇠는_Node_한_번(monkeypatch):
|
||||
calls = _patch(monkeypatch, [{"haul_plan": {"tag": "a"}}, {"haul_plan": {"tag": "b"}}])
|
||||
a = {"points": [{"cumulative_volume_m3": 1.0}]}
|
||||
b = {"points": [{"cumulative_volume_m3": 2.0}]}
|
||||
assert _post(a) == (200, {"status": "success", "haul_plan": {"tag": "a"}})
|
||||
assert _post(a)[1]["haul_plan"] == {"tag": "a"}
|
||||
assert len(calls) == 1
|
||||
assert _post(b)[1]["haul_plan"] == {"tag": "b"}
|
||||
assert len(calls) == 2
|
||||
|
||||
|
||||
def test_묶음_실패는_500_기억_안_함(monkeypatch):
|
||||
calls = _patch(monkeypatch, [None, {"haul_plan": None}])
|
||||
a = {"points": [{"cumulative_volume_m3": 1.0}]}
|
||||
assert _post(a)[0] == 500
|
||||
assert _post(a) == (200, {"status": "success", "haul_plan": None})
|
||||
assert len(calls) == 2
|
||||
@@ -99,6 +99,7 @@ def test_source_shared_rule_and_b05_entry_recompute():
|
||||
assert "scheduleCrossPreview();" in B05_PANEL
|
||||
# B06: 같은 규칙 하나만 쓴다 — 옛 암 2단계 필드 누락 조건도 공용 유틸로 옮겼다
|
||||
# (2026-09-03 일원화: 조건이 갈리면 같은 데이터가 두 화면에서 다른 값이 된다).
|
||||
assert "hasStaleDesigns(sectionDetail)" in B06_PAGE
|
||||
# 판정은 종단도가 쥔 화면 선 기준(342-1 · 공용 규칙 hasStaleDesigns 를 그 선으로 부름)
|
||||
assert "staleAgainstScreen(sectionDetail, currentRouteId)" in B06_PAGE
|
||||
assert "two_stage_slope === undefined" in COMMON
|
||||
assert "two_stage_slope === undefined" not in B06_PAGE
|
||||
|
||||
Reference in New Issue
Block a user