From 790ebba78f5d3ccf13bad23715e62638762a2e6f Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 14 Aug 2026 01:17:40 +0900 Subject: [PATCH] =?UTF-8?q?docs(research):=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=97=90=EB=9F=AC=20=EA=B2=A9=EB=A6=AC=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=20Fallback=20=EB=B0=B1=EB=A1=9C=EA=B7=B8=20=EC=8B=A0?= =?UTF-8?q?=EC=84=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 컴포넌트 함수를 감싸 에러 시 플레이스홀더를 그려주는 pcall/xpcall 래퍼 아이디어를 백로그로 문서화(research/component-fallback-plan.md), README/ question.md/CLAUDE.md 인덱스 반영. 후속 code-review로 발견된 결함(코드 스팬이 줄바꿈에 걸쳐 깨진 곳 4군데, 워크트리가 계획 문서 없이 시작되는 원인을 "git 미추적"으로 오진단했던 세션 로그 서술)도 같이 정정. Co-Authored-By: Claude Sonnet 5 --- .claude/README.md | 1 + .claude/question.md | 6 + .claude/research/component-fallback-plan.md | 127 ++++++++++++++++++ .../2026-08-14-01-component-fallback-plan.md | 80 +++++++++++ CLAUDE.md | 29 +++- 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 .claude/research/component-fallback-plan.md create mode 100644 .claude/session/2026-08-14-01-component-fallback-plan.md diff --git a/.claude/README.md b/.claude/README.md index 5dcfd33..3e4c9d9 100644 --- a/.claude/README.md +++ b/.claude/README.md @@ -72,6 +72,7 @@ | `additional-primitives-plan.md` | **[2026-08-09 세 번째 세션, 전부 해소]** 마지막으로 남아있던 키 기반 동적 컬렉션 재조정도 `Slot:List(...)`로 확정되어 `base/slot-plan.md`로 승격 — 이 문서엔 새로 열린 설계 질문 없음, "빈 자리 아닌 것"/"문서화 백로그"/조사 소스 목록만 배경 자료로 유지 | 하 — 배경 리서치 기록용, 열린 결정 없음 | | `pre-implementation-audit.md` | M0 착수 직전 크리티컬 감사(2026-08-06 신설) — `base/` 전체를 모호성/지연결정리스크/단순화후보 세 렌즈로 재검토, 11개 우선순위1 + 11개 우선순위2 + 2개 단순화후보. **[2026-08-12 열일곱 번째 세션]** 우선순위1 11개 전원 해소 — 남은 건 `.claude/luau-test/` 스파이크 실측 확인뿐 | 상 — 설계는 전부 해소, `.claude/luau-test/` 스파이크 실측만 남음 | | `operator-sugar-plan.md` | **[2026-08-12 신설]** `Sum`/`Product`/`Not`/비트연산 등 `:Compute`/`:Apply`용 연산자 콤비네이터 슈가 — 메커니즘은 이미 확정된 계약(`Animate`와 동형 패턴) 재사용이라 확정, 네임스페이스 이름만 미정. **[2026-08-12 열아홉 번째 세션]** 서브 에이전트 외부 리서치로 다른 리액티브 라이브러리 선례와 대조 — `Operator`가 가장 강한 선례(Python `operator` 모듈), `Clamp`/`Min`/`Max`가 추가 후보로 부상, 비트연산·비교연산자·`Sub`/`Div`는 선례 전무로 드랍 후보, Debounce/Throttle은 `Blocker`와 다른 시간 기반 메커니즘이라 별도 질문으로 분리, `Filtered`의 Slot 안/밖 구분 판단이 ReactiveUI/SolidJS 선례로 뒷받침됨 — 최종 이름 결정은 여전히 사용자 몫. **[2026-08-13 세션, 두 번째]** Haskell 비교 리서치 중 `Alternative`(nil 대체값, coalesce류) 후보 신설 — 카탈로그 확정 규칙에 그대로 맞음, 이전엔 없던 게 확인됨 | 하 — 구현은 맨 마지막(순수 슈가, 없어도 무방, 함수 간 의존 없음), 사용자가 직접 후순위 지정 **[2026-08-13 여섯 번째 세션]** `State|T>` → `State` 평탄화 항목 신설(백로그) — `State>`가 정상 동작하게 됐지만 `retractFrom`의 힌트가 직속 1단계에만 가서 깊은 중첩에선 깜빡임 방지가 꺼진다는 게 구체적 동기, 사용자 판단으로 "UB는 아니지만 원치 않는 방향". `Operator.*`가 아니라 `state:Flatten()` 메소드로 제공하는 게 맞아 보이며, **반환 노드가 동적 의존성을 갖는다는 난점**(quad가 의도적으로 비지원하기로 한 바로 그것)이 확정 전 최대 쟁점 | +| `component-fallback-plan.md` | **[2026-08-14 신설]** 컴포넌트 함수를 감싸 에러 시 자동으로 플레이스홀더(fallback 컴포넌트)를 그려주는 유틸 `Fallback(original, onError)` — `additional-primitives-plan.md`가 이미 확정한 "Error Boundary는 빈 자리 아님, `pcall(MyComp,props)`로 충분"이라는 결론 위에 얹는 순수 슈가(`Operator`가 `:Compute`/`:Apply` 위에 얹힌 것과 같은 관계, 그 문서 재오픈 아님). `pcall`/`xpcall` 선택, 패키지 배치, 이름 전부 미정 | 하 — 형제 백로그(`quad-mock`/`quad-debug`/`Operator`)와 동급, "quad 개발 상당 부분 끝난 뒤" | | `v1-compat-plan.md` | v1 하위호환(compat) 레이어 — `quad-roblox-v1-compat` 패키지, v2→v1 단방향 브리지(`state:Observer()`+v1 프로퍼티 재대입), v2-in-v1/v1-in-v2 두 임베딩 방향의 기술 규칙까지 확정. quad2-try의 `quad-compat`은 빈 폴더로 실제 시도된 적 없었음을 확인 | 하 — Slot이 foreign Instance를 어떻게 다루는지만 Slot 코어 구현 시점까지 미결 | ## `archive/` — 완료됐거나 완전히 뒤집힌 것, 능동 참고 불필요 diff --git a/.claude/question.md b/.claude/question.md index 4fa82df..9b56e9f 100644 --- a/.claude/question.md +++ b/.claude/question.md @@ -207,6 +207,12 @@ 사용자 확인 필요 — `base/attribute-plan.md` "열린 질문" 절. - `research/existing-instance-bind-plan.md` — 스코프 논의만 필요, 구현 착수를 막지 않음. +- **컴포넌트 에러 격리 유틸 `Fallback`(2026-08-14 신설, 사용자 제안)** — + 컴포넌트 함수를 감싸 에러 시 자동으로 플레이스홀더를 그려주는 + `pcall`/`xpcall` 래퍼. 기존 "Error Boundary는 빈 자리 아님" + (`additional-primitives-plan.md`) 결론 위의 순수 슈가라 그 결론 자체는 + 안 흔들림 — `pcall` vs `xpcall`+`debug.traceback`, 패키지 배치 + (`quad-base` 추정), 이름 전부 미정. 상세는 `research/component-fallback-plan.md`. - **`quad-debug` 세부 API 이름** — `research/debug-tooling-plan.md` 참고. 채널 실현 가능성(BindableEvent/Function이 플러그인↔Play 중 게임 경계를 넘는지)까지 사용자가 Studio에서 직접 실측 검증 완료 — 기술적 불확실성은 diff --git a/.claude/research/component-fallback-plan.md b/.claude/research/component-fallback-plan.md new file mode 100644 index 0000000..cef4dda --- /dev/null +++ b/.claude/research/component-fallback-plan.md @@ -0,0 +1,127 @@ +# 컴포넌트 에러 격리 유틸 — `Fallback` + +**상태**: research — 사용자 제안(2026-08-14 세션)으로 신설, 착수 전 +백로그. `research/additional-primitives-plan.md`가 이미 "Error Boundary는 +빈 자리 아님 — `pcall(MyComp, props)`만으로 React Error Boundary와 같은 +격리 효과를 얻는다"고 확정해둔 결론을 뒤집는 게 아니라, **그 결론 위에 +얹는 순수 슈가**(그 문서를 다시 열 필요 없음) — `Operator` 콤비네이터 +(`research/operator-sugar-plan.md`)가 `:Compute`/`:Apply` 위에 얹힌 것과 +같은 관계. 우선순위는 그 형제 백로그 항목들(`quad-mock`/`quad-debug`/ +문서 사이트/`Operator`)과 동급 — "quad 개발 상당 부분 끝난 뒤"로 사용자가 +명시(`CLAUDE.md` "지금 할 일" 4번). + +## 동기 (사용자 원 메모) + +컴포넌트마다 개별적으로 `pcall`을 직접 감싸는 건 실용적이지 않음 — 매 +컴포넌트 호출 자리마다 +`local ok, result = pcall(MyComp, props); if not ok then ... end`를 +손으로 반복해 쓰는 건 번거롭고 빠뜨리기도 쉬움. 대신 +컴포넌트 함수 하나를 받아서 "에러 나면 자동으로 플레이스홀더를 그려주는 +버전"으로 바꿔주는 아주 단순한 유틸이 있으면 충분함 — 클린업 동작 +(언마운트/리소스 해제)이 목적이 아니라, **실제 에러가 났을 때 디버깅이나 +프로덕션 유저 리포트를 편하게 만드는 게 유일한 목적**. + +## 제안 API — `Fallback(original, onError) -> wrapped` + +``` +Fallback( + original: (T...) -> Comp, + onError: (errorMessage: string, trace: string?) -> Comp +) -> (T...) -> Comp +``` + +`original`은 평범한 컴포넌트 함수(`function(props) return Frame{...} end` +모양) 그대로. `Fallback`은 그걸 감싼 **같은 시그니처의 새 컴포넌트 함수**를 +돌려주므로, 호출부 입장에선 원래 컴포넌트를 쓰던 자리에 그대로 대체해 +끼워 넣을 수 있음(`MyComp{...}` → `Fallback(MyComp, OnMyCompError){...}`). + +```lua +local SafeWidget = Fallback(Widget, function(message, trace) + return ErrorPlaceholder { Message = message } +end) + +-- 호출부는 Widget 대신 SafeWidget을 그대로 씀 +Frame { SafeWidget{ ... } } +``` + +### 메커니즘 스케치 — 새 프리미티브 아님, `pcall`/`xpcall` 위의 순수 함수 + +```lua +function Fallback(original, onError) + return function(...) + local trace: string? = nil + local ok, resultOrErr = xpcall(original, function(err) + trace = debug.traceback(nil, 2) + return err + end, ...) + if ok then + return resultOrErr + end + return onError(resultOrErr, trace) + end +end +``` + +(의사코드 수준 — `xpcall` 에러 핸들러 안에서 잡은 `trace`를 업밸류로 +빼내는 게 실제로 원하는 순서/타이밍에 실행되는지는 Luau로 직접 실측 +필요, 아래 "열린 질문" 참고.) `research/debug-tooling-plan.md`가 이미 +확인해둔 선례(Vide/Fusion 둘 다 `xpcall`+`debug.traceback`으로 **에러 +나는 순간에만** 스택을 찍는 패턴)를 그대로 재사용 — 새 트레이싱 +메커니즘을 발명하지 않음. + +### `ErrorComp`가 추가 상태가 필요하면 — 커링 (사용자 명시) + +`onError` 자체가 클로저이므로, 별도 API 없이 그냥 커링으로 풀림: + +```lua +local function makeErrorHandler(context) + return function(message, trace) + return ErrorPlaceholder { Message = message, Context = context } + end +end + +local SafeWidget = Fallback(Widget, makeErrorHandler(someContext)) +``` + +`Fallback` 자신은 이런 경우를 특별히 신경 쓸 필요 없음 — `onError`가 +이미 평범한 함수이기 때문. + +## 왜 기존 "Error Boundary는 빈 자리 아님" 결론과 안 부딪히는가 + +`research/additional-primitives-plan.md`의 결론은 "새 프리미티브가 필요 +없다"는 것이었지 "지금 이대로 편하다"는 게 아니었음 — `Fallback`은 그 +문서가 이미 지목한 정확히 같은 메커니즘(`pcall(MyComp, props)`)을 감싸는 +얇은 편의 함수일 뿐, 디스패치/Store/Handler 계층에 아무것도 새로 안 만듦. +`Operator` 콤비네이터가 `:Compute`/`:Apply` 위에서 그랬던 것과 동일한 +관계 — 그 문서를 다시 열 필요 없음. + +## 열린 질문 + +- **`pcall` vs `xpcall`+`debug.traceback`**: 스택 트레이스까지 항상 + 캡처할지, 아니면 가벼운 `pcall`(에러 메시지만)을 기본으로 하고 트레이스는 + 옵션(`onError`가 2번째 인자를 안 받으면 그냥 안 계산)으로 둘지. Roblox + `debug` 라이브러리가 제한적이라는 건 이미 확인돼 있어서(`debug-tooling-plan.md`) + 부담은 크지 않아 보이나 실측 필요. +- **`xpcall` 에러 핸들러 배선의 실측**: 위 의사코드가 실제 Luau에서 + 그대로 동작하는지(에러 핸들러 안에서 클로저 업밸류에 쓴 값이 바깥에서 + 제대로 보이는지 등) 착수 시점에 `luau`로 직접 확인 필요. +- **패키지 배치**: `original`을 그냥 호출하고 결과를 그대로 돌려주는 + 순수 함수라 Store/Dispatch 어디에도 안 걸림 — `quad-base`(엔진 무종속)가 + 자연스러워 보임, `Operator`와 같은 결. 최종 확인 필요. +- **이름**: `Fallback`이 흔한 단어라 top-level 노출 시 충돌 위험 — 다른 + 가칭들과 같은 용어 정리 대기열로 볼지, 아니면 이 유틸 하나뿐이라 + 네임스페이스 없이 top-level 함수로 둬도 괜찮을지(`Tag`/`Attribute`류 + 네임스페이스가 필요했던 건 그 안에 여러 이름이 몰려서였고, 이건 낱개 + 함수 하나뿐이라 충돌 표면이 작음). +- **프로덕션에서의 동작**: 에러 메시지/트레이스를 유저에게 보이는 화면에 + 그대로 노출할지, 아니면 로그로만 보내고 화면엔 일반화된 메시지만 + 보여줄지는 `onError` 구현(사용자 코드) 몫으로 완전히 열어두는 게 맞아 + 보임 — `Fallback` 자체는 raw 에러 정보를 그대로 넘기기만 하고 가공은 + 안 함(가공까지 대신해주면 그게 또 다른 매직). +- 그 외 확정된 결정 없음 — 착수 시점에 위 항목들을 순서대로 확인. + +## 우선순위 + +**형제 백로그 항목들과 동급, 맨 뒤.** `Operator`처럼 순수 슈가라 없어도 +기능 격차 없음(`pcall`을 직접 쓰면 되므로, `additional-primitives-plan.md`가 +이미 확인한 그대로) — 편의성 문제일 뿐. diff --git a/.claude/session/2026-08-14-01-component-fallback-plan.md b/.claude/session/2026-08-14-01-component-fallback-plan.md new file mode 100644 index 0000000..33d4239 --- /dev/null +++ b/.claude/session/2026-08-14-01-component-fallback-plan.md @@ -0,0 +1,80 @@ +# 2026-08-14 첫 번째 세션 — 컴포넌트 에러 격리 유틸 `Fallback` 백로그 신설 + +## 배경 + +사용자가 컴포넌트마다 개별적으로 `pcall`을 직접 감싸는 게 실용적이지 +않다고 지적 — 매 컴포넌트 호출 자리마다 손으로 `pcall`을 반복해 쓰는 +대신, 컴포넌트 함수 하나를 받아 에러 시 자동으로 플레이스홀더를 그려주는 +버전으로 바꿔주는 아주 단순한 유틸을 요청. 사용자가 직접 제시한 모양: + +``` +Fallback((T...)→OriginalComp, (errorMessage)→ErrorComp) → (T…)→OriginalComp|ErrorComp +``` + +클린업 동작(언마운트/리소스 해제)이 목적이 아니라, 실제 에러가 났을 때 +디버깅이나 프로덕션 유저 리포트를 편하게 만드는 게 유일한 목적이라고 +명시. `ErrorComp`가 추가 상태/props가 필요하면 `Fallback`이 그걸 신경 쓸 +필요 없이 `onError` 자체를 커링해서 만들면 된다는 점도 사용자가 직접 +짚음. "이걸 백로그로 작성해봐, 워크트리에서 작업해"라고 요청. + +## 확인한 것 — 기존 결론과의 관계 + +`research/additional-primitives-plan.md`를 확인한 결과, 이미 "Error +Boundary는 빈 자리 아님 — `pcall(MyComp, props)`만으로 React Error +Boundary와 같은 격리 효과를 프레임워크 지원 없이 얻는다"는 결론이 확정돼 +있었음(2026-08-06~07 세션, 이 문서는 이후 "새로 열린 설계 질문 없음"으로 +배경 자료화됨). 사용자의 `Fallback` 요청은 이 결론을 뒤집는 게 아니라 +정확히 그 결론이 지목한 메커니즘(`pcall(MyComp, props)`)을 감싸는 얇은 +편의 함수 — `Operator` 콤비네이터가 `:Compute`/`:Apply` 위에 얹힌 것과 +같은 관계이므로, `additional-primitives-plan.md`를 다시 열지 않고 새 +research 문서로 분리하는 게 맞다고 판단. + +`research/debug-tooling-plan.md`가 이미 확인해둔 선례(Vide/Fusion 둘 다 +`xpcall`+`debug.traceback`으로 에러 나는 순간에만 스택을 찍는 패턴)도 +같이 참고해, 에러 트레이스 캡처 메커니즘을 새로 발명하지 않고 재사용하는 +방향으로 스케치. + +## 한 일 + +- `research/component-fallback-plan.md` 신설 — 동기, 제안 API(`Fallback(original, onError)`), + 메커니즘 의사코드(`xpcall`+`debug.traceback`), 커링 관용구, 기존 + "Error Boundary는 빈 자리 아님" 결론과 안 부딪히는 이유, 열린 질문 + (pcall vs xpcall 트레이드오프, `xpcall` 에러 핸들러 배선 실측 필요, + 패키지 배치, 이름, 프로덕션 동작) 정리. **설계 확정 아님 — 순수 + 백로그**, 사용자가 어떤 결정도 아직 내리지 않음. +- `.claude/README.md` research 표에 새 행 추가. +- `CLAUDE.md` "지금 할 일" 4번 백로그 목록에 `Fallback`을 형제 항목 + (`quad-mock`/`quad-debug`/문서 사이트/`Operator`)과 나란히 추가, 상세 + 링크 목록에도 `component-fallback-plan.md` 추가. + +## 반영 상태 + +새로 연 설계 질문 없음(전부 문서 신설 자체가 목적) — `question.md`에 +낮은 우선순위 항목으로 포인터 추가는 이 세션 안에서 같이 처리. +`doc-check.py`는 워크트리에 `.claude/` 전체가 없어(아래 "워크트리 관련 +메모" 참고) 메인 체크아웃에 결과 반영 후 그쪽에서 실행. + +## 워크트리 관련 메모 (재발 방지용, 코드 리뷰로 정정됨) + +**[정정, 같은 세션 후속 `/code-review`]** 최초 기록("`.claude/`와 루트 +`CLAUDE.md`/`ROADMAP.md`/`HUMAN_TODO.md`가 git에 커밋돼 있지 않음")은 +틀렸음 — `git ls-files`로 재확인한 결과 이 파일들 전부(`.claude/` 208개 +포함) 로컬 `main` 브랜치엔 정상적으로 커밋돼 있음. 실제 원인은 따로 +있었음: `EnterWorktree`가 기본값(`baseRef: "fresh"`)으로 +**`origin/<기본브랜치>`**(이 레포는 `origin/master`)에서 새 브랜치를 침 — +그런데 `origin/master`는 `.claude/` 파일이 **0개** +(`git ls-tree -r origin/master -- .claude`로 확인, `CLAUDE.md`도 없음). 이 레포의 계획 +문서(`.claude/`, 루트 `CLAUDE.md`/`ROADMAP.md`/`HUMAN_TODO.md`)는 +`SAFETY.md`의 "GitHub 등 외부 git 호스팅에 이 레포를 push하지 말 것" +규칙에 따라 **로컬 `main`에만 있고 `origin`(GitHub)엔 의도적으로 한 번도 +push된 적 없음** — 그래서 `origin/master`에서 갈라친 fresh 워크트리는 +계획 문서가 원천적으로 빠진 채 시작되는 게 **의도된 안전장치**이지, +문서가 untracked라서가 아님. + +**재발 방지 — 다음에 이 레포에서 "워크트리에서 작업해"라는 지시를 받으면**: +계획 문서를 편집해야 하는 작업이면 `EnterWorktree`에 `path`로 로컬 +`main`에서 이미 갈라친 워크트리를 쓰거나, 필요한 파일만 메인 체크아웃 +(로컬 `main`)에서 복사해 편집 후 다시 복사해 반영하는 이번 방식을 그대로 +반복하면 됨 — 다만 "git에 안 올라가 있어서"가 아니라 "`origin/master` +브랜치엔 애초에 이 문서들이 없어서(의도된 것)"라는 정확한 이유로 +이해하고 시작할 것. diff --git a/CLAUDE.md b/CLAUDE.md index ff4ce6c..bd9c168 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -238,11 +238,15 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션 실현 가능성은 실측 검증 완료, 세부 API 이름만 남음), 문서 사이트 전체 구조(초심자/api/심화/`quadnomicon` 4축 + 콘텐츠 맵), `Operator` 콤비네이터 슈가(`Sum`/`Product`/`Not`/비트연산 등 `:Compute`/`:Apply`용 — 메커니즘은 - 확정, 네임스페이스 이름만 미정, 구현은 순수 슈가라 맨 마지막) — 전부 "quad + 확정, 네임스페이스 이름만 미정, 구현은 순수 슈가라 맨 마지막), 컴포넌트 + 에러 격리 유틸 `Fallback`(**[2026-08-14 신설]** 컴포넌트 함수를 감싸 에러 + 시 자동으로 플레이스홀더를 그려주는 `pcall`/`xpcall` 래퍼 — 기존 + "Error Boundary는 빈 자리 아님" 결론 위의 순수 슈가, + `research/component-fallback-plan.md`) — 전부 "quad 개발 상당 부분 끝난 뒤"로 사용자가 못박은 후순위. 상세는 `.claude/README.md`의 `research/` 표(`debug-tooling-plan.md`/`documentation-plan.md`/ `documentation-content-map.md`/`framework-comparison-findings.md`/ - `operator-sugar-plan.md`). + `operator-sugar-plan.md`/`component-fallback-plan.md`). 5. 자율 작업 루프/스케줄 설정 여부는 사용자 결정 대기 중 (`HUMAN_TODO.md` 2번 항목). @@ -1111,3 +1115,24 @@ claim**으로 확정. 이걸로 마지막 게이트가 열려 **0-A(하강 diff `REF` 정규식이 줄 단위라 파일명과 절 제목이 줄바꿈에 걸친 인용을 통째로 놓치고 있었고, 고치자 이번 분할뿐 아니라 **9차 세션 1단계 분할의 stale 참조까지** 무더기로 드러나 30여 곳 정정. + +**2026-08-14 첫 번째 세션 — 컴포넌트 에러 격리 유틸 `Fallback` 백로그 신설** +(`session/2026-08-14-01-component-fallback-plan.md`) +사용자가 컴포넌트마다 손으로 `pcall`을 감싸는 게 번거롭다며, 컴포넌트 +함수를 감싸 에러 시 자동으로 플레이스홀더를 그려주는 +유틸(`Fallback(original, onError)`)을 제안하고 백로그 문서화를 요청 — +워크트리에서 작업. +`research/additional-primitives-plan.md`가 이미 확정한 "Error Boundary는 +빈 자리 아님, `pcall(MyComp,props)`로 충분"이라는 결론을 뒤집는 게 아니라 +그 위에 얹는 순수 슈가(`Operator`가 `:Compute`/`:Apply` 위에 얹힌 것과 +같은 관계)로 판단해 새 `research/component-fallback-plan.md` 신설 — +`xpcall`+`debug.traceback` 메커니즘 스케치, 커링 관용구, 열린 질문(pcall +vs xpcall, 패키지 배치, 이름, 프로덕션 동작) 정리, 설계 확정은 아직 없음. +부수적으로 워크트리가 계획 문서 없이 빈 채로 시작되는 걸 발견 — +**[정정, 후속 `/code-review`]** 처음엔 "`.claude/`가 git에 안 커밋돼 +있어서"로 잘못 진단했으나, 실제로는 `EnterWorktree` 기본값이 +`origin/master`에서 갈라치는데 `SAFETY.md`(GitHub push 금지) 때문에 +계획 문서가 로컬 `main`에만 있고 `origin`엔 애초에 없는 것(의도된 것)이 +원인 — 필요한 파일만 메인 체크아웃(로컬 `main`)에서 복사해 편집 후 다시 +복사하는 방식으로 처리, 상세 정정은 +`session/2026-08-14-01-component-fallback-plan.md` 참고.