From efd1a2dfed7e9df98e76ae2848138682b087db4a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 17 Oct 2026 13:20:56 +0900 Subject: [PATCH] =?UTF-8?q?fix(365-4):=20=EC=B4=88=EC=95=88=20cross=20?= =?UTF-8?q?=EC=97=94=EC=A7=84=EC=9D=B4=20=EB=8B=A4=EC=8B=9C=20=EC=85=88=20?= =?UTF-8?q?=EC=B0=BD=EA=B5=AC=20=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=93=B0=EC=A7=80=20=EC=95=8A=EC=9D=8C=20=E2=80=94?= =?UTF-8?q?=20=EB=81=88=20=EC=B4=88=EC=95=88=20=3D=20=EC=83=88=EB=A1=9C?= =?UTF-8?q?=EA=B3=A0=EC=B9=A8=20=EC=B4=88=EC=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 화면 검증 흠: 저장 노선(창구 출력)으로 연 뒤 끈 초안 카드가 새로고침(초안 둔 채 B06 열기) 카드와 0.01 ㎡ · 측점 하나 다름 — 엔진이 창구 출력을 앞 결과로 재사용 - 창구 출력은 엔진 재사용에서 뺌(savedOut) · 시험 test_365 창구로 연 뒤 초안 = 다시 연 초안 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ --- A00_Common/design/design_pipeline_page.ts | 11 ++++- resources/tester/helper_365_page_pipeline.cjs | 46 +++++++++++++++++-- resources/tester/test_365_page_pipeline.py | 5 ++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/A00_Common/design/design_pipeline_page.ts b/A00_Common/design/design_pipeline_page.ts index 895ecb64e..69f6a0bcc 100644 --- a/A00_Common/design/design_pipeline_page.ts +++ b/A00_Common/design/design_pipeline_page.ts @@ -337,6 +337,8 @@ function createPagePipeline( saved, ) : list; + /** 다시 셈 창구가 낸 cross 출력(365-4) — 엔진 재사용에서 뺌. */ + const savedOut = new WeakSet(); const pipe = createDesignPipeline({ stages: { route: createRouteStage({ @@ -363,9 +365,11 @@ function createPagePipeline( // 단면 유형 기본값 = 새 지형 상단측(서버 노선 저장 규칙) — 단계 본문은 그대로 부름 · 저장 노선 = 다시 셈 // 창구 한 벌(카드 · 유토곡선이 보는 상세 설계 · 365-4) cross: (ctx) => { + // 엔진은 다시 셈 창구가 낸 앞 출력을 이어 쓰지 않음 — 초안 = 새로고침과 같은 값(365-4) const engine = () => crossStage.stage({ ...ctx, + prev: ctx.prev && savedOut.has(ctx.prev) ? null : ctx.prev, inputs: { ...ctx.inputs, cross: crossWithUphill( @@ -379,7 +383,12 @@ function createPagePipeline( !ctx.inputs.route && detail && typeof routeId === "number" ? options.savedCross?.(detail, routeId, ctx.out.ground?.stations ?? []) : null; - return saved ? saved.then((out) => out ?? engine()) : engine(); + if (!saved) return engine(); + return saved.then((out) => { + if (!out) return engine(); + savedOut.add(out); + return out; + }); }, footprint: footprintStage, masshaul: createMassHaulStage(() => earthwork), diff --git a/resources/tester/helper_365_page_pipeline.cjs b/resources/tester/helper_365_page_pipeline.cjs index 8ee5eecee..eb9f29bfa 100644 --- a/resources/tester/helper_365_page_pipeline.cjs +++ b/resources/tester/helper_365_page_pipeline.cjs @@ -341,16 +341,26 @@ async function run() { const Q = "proj-365b"; window.localStorage.setItem("frd_current_project_id", Q); let refreshCalls = 0; - const qBridge = pageMod.routeDraftBridge(Q, link(), { + let qBridge = pageMod.routeDraftBridge(Q, link(), { stationIntervalM: job.interval, savedCross: async (detail, _routeId, stations) => { if (!detailMod.detailCross(detail, stations)) return null; refreshCalls += 1; + // 창구가 고친 설계 흉내 — 계획고 = 지금 종단(엔진이 「같은 자리」로 볼 값) · 면적 표시 999 + const profile = pageMod.pagePipeline(Q).output("profile"); + detail.cross_sections.forEach((section) => { + section.design = { + ...section.design, + design_elevation_m: alignment.planElevationAt(profile, section.chainage_m), + cut_area_m2: 999, + fill_area_m2: 999, + }; + }); return detailMod.detailCross(detail, stations); }, }); pageMod.pipelineEarthwork(Q, { conversion: job.conversion }); - const qPipe = pageMod.pagePipeline(Q); + let qPipe = pageMod.pagePipeline(Q); await settle(runs().length + 1); await tick(20); const openCalls = refreshCalls; @@ -369,6 +379,25 @@ async function run() { qPipe.output("cross").byKey[firstKey]?.detail === job.detail.cross_sections[0].design, }; + // ⑩ 다시 셈 창구로 연 뒤 끈 초안 = 새로고침(초안 둔 채 다시 열기) 초안 — 엔진이 창구 출력을 안 이어 씀 + mark = runs().length; + qBridge.edited(draftOf(shift(n - 2, 0, 2))); + await settle(mark + 1); + await tick(job.haulDelayMs + 30); + const dragRows = shownRows(Q); + pageMod.disposePagePipeline(Q); + qBridge = pageMod.routeDraftBridge(Q, link(), { stationIntervalM: job.interval }); + pageMod.pipelineEarthwork(Q, { conversion: job.conversion }); + qPipe = pageMod.pagePipeline(Q); + await settle(runs().length + 1); + await tick(job.haulDelayMs + 30); + const reopenRows = shownRows(Q); + const sameAfterReload = { + rows: dragRows?.length ?? 0, + same: JSON.stringify(dragRows) === JSON.stringify(reopenRows), + marked: (dragRows ?? []).filter((row) => row[2] === 999).length, + }; + // ⑧ 중심점 좌우(356-3 꼴) — 노선 한 걸음 → 새 종단이 오면 계획고 맞춤 · 첫 차례는 cross 전에 밀림(무거운 셈 한 번) let graded = false; const stopShift = qPipe.subscribe((event) => { @@ -389,7 +418,18 @@ async function run() { .map((r) => ({ outcome: r.outcome, cross: "cross" in r.stages, sources: r.sources })); pageMod.disposePagePipeline(Q); page.clearDrafts(Q); - return { kept, b05, b06, dropped, edit, loop, pane: paneCheck, saved, shiftRuns }; + return { + kept, + b05, + b06, + dropped, + edit, + loop, + pane: paneCheck, + saved, + shiftRuns, + sameAfterReload, + }; } run() diff --git a/resources/tester/test_365_page_pipeline.py b/resources/tester/test_365_page_pipeline.py index a77d6797b..fbc1c2841 100644 --- a/resources/tester/test_365_page_pipeline.py +++ b/resources/tester/test_365_page_pipeline.py @@ -150,6 +150,11 @@ def test_365_4_중심점_좌우_횡단_한_번(r): assert runs[1]["sources"] == ["route", "grade"] # 밀린 노선 범위 + 계획고 = 한 차례 +def test_365_4_창구로_연_뒤_초안_새로고침과_같음(r): + s = r["sameAfterReload"] + assert s["rows"] > 5 and s["marked"] == 0 and s["same"] + + def test_365_4_다시_그림_한_번(): swap = (ROOT / "B06_Section/B06_Section_UI_Page_Station_Swap.ts").read_text(encoding="utf-8") view = (ROOT / "A00_Common/design/design_view_cross.ts").read_text(encoding="utf-8")