diff --git a/docs/plans/2026-06-01-skeleton-roofline-edit-design.md b/docs/plans/2026-06-01-skeleton-roofline-edit-design.md
index 82414cae..9e97a2d2 100644
--- a/docs/plans/2026-06-01-skeleton-roofline-edit-design.md
+++ b/docs/plans/2026-06-01-skeleton-roofline-edit-design.md
@@ -1,7 +1,7 @@
# 용마루(skeleton) 경로 외곽 지붕선 편집 기능 — 설계
- 작성일: 2026-06-01
-- 대상 브랜치: `feature/redo-undo`
+- 대상 브랜치: `feature/roofline-edit`
- 관련 파일: `src/util/skeleton-utils.js`, `src/util/qpolygon-utils.js`, `src/hooks/useContextMenu.js`
## 1. 배경 / 문제
@@ -66,13 +66,13 @@ splitRoofLinesToInnerLines(roof, canvas, textMode) → QLine[]
- **`drawRoofByAttribute` 교체**: 인라인 블록을 함수 호출로 교체. 순수 추출이므로 변별 경로 동작 불변.
### 3-2. skeleton 경로 변경
-- `createInnerLinesFromSkeleton` 의 `isOuterEdge` 숨김 처리(`:1636-1643` 의 `visible:false`, `:1624` 의 `selectable:false`) 제거.
-- 내부선(용마루/추녀) 생성 완료 후 `splitRoofLinesToInnerLines(roof, canvas, textMode)` 호출 → 외곽 지붕선이 변별 경로와 동일한 형태로 `roof.innerLines` 에 합류.
+- `createInnerLinesFromSkeleton` 의 `isOuterEdge`(SK eaves) 숨김 처리는 **유지**. (§9 정정: SK eaves 라인은 baseLine 기준이라, 노출하면 처마변 split 결과와 offset 만큼 어긋나 이중 표시됨. 처마 외곽선은 아래 split 으로 별도 innerLine 화.)
+- **추녀 연장(`drawBaselineToRooflineHelpers`, `:1285`) 완료 후** `splitRoofLinesToInnerLines(roof, canvas, textMode)` 호출 → 추녀 종점이 처마변 위에 있는 상태라 split 정합 성립, 외곽 지붕선이 변별 경로와 동일한 형태로 `roof.innerLines` 에 합류. (⚠️ 연장 **전**에 호출하면 종점이 baseLine 위라 분할점을 못 잡음 — §9 참조)
- `drawHelpLine` 재호출 시마다 자동 재실행되어 편집 후 재그리기에도 외곽 지붕선 유지.
## 4. 리스크 & 구현 전 검증
-1. **SK 추녀 끝점 ↔ `roof.lines` 정합성**: split 은 "innerLine 끝점이 `roof.lines` 위에 있다"(`isPointOnLineNew`, tol 0.1)를 전제로 한다. SK 가 만든 hip 끝점이 처마 외곽선 위에 실제로 떨어지는지 **실측 확인 필요**. 안 맞으면 split 이 헛돌아 외곽선이 통째로 roofLine 1개로만 그려진다. → 구현 첫 단계에서 검증.
+1. **SK 추녀 끝점 ↔ `roof.lines` 정합성** — ✅ **검증 완료 (2026-06-12, §9 참조)**: **연장 후 정합 OK**. SK 골조는 `wall.baseLines` 기준이라 추녀 끝점이 처음엔 baseLine 코너에 있으나(연장 전 `onRoof=false`), `drawBaselineToRooflineHelpers`(`:1285`)가 추녀를 처마변까지 **연장**해 종점을 처마변 위로 옮긴다(연장 후 4코너 전부 `diffRoof=0`, `onRoof=true`). → **split 을 연장 다음에 호출하면 정합 자동 성립**. (초기 측정이 연장 전에 찍혀 "구조적 불일치"로 오판했음 — §9-0 참조)
2. **순환 import**: `qpolygon-utils ↔ skeleton-utils` 상호 import 여부 점검. 순환이면 split 함수를 제3의 모듈(예: canvas-util)로 추출하거나 의존성 정리.
3. **기존 `isOuterEdge` roofLine 제거 영향**: 숨긴 라인을 참조하는 곳(치수 계산, 플랜 저장/복원 등)이 있는지 확인 후 제거.
@@ -159,3 +159,41 @@ opts.degreeOf?: (parentLine) => number // 부모 외곽변 → 경사각(도).
### 8-5. 리스크
- **분할점 부재**: 한쪽흐름은 내부 보조선이 없어 외곽변이 1:1 통짜 라인으로 그려진다 → 부모 변 type 매칭이 단순(분할 시에도 조각은 부모 type 상속). split 의 끝점 정합성(`isPointOnLineNew`, tol 0.1) 자체는 분할점이 없으면 무의미하므로 `else` 통짜 경로(`:5493`)로 안전하게 떨어진다.
- **`isGable` 판정원**: `drawShedRoof` 의 `gables` 분류(`:1653`)와 동일 기준(`attributes.type === GABLE`)을 써야 보정 대상이 일치.
+
+---
+
+## 9. SK 끝점 ↔ 처마변 정합 — 실측 결과 (2026-06-12, 측정 시점 정정)
+
+§4 리스크1 을 임시 계측(`skeleton-utils.js` 의 `logSkRoofLineAlignment`)으로 추녀 연장 **전/후** 2단계 실측한 결과.
+
+### 9-0. ⚠️ 측정 시점 정정 (중요)
+1차 측정은 `createInnerLinesFromSkeleton` **직후**(`:1279`, 추녀 연장 전)에 찍혀, 추녀 종점이 baseLine 코너에 있는 상태(`onRoof=false`, `perpRoof=offset`)만 보고 **"구조적 불일치 → 투영 보정 필요"로 오판**했다. 실제로는 그 직후 `drawBaselineToRooflineHelpers`(`:1285`)가 추녀를 처마변까지 연장한다. 연장 **후**(`afterExt`) 측정에서 정합이 성립함을 확인 → 아래는 정정된 결론. **(투영 보정·SK 입력 교체·연장 보정 설계는 모두 폐기. 불필요했음.)**
+
+### 9-1. 실측 결과 (용마루 우진각, 변별 offset 50px)
+처마변 x∈[357.5,1147.6]·y∈[115.2,636.7] vs baseLine x∈[407.5,1097.6]·y∈[165.2,586.7] (전 변 50px 안쪽).
+
+| 추녀 끝점 | beforeExt (`:1279`, 연장 전) | afterExt (`:1285`, 연장 후) |
+|---|---|---|
+| **바깥** 끝점(4코너) | baseLine 코너 — `onRoof=false`, `diffRoof=22.4`, `onBase=true` | **처마 코너로 연장 — `onRoof=true`, `diffRoof=0`** |
+| 안쪽·용마루(내부점) | `onRoof=false` (260.7) | `onRoof=false` (260.7) — 내부점이라 정상 |
+
+예: 추녀 바깥 끝 `(407.5,165.2)`(baseLine) → `(357.5,115.2)`(처마 코너) 로 연장. 4코너 전부 `diffRoof=0`, `onRoof=true`.
+
+### 9-2. 추녀 연장 메커니즘 (이미 구현됨)
+`drawBaselineToRooflineHelpers`(`:685`, 플래그 `DRAW_BASELINE_TO_ROOFLINE_HELPER=true`, `:25`):
+- `hipLines` 추출(`:734`) → baseLine 코너에 닿는 hip 만(`CORNER_EPS`, `:773`) → 추녀 진행 방향으로 ray cast(`rayHitSegment`, `:693`) → 처마변 교점까지 hip 좌표를 **연장**(`:861-865`).
+- `actualSize` 비율 보정(`:871`) + `__extended`/`attributes.extended` 플래그로 save/load 영속(`:879`).
+- 즉 "추녀는 roof.lines 까지 연결되는 선" 이 이미 코드에 있다. SK 골조 자체는 baseLine 기준(동기화 유지) + 추녀 종점만 처마변까지 연장.
+
+### 9-3. 결론 — split 은 추녀 연장 **다음**에 호출
+- 추녀 종점은 연장 후 처마변 위(`onRoof=true`, `diffRoof=0`)에 정확히 앉으므로, **split/외곽선 innerLine화의 정합은 깨지지 않는다.**
+- **유일한 요건**: `splitRoofLinesToInnerLines` 호출을 `createInnerLinesFromSkeleton` 직후가 아니라 **`drawBaselineToRooflineHelpers`(`:1285`) 다음에** 둘 것. §3-2 가 호출 위치를 연장 전으로 잡은 것이 유일한 함정이었음.
+- **단순 우진각**: 추녀가 처마 **코너**(변 끝점)에 닿으므로 split 분할점 없음 → 처마 4변 통짜 innerLine(정상).
+- **복합 형상**(L자·凸자): 추녀가 처마변 **중간**에 닿으면 그 점에서 분할. 연장 후 종점이 처마변 위이므로 분할점으로 정상 인식.
+
+### 9-4. 검증 기준 (구현 시)
+- split 을 연장 후 호출 → 처마 4변이 innerLine 으로 등록, select+우클릭 편집 가능.
+- 복합 형상: 처마변 중간 접점에서 분할, 각 조각 독립 편집.
+- offset=0 / offset≠0 양쪽 동작.
+- 마루이동/벽이동 후 재그리기에도 유지(연장은 `__extended`/`attributes.extended` 로 영속).
+- **임시 계측(`logSkRoofLineAlignment` 정의 + 호출부 3곳 `:1279`/`:1285`/`:1413`) 제거** 후 커밋.
diff --git a/src/components/common/ErrorBoundary.jsx b/src/components/common/ErrorBoundary.jsx
index 677a67fa..dad497a0 100644
--- a/src/components/common/ErrorBoundary.jsx
+++ b/src/components/common/ErrorBoundary.jsx
@@ -40,7 +40,7 @@ class ErrorBoundary extends React.Component {