fix(평면): 새 구조물 측점 놓는 즉시 평면 비탈 끝 · 면적 = 저장 뒤 — 튐 없음 · 옮김 계획고 (PLAN 583-1 · 요구 441)

- 원인: 구조물을 새 측점에 놓으면 측점 갈아끼움(비동기)이 끝나기 전 묶음 cross 단계가 옛 상세를 봐 엔진 길로 빠짐 — 구조물 얹기 없는 한 차례(벽 측점 비탈 끝 35 · 55 m · 기존 벽 측점 18.96 m)가 약 80 ms 평면에 튐 · 다음 차례(0.25 s)에 저장 값
- design_shared savedCross = 도는 갈아끼움(swapInFlight)을 기다려 그 상세로 다시 셈 · 상세 가게 swapInFlight 새로
- 종단도 listed() 옛 측점 = 저장 정본 상세 — 갈아끼운 상세로 셈해 옮긴 구조물 옛 측점 꼭짓점이 안 옮겨져 계획고 최대 2.4 cm 갈리던 것(옮김 면적 차 0.17 → 0.0175 ㎡)
- 시험: test_272_swap_keeps_canon 에 도는 갈아끼움 기다림 · test_473_lane_ready 글 대조를 새 호출 꼴로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 15:05:16 +09:00
co-authored by Claude Opus 5.5
parent c4b37023c7
commit f4a7b183b0
7 changed files with 60 additions and 8 deletions
+25 -1
View File
@@ -258,13 +258,37 @@ export async function swapSectionStations(
projectId: string,
routeId: number,
stations: ReadonlyArray<PipelineStation>,
): Promise<{ detail: SectionDetailResponse; moves: Map<string, string> } | null> {
): Promise<SwapResult> {
const key = keyOf(projectId, routeId);
const current = cache.get(key);
if (!current || !stations.length) return null;
const interval = stationIntervalOf(current);
const oldKeys = registeredKeys(projectId, routeId, current.cross_sections, interval);
if (sameStationList(current.cross_sections, oldKeys, stations)) return null;
const run = swapDetail(projectId, routeId, current, stations, oldKeys, interval);
swapping.set(key, run);
const clear = () => void (swapping.get(key) === run && swapping.delete(key));
run.then(clear, clear);
return run;
}
type SwapResult = { detail: SectionDetailResponse; moves: Map<string, string> } | null;
/** 도는 갈아끼움(노선마다) — 묶음 cross 단계가 갈아끼운 상세로 셈하게 기다림(583). */
const swapping = new Map<string, Promise<SwapResult>>();
/** 이 노선에 도는 측점 갈아끼움 — 없으면 null(583). */
export const swapInFlight = (projectId: string, routeId: number): Promise<SwapResult> | null =>
swapping.get(keyOf(projectId, routeId)) ?? null;
async function swapDetail(
projectId: string,
routeId: number,
current: SectionDetailResponse,
stations: ReadonlyArray<PipelineStation>,
oldKeys: ReturnType<typeof registeredKeys>,
interval: number,
): Promise<SwapResult> {
const key = keyOf(projectId, routeId);
// 계산 자리 fixed_browser = server 면 잠잠 뒤 서버 대조만(511-A)
const swap = calcChecked("fixed_browser", "stations.swap", swapCrossSections, [
current,