feat(365-5): 초안 소단 고침 → 묶음 cross 입력

- 초안 cross 소단 = 지금 구조물(따라간 자리)의 소단 구간(bermAt · crossWithBerm) · 쪽 깊이 = 세션 bermdepth(측점 열쇠) — 노선 초안 동안 소단 고침도 카드에
- 저장 노선은 지금처럼 다시 셈 창구(세션 사본) · 노선 밖 고침은 그대로
- 시험 test_365(구간 안 소단 · 밖 없음 · 깊이 고침 1바퀴)

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 13:42:00 +09:00
co-authored by Claude Opus 5.5
parent 6aa42da575
commit 201ff9eb94
6 changed files with 118 additions and 15 deletions
@@ -418,6 +418,55 @@ async function run() {
.map((r) => ({ outcome: r.outcome, cross: "cross" in r.stages, sources: r.sources }));
pageMod.disposePagePipeline(Q);
page.clearDrafts(Q);
// ⑪ 초안 소단(365-5) — 소단 = 지금 구조물 구간(bermAt) · 쪽 깊이 = 세션 고침(측점 열쇠) → 묶음 cross
const B = "proj-365c";
window.localStorage.setItem("frd_current_project_id", B);
const span = { from: 30, to: 70 };
const bBridge = pageMod.routeDraftBridge(B, link(), {
stationIntervalM: job.interval,
bermAt: () => (c) =>
c >= span.from && c <= span.to
? { width_m: 1.5, interval_m: 5, slope_deg: 60, depth_m: 1 }
: null,
});
pageMod.pipelineEarthwork(B, { conversion: job.conversion });
const bPipe = pageMod.pagePipeline(B);
await settle(runs().length + 1);
bBridge.edited(draftOf(shift(n - 2, 0, 2)));
await settle(runs().length + 1);
await tick(20);
const bermRows = () =>
bPipe.output("ground").stations.map((st) => {
const d = bPipe.output("cross").byKey[st.key]?.detail ?? {};
return [
st.key,
r3(st.chainageM),
d.berm ? r3(d.berm.width_m) : null,
d.berm_depth_left_m ?? null,
];
});
const bermBefore = bermRows();
const inside = bermBefore.find((row) => row[1] > span.from + 1 && row[1] < span.to - 1);
page.writeState("bermdepth", { [inside[0]]: { left: 2.5 } }, B, 7);
mark = runs().length;
pageMod.pipelineCross(B);
await settle(mark + 1);
await tick(20);
const bermAfter = bermRows();
const berm = {
inSpan: bermBefore
.filter((row) => row[1] >= span.from && row[1] <= span.to)
.every((row) => row[2] === 1.5),
outSpan: bermBefore
.filter((row) => row[1] < span.from || row[1] > span.to)
.every((row) => row[2] === null),
depthBefore: inside[3],
depthAfter: bermAfter.find((row) => row[0] === inside[0])[3],
runs: runs().length - mark,
};
pageMod.disposePagePipeline(B);
page.clearDrafts(B);
return {
kept,
b05,
@@ -429,6 +478,7 @@ async function run() {
saved,
shiftRuns,
sameAfterReload,
berm,
};
}
@@ -155,6 +155,12 @@ def test_365_4_창구로_연_뒤_초안_새로고침과_같음(r):
assert s["rows"] > 5 and s["marked"] == 0 and s["same"]
def test_365_5_초안_소단_고침(r):
b = r["berm"]
assert b["inSpan"] and b["outSpan"] # 소단 = 지금 구조물 구간(초안 측점)
assert b["depthBefore"] is None and b["depthAfter"] == 2.5 and b["runs"] == 1
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")