From a622bcb9641ba4148050db932c7748a8a7ab6910 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 7 Sep 2026 11:40:03 +0900 Subject: [PATCH] =?UTF-8?q?fix(=EC=84=B8=EC=85=98):=20=EB=85=B8=EC=84=A0?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EB=95=8C=20=EC=98=9B=20=EB=85=B8?= =?UTF-8?q?=EC=84=A0=20=EC=B4=88=EC=95=88=C2=B7=EA=B2=B0=EA=B3=BC=EA=B0=80?= =?UTF-8?q?=20=EC=95=88=20=EC=A7=80=EC=9B=8C=EC=A7=80=EB=8D=98=20=EA=B2=83?= =?UTF-8?q?=20(=EA=B3=84=ED=9A=8D=EC=84=9C=200-7=20=EA=B3=81=EA=B0=80?= =?UTF-8?q?=EC=A7=80=20=E2=91=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 노선을 다시 계산하면 세션의 옛 노선치가 그대로 쌓였음. 용화(5601e828)에 145·161·169 세 노선치가 남아 있는 것을 실측함. 원인은 「안 지웠다」가 아니라 **못 지웠다** — 노선 변경 자리는 새 번호를 아직 모르니 `clearDrafts(projectId)` 로 부르는데, `stateKey` 가 노선 번호 없이는 `null` 을 내어 route 범위 키가 한 개도 안 나갔음. 부르는 쪽 주석은 「남기지 않는다」였고 실제로는 다 남았음. `clearState` 한 곳에서, 노선 범위인데 노선 번호가 없으면 `aislo:<통>:<이름>:<프로젝트>:` 로 시작하는 키를 모두 쓸어 내게 함. `clearDrafts` 와 `clearResults` 가 함께 나음. 노선 번호를 주면 종전대로 그 한 벌만 나감. 안전 확인 — 옛 노선치를 읽는 자리 없음(`readState` 호출 8곳 전부 전역·프로젝트 범위). 노선 복원도 새 route id 를 발급하므로 옛 키는 다시 안 불림. 자체검증 — `tmp/tests/test_page_state_route_sweep.py` 3건 신설. 옛 코드로 같은 시험을 돌리면 세 벌이 그대로 남아 깨지는 것까지 확인(헛도는 시험 아님). 전체 511 passed · 18 skipped. Co-Authored-By: Claude Opus 5 (1M context) --- A00_Common/b_page_state.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/A00_Common/b_page_state.ts b/A00_Common/b_page_state.ts index 57a6c426..7c6e06ed 100644 --- a/A00_Common/b_page_state.ts +++ b/A00_Common/b_page_state.ts @@ -278,6 +278,27 @@ export function clearState( projectId?: string | null, routeId?: number | string | null, ): void { + const entry = entryOf(name); + // 노선 범위인데 노선을 안 받았으면 그 프로젝트의 **모든 노선** 것을 쓸어 낸다. + // 노선을 다시 계산하면 번호가 새로 매겨져 부르는 쪽은 옛 번호를 모르고(`clearDrafts(projectId)`), + // 그러면 `stateKey` 가 null 을 내어 **아무것도 안 지워졌다** — 용화(5601e828)에 145·161·169 + // 세 노선치가 그대로 쌓여 있었다(2026-09-07 실측). 옛 번호는 다시 불리지 않는다 — + // 노선 복원도 **새 route id** 를 발급하므로 그 키를 읽는 자리가 없다. + if (entry?.scope === "route" && projectId && (routeId === null || routeId === undefined)) { + const suffix = entry.version && entry.version > 1 ? `-v${entry.version}` : ""; + const prefix = `aislo:${entry.bucket}:${name}${suffix}:${projectId}:`; + try { + const doomed: string[] = []; + for (let i = 0; i < window.sessionStorage.length; i += 1) { + const key = window.sessionStorage.key(i); + if (key && key.startsWith(prefix)) doomed.push(key); + } + doomed.forEach((key) => writeRaw(key, null)); + } catch { + /* 무시 — 저장소가 막힌 브라우저 */ + } + return; + } writeStateRaw(name, null, projectId, routeId); } @@ -290,7 +311,8 @@ export function namesInBucket(bucket: StateBucket): StateName[] { /** * 초안을 통째로 비운다 — **[저장]·[확정]·[초기화]·노선 변경 뒤 여기 한 곳**만 부른다 - * (예전에는 파일마다 따로 지웠다). 노선을 모르면 노선 범위 초안은 남는다. + * (예전에는 파일마다 따로 지웠다). 노선을 안 주면 그 프로젝트의 **모든 노선** 초안이 나간다 + * (노선 변경 자리가 그렇게 부른다 — 새 번호를 아직 모르기 때문). */ export function clearDrafts(projectId: string | null, routeId?: number | string | null): void { namesInBucket("draft").forEach((name) => clearState(name, projectId, routeId));