fix(B06): 횡단 조정 줄 자리 — 숨은 명세 폼 칸은 뺌 (PLAN 52-2b)

- slotUsable = fieldset 안 · 숨은 조상 없음 — 앞 시설 명세 폼이 숨은 채 남아도 그 칸으로 안 옮김
- 화면 시나리오 52-2b(배관 → BOX → 세월교 → 배관 · 유입 · 유출) — 줄이 보이는 명세 폼 inlet · outlet 칸에 섬 · 옛 판정이 숨은 칸을 쓸 수 있음으로 본 건수 14

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
2026-10-06 00:03:22 +09:00
co-authored by Claude Opus 5.5
parent 6926550251
commit 220a7ddc59
2 changed files with 85 additions and 4 deletions
+2 -4
View File
@@ -57,11 +57,9 @@ const SIDE_ROWS = [
".b06-structure-panel__struct--wall-height",
].join(", ");
/** 이식 자리가 지금 화면에 서 있는지 — 숨겨진 그룹(다른 시설)이면 옮기지 않는다. */
/** 이식 자리가 지금 화면에 서 있는지 — 그 위 어느 줄이든 숨었으면(다른 시설 명세 폼 등) 옮기지 않는다. */
function slotUsable(target: HTMLElement | undefined): target is HTMLElement {
if (!target) return false;
const group = target.closest("fieldset");
return !!group && !group.hidden;
return !!target?.closest("fieldset") && !target.closest("[hidden]");
}
/** 배관이면 유입구·유출구 칸, 독립 기슭막이면 좌·우 칸, 세월교면 날개벽 칸 —
@@ -0,0 +1,83 @@
/* 52-2b — B06 횡단 조정 줄(단 수 · 옵션 · 읽기)이 서는 자리 = 지금 보이는 명세 폼의 유입 · 유출 칸
* 시작 화면: B06 횡단설계(#/b06-section) · 검증 프로젝트(sub3_검증) · 목록에 「배관 1」 「BOX암거」 「세월교 1」
* 부르는 법: orca eval --expression "$(cat 이 파일)" — 쓰는 것 없음(가짜 조정 사본을 세웠다 내림)
* 차례: 배관 1 → BOX암거 → 세월교 1 → 배관 1 (앞 시설 명세 폼이 숨은 채 남는 경우까지)
* 기대 수치: 모든 단계 · 양쪽 — 줄이 숨은 조상 없이 보이는 자리 · 그 시설 명세 폼의 inlet/outlet 칸 ·
* 숨은 명세 칸을 「쓸 수 있음」으로 보던 옛 판정 건수(oldWouldPickHidden)는 참고값
*/
(async () => {
const w = (ms) => new Promise((r) => setTimeout(r, ms));
const until = async (fn, ms = 20000) => {
for (let t = 0; t < ms; t += 200) {
if (fn()) return true;
await w(200);
}
return false;
};
const modUrl = (part) =>
performance
.getEntriesByType("resource")
.map((e) => e.name)
.filter((n) => n.includes(part))
.pop();
const dock = await import(modUrl("/B06_Section/B06_Section_UI_Adjust_Dock.ts"));
const visibleSpec = () =>
[...document.querySelectorAll(".b05-structure__spec")].find((n) => !n.closest("[hidden]"));
const firstContainer = () =>
visibleSpec()?.querySelector("[data-spec-container]")?.dataset.specContainer;
const pick = async (name, head) => {
await until(() => document.querySelectorAll(".b05-route__irregular-list li").length > 0);
const li = [...document.querySelectorAll(".b05-route__irregular-list li")].find(
(l) => l.offsetParent !== null && name.test(l.textContent.trim()),
);
(li.querySelector("button") ?? li).click();
await w(800);
if (firstContainer() !== head) (li.querySelector("button") ?? li).click();
return until(() => firstContainer() === head, 8000);
};
// 옛 판정 — 바로 위 fieldset 만 봄
const oldUsable = (t) => !!t.closest("fieldset") && !t.closest("fieldset").hidden;
const fakePanel = (side) => {
const panel = document.createElement("div");
panel.dataset.side = side;
panel.dataset.panelTitle = "52-2b 시험";
const row = document.createElement("div");
row.className = "b06-structure-panel__struct--tier";
row.dataset.m522b = side;
panel.append(row);
return { panel, row };
};
const steps = [
[/배관 1$/, "pipe"],
[/BOX암거$/, "body"],
[/세월교 1$/, "ford"],
[/배관 1$/, "pipe"],
];
const out = { steps: [], oldWouldPickHidden: 0 };
for (const [name, head] of steps) {
const step = { name: String(name), shown: await pick(name, head) };
for (const side of ["inlet", "outlet"]) {
// 숨은 명세 폼의 같은 칸 — 옛 판정이 「쓸 수 있음」으로 봤는지
for (const s of document.querySelectorAll(
`[data-spec-container="${side}"] .b05-structure__adjust-slot`,
))
if (s.closest("[hidden]") && oldUsable(s)) out.oldWouldPickHidden++;
const { panel, row } = fakePanel(side);
dock.adoptAdjustPanel(panel);
step[side] = {
visible: !row.closest("[hidden]"),
container: row.closest("[data-spec-container]")?.dataset.specContainer ?? null,
inShownForm: !!visibleSpec()?.contains(row),
};
dock.releaseAdjustPanel(panel);
}
out.steps.push(step);
}
out.pass = out.steps.every(
(s) =>
s.shown &&
["inlet", "outlet"].every((k) => s[k].visible && s[k].inShownForm && s[k].container === k),
);
return JSON.stringify(out);
})();