fix(B05·B06 저장): [저장] 본문 보기 무관 — B05 만 연 캐시 패치 길 지움 (386-6)

- [저장]도 [확정]처럼 횡단 보기를 숨긴 채라도 세움 → 횡단 본문 = 횡단 보기 몫 한 벌
- 종단 보기 몫 cross(saveCachedCrossPatches) 지움 · 횡단 보기를 못 세우면 반쪽 저장 대신 실패 알림
- 시험 test_384_6

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
This commit is contained in:
2026-10-17 18:08:26 +09:00
co-authored by Claude Opus 5.5
parent 80cfc187c6
commit 82e3ded08b
3 changed files with 55 additions and 19 deletions
+7 -8
View File
@@ -342,12 +342,14 @@ async function routeChanged(shared: DesignPageShared): Promise<boolean> {
*/
export async function saveSharedDesign(shared: DesignPageShared, confirm: boolean): Promise<void> {
if (await routeChanged(shared)) return;
// [확정]은 횡단 본문(표준 횡단면 · 전 측점 면적)이 있어야 한다 — 숨긴 채라도 횡단 보기를 세운다.
if (confirm) await shared.ensureView("cross");
// [저장] · [확정] 본문 = 횡단 보기 한 벌(표준 횡단면 · 전 측점 면적 · 카드 고침) — 들어온 화면 무관 · 숨긴 채라도
// 세움(B05 만 연 캐시 패치 길 지움 · 386-6)
await shared.ensureView("cross");
const profileSave = shared.bindings.profile?.save;
const crossSave = shared.bindings.cross?.save;
if (confirm && !crossSave?.cross) {
showToast(L("B06_Profile_Confirm_Failed"), "error");
const crossBody = crossSave?.cross;
if (!crossBody) {
showToast(L(confirm ? "B06_Profile_Confirm_Failed" : "B06_Profile_Save_Failed"), "error");
return;
}
const profile = shared.profile;
@@ -371,10 +373,7 @@ export async function saveSharedDesign(shared: DesignPageShared, confirm: boolea
...profileSave?.steps,
...crossSave?.steps,
},
cross: async (isConfirm) => {
if (crossSave?.cross) await crossSave.cross(isConfirm);
else await profileSave?.cross?.(isConfirm);
},
cross: crossBody,
done: async (isConfirm) => {
markDesignClean(shared.projectId); // 떠남 확인 — 지금 초안이 저장분(346-4)
if (isConfirm) {
+2 -11
View File
@@ -9,10 +9,7 @@
import { confirmRoute, type RouteLatestResponse } from "./B05_Profile_Api_Fetch";
import type { DesignViewSave } from "../A00_Common/design/design_shared";
import {
invalidateSectionDetail,
saveCachedCrossPatches,
} from "../B06_Section/B06_Section_Section_Store";
import { invalidateSectionDetail } from "../B06_Section/B06_Section_Section_Store";
import type { createRoutePanel } from "./B05_Profile_UI_Panel";
import type { createRouteProfilePanel } from "./B05_Profile_UI_Profile_Panel";
import type { createStructuresBridge } from "./B05_Profile_UI_Page_Structures";
@@ -75,13 +72,7 @@ export function profileSaveParts(ctx: PageActionContext): DesignViewSave {
);
},
},
// 횡단 보기를 세운 적 없이 [저장]하면 — 캐시에 얹힌 횡단 수정분을 함께 남긴다. 안 보내면
// 바로 아래 캐시 비우기에서 사라진다. 계획선 저장 **뒤에** 보내야 사용자 수정 1세트가
// 최종본으로 얹힌다(2026-08-24 사용자 지적). 횡단 보기가 서 있으면 그쪽 본문이 나간다.
cross: async () => {
const routeId = ctx.latest()?.route?.id;
if (routeId != null) await saveCachedCrossPatches(projectId, routeId);
},
// 횡단 본문은 늘 횡단 보기 몫 — [저장]이 숨긴 채라도 세움(386-6 · 옛 캐시 패치 길 지움)
done: async () => {
// 서버가 종단 정본의 계획선을 다시 썼다 — 공유 캐시를 비워 횡단 보기가 옛 계획선을 못 보게 한다.
invalidateSectionDetail(projectId);
@@ -0,0 +1,46 @@
"""PLAN 386-6 sub7 — [저장] 본문 보기 무관(B05 만 연 길 지움).
못박는 것
- [저장] · [확정] 둘 다 횡단 보기를 (숨긴 채라도) 세움 → 횡단 본문 = 횡단 보기 몫 한 벌(`crossSaveParts`).
- 종단 보기 몫엔 횡단 본문이 없음 — 옛 「횡단 보기를 세운 적 없이 [저장]」 캐시 패치 길(saveCachedCrossPatches) 지움.
- 횡단 보기를 못 세우면 반쪽 저장 대신 실패 알림.
화면(B05 만 연 [저장] 본문 = B06 다녀온 본문)은 PLAN 386-6 검증 줄.
"""
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def _read(rel: str) -> str:
return (ROOT / rel).read_text(encoding="utf-8")
def _save_body() -> str:
shared = _read("A00_Common/design/design_shared.ts")
start = shared.index("export async function saveSharedDesign")
return shared[start : shared.index("\n}\n", start)]
def test_저장도_횡단_보기를_세움():
body = _save_body()
assert 'await shared.ensureView("cross");' in body
assert 'if (confirm) await shared.ensureView("cross")' not in body
assert "cross: crossBody," in body
assert "profileSave?.cross" not in body
def test_못_세우면_실패_알림():
body = _save_body()
assert "if (!crossBody) {" in body
assert '"B06_Profile_Save_Failed"' in body and '"B06_Profile_Confirm_Failed"' in body
def test_종단_보기_몫엔_횡단_본문_없음():
actions = _read("B05_Profile/B05_Profile_UI_Page_Actions.ts")
start = actions.index("export function profileSaveParts(")
parts = actions[start:]
assert "saveCachedCrossPatches" not in actions
assert "\n cross: " not in parts