quad/CLAUDE.md
qwreey 9dd82136bd
qa: 8라운드 손 트레이싱 처리 — 결정 Q1~Q10 반영, M2 착수 게이트 0
발견 17건(H-107~H-123)의 사용자 결정을 base/ 전체에 반영. 7라운드 확정 중
뒤집힌 건 없고, 고친 건 전부 7라운드가 base/에 내려앉을 때 생긴 누락·충돌
(하루 차로 확정된 결정들이 서로를 못 본 자리)이다. 결정의 소스는
qa-request/pre-implementation-handtrace-round8-followup.md.

계약 변경 넷:
- Ref 콜백이 fn(value, ref) — 2번째가 곧 출처 Epoch. Effect가 Update(from)에
  넘길 유일한 통로였다(k(value)뿐이면 Update(nil) 크래시, 실측 재현).
- Observer fn이 세 자리 fn(targetState, self, emitFrom) + observer._state
  강참조. 옛 2-인자는 "self는 리시버" 계약과 정면 충돌해 무인자
  state:Observer()의 내부 콜백이 즉사했다.
- WeakSubscribe도 .Subscribed를 세운다. 안 그러면 Effect의 State dep 전량이
  조용히 침묵. 해제는 "건 경로로 푼다"(양방향 fail-fast).
- 예약 키 진단이 CheckReservedKeys<keyof<T>> — T를 통째로 넘기는 배선은
  실사용 T에서 아예 안 돈다(Source<T>가 *error-type*을 품어 유효한 Store
  전부에 스퓨리어스 에러).

사용자가 문항의 전제를 두 번 정정: Ref 콜백과 Observer 콜백은 이질적이라
애초에 통합 대상이 아니었고(Observer엔 자기 epoch가 없다), H-118은 소유권
문제가 아니라 gate-plan 5번의 문장이 틀린 것이었다(🟡🟢).

커밋 전 검증 — 감사 11라운드(44건, 0건으로 수렴) + /code-review high
7라운드(42건) = 86건. 감사가 0으로 수렴한 직후 code-review가 42건을 냈고,
그중 하나가 H-101의 "새 필드를 안 만든다"를 역전시켰다: getOffsetAt의
부수효과가 splice의 되감기 신호를 지우는 경로가 실재해, 부기 필드를
offsetCacheValidUpTo(캐시)와 offsetSetUpTo(:Set 완료) 둘로 분리했다.
"Set을 해줬느냐"와 "캐시가 유효하냐"를 한 값이 쥔 게 원인이었다.

그 외: splice 무효화 i-1, 명시 recompute 호출부 전부 재진입 게이트,
recompute 되감기 클램프, Store defaults isSource 검증, isModifier 가드를
Source 생성자로, 훅 슈가 nil 가드, pesde.lock 커밋 확정, :Single 3-인자.
2026-08-25 session/ 원문 공백은 2026-08-19 선례대로 재구성 없이 기록만.

doc-check ERROR 0 / WARN 기준선 유지.

Claude-Session: https://claude.ai/code/session_01F9zgJ4c4kDitAoQMm9qxKn
Co-authored-by: qwreey <me@qwreey.moe>
2026-08-26 17:18:30 +09:00

3.6 KiB

CLAUDE.md

Roblox 엔진용 DOMless UI 렌더러 quad를 처음부터 다시 짜는 프로젝트. [2026-08-24 기준] M0(스파이크 검증)/M1(스캐폴딩)까지 완료, 다음은 M2(반응형 코어 — Source/State/Store). ⚠️ [2026-08-24] M2와 M3의 번호·순서가 맞바뀌었다 — 예전엔 M2=디스패치, M3=반응형이었는데 의존이 한 방향(디스패치 → 반응형)이라 반응형을 먼저 짓기로 확정했다. 그래서 2026-08-24 이전에 쓰인 session/·archive/·qa-request/ 문서의 M2/M3는 옛 의미로 읽을 것(라이브 문서는 전부 새 번호로 맞춰뒀음). 경위는 .claude/archive/question-resolved.md의 "마일스톤 경계" 절, 새 구성은 ROADMAP.md의 M2 배너. [2026-08-26] 8라운드 손 트레이싱까지 처리 완료 — M2 착수를 막는 항목이 하나도 없다. 결정의 소스는 .claude/qa-request/pre-implementation-handtrace-round8-followup.md (7라운드 몫은 -round7-followup.md)이고 .claude/question.md 최우선 절은 비어 있다. 같은 상태를 .claude/project-context.md도 서술하니 마일스톤이 넘어갈 때 두 곳을 같이 고칠 것. 진행 상황의 소스는 항상 루트 ROADMAP.md.

이 파일에 내용을 직접 쌓지 말 것 — 짧은 진입점으로 유지한다. 새 서술은 아래 import된 파일 중 맞는 곳에 넣을 것(어디에도 안 맞으면 그건 매 세션 로드될 내용이 아닐 가능성이 높음 — .claude/ 아래 해당 문서로).

항상 로드되는 컨텍스트

관례와 작업 방식 @.claude/conventions.md

프로젝트 컨텍스트와 문서 구조 @.claude/project-context.md

지금 할 일 @.claude/todos.md

온디맨드 자료 (자동 로드 안 됨 — 필요할 때 직접 열 것)

무엇이 궁금할 때 어디를 볼 것
지금 유효한 설계 — 어떤 결정이 확정돼 있는가 .claude/base/ (먼저 .claude/base/architecture.md)
문서 전체 색인 — 어느 파일이 뭘 다루는가 .claude/README.md
사용자가 답해야 할 열린 질문 .claude/question.md
구현 순서 / 마일스톤 루트 ROADMAP.md
사람만 할 수 있는 일 루트 HUMAN_TODO.md
어떤 결정이 왜 그렇게 됐나 / 전에 뒤집힌 적 있나 .claude/session-summary.md를 grep (세션별 2~4줄 요약 색인)
그 결정의 논쟁 과정 원문 .claude/session/YYYY-MM-DD-NN-slug.md
뒤집히거나 기각된 설계의 원문 .claude/archive/

주의: session-summary.md는 의도적으로 @import 안 함 — 계속 자라는 히스토리 문서라 통째로 올릴 이유가 없음(그 문서 스스로 "항상 읽을 필요 없음, 지금 유효한 설계는 base/가 소스"라고 명시). 필요해지면 그때 가서 열 것.

충돌 시 우선순위: .claude/base/ > 여기 요약이나 session-summary.md. 후자들은 과거 시점 서술이라 더 최근 결정이 안 반영돼 있을 수 있음.