docs(audit): 10차 세션 — 병렬 에이전트 코퍼스 감사, 부정확성 7건 수정
9차 세션의 구조 변경(luau-test 재편/bind-system-plan 분할/question.md 트림)이 남긴 반영 누락을 6개 병렬 에이전트로 찾아 즉시 수정: - luau-test 재편 후 깨진 flat 경로 참조 9곳을 파일명+실제 폴더로 정정 - bind-system-plan.md 분할 후 자기참조/외부참조 깨짐 8곳 정정 - ref-plan.md에 0-Z 배너가 안 옮겨와 옛 재디스패치 모델을 무배너로 서술 중이던 것 발견 — 배너 추가, 반영 대상 6개→7개로 갱신 - "8차 세션"으로 잘못 표기된 9차 세션 작업 17곳(git 커밋 타임스탬프로 교차검증) 정정 - question.md 트림 중 빠진 열린 질문(State<State<T>> 평탄화) 복원, 트림 후 깨진 참조 2곳 정정 - ROADMAP.md M0 섹션에 0-Y/0-Z 게이트 표시 누락 보강 doc-check.py ERROR 0 유지. 새로 연 설계 질문 없음 — 전부 기존 서술 정합성 문제. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
This commit is contained in:
parent
540c142969
commit
aaefa08c1c
25 changed files with 223 additions and 51 deletions
|
|
@ -16,8 +16,8 @@
|
|||
| `archive/` | 완료 + 사용자가 실사용/실기기로 직접 검증까지 마침 (구현 대상). **[2026-08-06 확장]** 완전히 뒤집힌 설계 결정을 원문+역전 이유+diff와 함께 보존하는 용도로도 사용(제목 `[역전됨]` — 한 번 확정했다가 뒤집힌 것) — 더 이상 능동적으로 참고 안 해도 되지만(토큰 낭비 방지 위해 `base/`/`research/`에서 뺌) `quadnomicon` 소재로는 나중에 쓸 수 있음. **[2026-08-07 확장]** 후보였다가 채택 안 된 것(확정한 적 없이 검토 후 기각)도 같은 방식으로 보존, 제목은 구분을 위해 `[기각됨]` — `[역전됨]`과 의미가 다르므로 혼동하지 말 것. **[2026-08-07 세 번째 확장]** 설계 반전/기각과 별개로, 에이전트가 문서 작성 중 스스로 낸 개념 혼동을 정정한 이력은 `[에이전트 실수]` 태그로 `agent-mistake.md` 하나에 모음(CLAUDE.md 세션 로그 중복 방지) |
|
||||
| `feedback/` | 실사용 피드백을 정리한 긴 로그 — 지금은 비어있음(구현 시작 전) |
|
||||
| `luau-test/` | **[2026-08-09 신설]** `base/` 확정 사항 중 "추론만으로 확정하고 실제 Luau로 부딪혀본 적 없는 것"(M0 스파이크 대상)을 `luau`/`luau-analyze`/`luau-lsp`/Roblox Studio로 사용자가 직접 돌려볼 독립 실행 스크립트 모음. **[2026-08-13 여섯 번째 세션, 첫 실측]** `luau`/`luau-analyze` 바이너리가 생겨 처음으로 실제 실행 — **런타임 12개 전원 통과**, 타입 쪽에서 `:Compute(fn)` lazy 핸들 계약이 Luau 추론과 충돌하는 게 드러남(`question.md` 0-Y). **`STATUS.md`가 상태의 소스**(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행 분류 — 사람이 먼저 볼 것만 위에), `luau-test/README.md`는 각 파일의 검증 의도·배경, 실행 결과 상세는 `audit/luau-test-first-run-2026-08-13.md` |
|
||||
| `audit/` | **[2026-08-13 신설]** `luau-test/` 등 스파이크를 실제로 돌려본 뒤 "무엇이 확인됐고 무엇이 아직 안 됐는지"를 기록하는 곳 — 스크립트/계획 자체가 아니라 **실측 결과**만 다룸. base/luau-test와 달리 부분 확인(일부만 통과)도 있는 그대로 기록, 완전히 해소되면 관련 `base/`/`luau-test/README.md` 캐비엇을 지우고 이 문서는 근거로 남김. **현재 2개**: `luau-test-first-run-2026-08-13.md`(첫 실측 라운드 전체 — 런타임 12개 통과, `question.md` 0-Y의 1차 근거), `gcconn-trick-verification.md`(사용자가 Studio에서 직접 돌린 gcconn 트릭 부분 확인 — `luau-test/10`의 A 섹션 앞부분만, A-1/A-2/B/C는 미확인) |
|
||||
| `tools/` | **[2026-08-13 여덟 번째 세션 신설]** 코퍼스 기계 점검 — `doc-check.py`가 깨진 파일/절 참조, README 색인 누락, 날짜 없는 시한부 주장("아직 안 돌려봄" 등), 미반영 ⚠️ 배너를 한 번에 훑음. **중대 변경 후 커밋 전에 돌릴 것**(`python3 .claude/tools/doc-check.py`) — 수동 감사에서 나온 발견의 대부분이 이 종류였고, 실제로 문서를 쪼개다 잘못 옮긴 참조를 이게 잡아냄. ERROR는 고치고 WARN은 판단 대상 |
|
||||
| `audit/` | **[2026-08-13 신설]** `luau-test/` 등 스파이크를 실제로 돌려본 뒤 "무엇이 확인됐고 무엇이 아직 안 됐는지"를 기록하는 곳 — 스크립트/계획 자체가 아니라 **실측 결과**만 다룸. base/luau-test와 달리 부분 확인(일부만 통과)도 있는 그대로 기록, 완전히 해소되면 관련 `base/`/`luau-test/README.md` 캐비엇을 지우고 이 문서는 근거로 남김. **현재 2개**: `luau-test-first-run-2026-08-13.md`(첫 실측 라운드 전체 — 런타임 12개 통과, `question.md` 0-Y의 1차 근거), `gcconn-trick-verification.md`(사용자가 Studio에서 직접 돌린 gcconn 트릭 부분 확인 — `10`의 A 섹션 앞부분만, A-1/A-2/B/C는 미확인) |
|
||||
| `tools/` | **[2026-08-13 아홉 번째 세션 신설]** 코퍼스 기계 점검 — `doc-check.py`가 깨진 파일/절 참조, README 색인 누락, 날짜 없는 시한부 주장("아직 안 돌려봄" 등), 미반영 ⚠️ 배너를 한 번에 훑음. **중대 변경 후 커밋 전에 돌릴 것**(`python3 .claude/tools/doc-check.py`) — 수동 감사에서 나온 발견의 대부분이 이 종류였고, 실제로 문서를 쪼개다 잘못 옮긴 참조를 이게 잡아냄. ERROR는 고치고 WARN은 판단 대상 |
|
||||
| `session/` | **[2026-08-11 신설]** 세션별 상세 로그 원문(시행착오·정정 전 서술 포함, `quadnomicon` 개발로그 소재용) — 루트 `CLAUDE.md`가 3196줄까지 불어나 성능 저하를 유발해서 분리함. 파일명 `YYYY-MM-DD-NN-slug.md`, CLAUDE.md의 "세션 히스토리" 절에서 각 항목이 여기로 링크. 항상 읽을 필요 없음 — 결정의 논의 과정이 궁금할 때만 |
|
||||
| `initreq/` | 프로젝트 착수 시 클론해둔 참고 레포(quad v1, fusion, vide, rbvm, tbox, code-docker) + PA님 실 코드(`artworks/`, 4차 라운드 교차검증 근거) + 원본 요청(`req.md`, `raw-userinput.md`) + `quad2-try`(이전에 시도했다 폐기한 v2 재작성 시도 — 리서치 완료, 결론은 `base/bind-system-plan.md`) — 읽기 전용 리서치 소스, 여기 내용을 옮기지 말고 항상 원본 그대로 유지 |
|
||||
|
||||
|
|
@ -45,9 +45,9 @@
|
|||
| `attribute-plan.md` | **[2026-08-07 여덟 번째 세션 신설]** 단일 키 `[AttributeKey<T> "Name"]`(구 `Attribute<T>`) — `SetAttribute(name, nil)`이 네이티브 지우기라 `None` 센티널과 가장 깔끔하게 맞아떨어짐. **[2026-08-11 아홉 번째 세션]** 여러 Store를 한 번에 attribute로 묶는 그룹 `Attribute(...)` 프리미티브 신설(`Tag`와 동형 array-part 값 객체, `Merged`로 헤테로지니어스 Store 합성), 이름 충돌 방지로 단일 키를 `AttributeKey`로 리네임(잠정). **[같은 세션 후속]** `AttributeKey(name)`이 이름별 weak 캐시로 동등성 보장하도록 확정되며, 그룹 Handler는 자기 완결형 재구현 대신 메모이즈된 키로 기존 단일 키 경로에 재귀 위임하는 걸로 개정(중복 구현 제거). **[2026-08-12 열 번째 세션]** 그룹/직접 쓰기가 같은 이름을 동시에 관리하는 충돌을 막기 위해 그룹은 공개 캐시 대신 `rawNew(name)` 전용 키+소유권 `Relate`로 전환. **[열한 번째 세션]** `retract`가 store 재발행마다 항상 불린다는 정정에 맞춰 `AttributeKeyHandler.retract`를 손봄(이 시점엔 `v==nil` 가드 버전 — 아래 열여섯 번째 세션에서 최종 재정정됨), 그룹의 "남아있는 이름" 위임도 매번 `retractUnder`를 먼저 부르도록 정정(체인 누수 방지). **[2026-08-12 열여섯 번째 세션, 최종 재정정]** `retract`는 완전 no-op으로 굳어짐(`SetAttribute`는 오직 `process(inst,k,nil)`에서만) — Attribute는 명시적 `None`/`nil`로만 지워지고, 그룹 diff나 컴포넌트 언마운트로 이름이 조용히 사라져도 값은 자동으로 안 지워짐(`Ref`의 "Destroy 무관, 정리는 명시적으로" 철학과 통일), 단 사라진 이름의 *구독*은 끊어 자원 누수는 막음 — 위 "v==nil 가드" 버전은 이걸로 폐기. **[2026-08-13 세션, 전면 재정정]** `rawNew`+`owners` 수동 레지스트리 방식이 "그룹이 이름을 놓았다 다시 포함하면 자기 자신과 충돌"하는 실제 버그로 확인됨 — `AttributeGroupKeyHandler`라는 `isHandlable` 없는 순수 체크포인트 핸들러를 `Dispatch.processAs`로 명시 push하고 `Dispatch.retractSelfAndUnder`로 통째 철거하는 방식으로 전면 재설계, 소유권 충돌 감지도 별도 레지스트리 없이 기존 재진입 가드가 대신 잡아줌(`bind-system-plan.md` 참고). `AttributeKeyHandler`는 다시 완전 무상태로 단순화됨. **[2026-08-13 세션, 다섯 번째, 전면 재설계 — 체크포인트조차 불필요해짐]** `Dispatch`가 인덱스 기반으로 재설계되며 `AttributeGroupKeyHandler`/`processAs`/`retractSelfAndUnder`를 전부 걷어냄 — 그룹이 그냥 공개 `AttributeKey(name)`으로 항상 인덱스 1부터 `Dispatch.process`/`retractFrom`을 직접 부르면 끝(점유 체크 자체가 소유권 충돌 감지), `groupState` Relate도 필요 없어짐(반환 클로저가 이름 집합을 직접 캡처) — 중간 버전은 `archive/checkpoint-handler-pattern-reversed.md`. **[2026-08-13 감사, 정정]** 그런데 그 의사코드가 `process` 안에서 이름마다 `retractFrom(...,1,...)`을 먼저 부르고 있어 **인덱스 1이 무조건 비워지는 바람에 점유 체크가 전혀 작동하지 않았음**(그룹↔그룹 사이에서 조용한 last-write-wins가 그대로 남아 있었음) — `process`는 `Dispatch.process`만 부르고 철거는 반환 클로저가 자기가 등록한 이름 전부에 대해 하도록 정정. 그룹 Handler 시그니처가 계약과 안 맞던 것(`process(inst,index,v)` 3-인자)도 같이 수정 |
|
||||
| `onchange-plan.md` | **[2026-08-10 세션 신설]** `OnChange(name)` — `GetPropertyChangedSignal` 바인딩 전용 DI 키, `Attribute`와 달리 제네릭 타입 파라미터 없음(콜백 타입은 인라인 명시, 이벤트 바인딩과 같은 급 트레이드오프). 전부 quad-roblox(`Handlers/OnChange.luau`), `State<function>`은 기존 이벤트 store-bind 메커니즘 재사용. **[2026-08-11 아홉 번째 세션 후속]** `AttributeKey`와 동일한 이름별 weak 캐시로 `OnChange(a) == OnChange(a)` 동등성 보장 |
|
||||
| `relate-plan.md` | **[2026-08-08 신설]** `Relate` — `inst`를 weak 키로 하는 범용 릴레이션 프리미티브(`SetWeak`/`GetWeak`/`SetStrong`/`GetStrong`, 비싱글톤 생성자). 구 `base.perInstanceState(inst)` placeholder를 대체·정식 승격, `lifecycle-pattern.md`의 `bindLifetime`/`canExecute`가 그 위에 얹힘. **[2026-08-12 열세/열네 번째 세션]** 서로 다른 두 `Relate`가 서로의 키를 상대방 값으로 강하게 붙잡는 상호 순환 패턴 경고 신설 — Luau에 ephemeron 테이블이 없어(공식 확인, luau.org/compatibility) 이런 순환은 실제로 GC가 안 됨, `Slot`의 `kSlotMap`/`slotOwner`가 실제 사례이자 수정 사례 |
|
||||
| `ref-plan.md` | **[2026-08-13 여덟 번째 세션, `bind-system-plan.md`에서 분리]** `Ref`/`PreRef` — 지연 없는 확정 값 박스. 용도 재정의(leaf 노드를 담는 용도로도, leaf 노드에 바인딩하는 용도로도), `.Value`+`:Set`/`:Callback`/`:Wait`(전부 self 반환), `Ref`의 retract가 `TagHandler`와 같은 `Relate` diff 패턴이라는 것, 이중 바인딩 금지(`canBound`), `PreRef` 호이스팅 pre-pass와 1회용 `_fired` 가드. **분리는 순수 이동 — 결정은 하나도 안 바뀜** |
|
||||
| `event-plan.md` | **[2026-08-13 여덟 번째 세션, `bind-system-plan.md`에서 분리 — 사용자가 직접 지목]** 이벤트 바인딩 — 핸들러가 self(Instance)를 **안** 받는다는 확정(Ref가 이미 커버, 이중 쓰기 경로 방지), 이벤트도 store-bind 가능하며 `false`를 넣으면 disconnect. 이벤트 *네이밍* 관례는 인스턴스 생성과 한 절에 섞여 있어 `bind-system-plan.md`에 남음, `GetPropertyChangedSignal`은 `onchange-plan.md`. **분리는 순수 이동** |
|
||||
| `brand-plan.md` | **[2026-08-13 여덟 번째 세션, `bind-system-plan.md`에서 분리]** `Brand` — 런타임 nominal 타입 판별 통합 메커니즘(`Brand.set`/`Brand.get`), `isState`를 10종 branded 타입 전부로 일반화. 동작/구현은 확정, **이름 `Brand` 자체만 용어 정리 대기**(`question.md` 1번). **분리는 순수 이동** |
|
||||
| `ref-plan.md` | **[2026-08-13 아홉 번째 세션, `bind-system-plan.md`에서 분리]** `Ref`/`PreRef` — 지연 없는 확정 값 박스. 용도 재정의(leaf 노드를 담는 용도로도, leaf 노드에 바인딩하는 용도로도), `.Value`+`:Set`/`:Callback`/`:Wait`(전부 self 반환), `Ref`의 retract가 `TagHandler`와 같은 `Relate` diff 패턴이라는 것, 이중 바인딩 금지(`canBound`), `PreRef` 호이스팅 pre-pass와 1회용 `_fired` 가드. **분리는 순수 이동 — 결정은 하나도 안 바뀜** |
|
||||
| `event-plan.md` | **[2026-08-13 아홉 번째 세션, `bind-system-plan.md`에서 분리 — 사용자가 직접 지목]** 이벤트 바인딩 — 핸들러가 self(Instance)를 **안** 받는다는 확정(Ref가 이미 커버, 이중 쓰기 경로 방지), 이벤트도 store-bind 가능하며 `false`를 넣으면 disconnect. 이벤트 *네이밍* 관례는 인스턴스 생성과 한 절에 섞여 있어 `bind-system-plan.md`에 남음, `GetPropertyChangedSignal`은 `onchange-plan.md`. **분리는 순수 이동** |
|
||||
| `brand-plan.md` | **[2026-08-13 아홉 번째 세션, `bind-system-plan.md`에서 분리]** `Brand` — 런타임 nominal 타입 판별 통합 메커니즘(`Brand.set`/`Brand.get`), `isState`를 10종 branded 타입 전부로 일반화. 동작/구현은 확정, **이름 `Brand` 자체만 용어 정리 대기**(`question.md` 1번). **분리는 순수 이동** |
|
||||
| `tween-plan.md` | **[2026-08-12 세션, `research/`에서 승격]** 값-레벨 `Tween<T>` 래퍼(PropertyHandler가 소비, 구 특수 bind key 모델은 `archive/tween-special-bind-key-reversed.md`). 3-상태 릴레이션 슬롯(`{Tween,Value}\|true\|nil`), `T'=T\|Tween<T>` 타입 치환. 옵션 값 모양은 `Info: TweenInfo?` 우선+편의 필드 폴백, override는 `Tween.Cancel`(기본)/`Tween.Finish` 2값. `Animate(info)`는 `Tween` opts를 `T\|State<T>`로 받아 `:Apply`로 꽂는 sugar. 자연완료 시 per-instance 북키핑은 정리 안 해도 됨으로 확정(목표값 도달 상태라 부작용 없음, Completed 이벤트 구독 장치는 오버엔지니어링으로 판단). `initValue`는 사용자가 직접 처리(에이전트 범위 제외) |
|
||||
|
||||
## `reference/` — 온디맨드 참고 자료 (2026-08-07 신설)
|
||||
|
|
@ -93,7 +93,7 @@
|
|||
| `onchange-per-property-codegen-rejected.md` | **[기각됨, 2026-08-10 신설]** `OnChange.PropertyName` 프로퍼티별 정적 코드 생성 — Attribute의 정적 지름길과 달리 (클래스 수 × 프로퍼티 수) 규모로 폭발해 기각, `OnChange(name)` 단일 팩토리로 대체 |
|
||||
| `retract-always-fires-reversed.md` | **[역전됨, 2026-08-12 열한 번째 세션 신설]** "핸들러 타입이 안 바뀌면 retract 없이 process가 diff" — 실제로는 `retract`가 store 재발행마다 항상 불림(핸들러 타입 무관). `Tag`/`Ref`/`Slot`/`Attribute` 전부 이 오류 위에서 설계돼 있었음이 드러나 한 세션에 전부 정정 |
|
||||
| `slot-discard-no-portal-reversed.md` | **[역전됨, 2026-08-13 일곱 번째 세션 신설]** Slot의 **"retract = 폐기, 옮기지 않음"(2026-08-04 확정) + "portal은 오버엔지니어링이라 안 함"** — 여섯 번째 세션에 `State<Slot>` 교체가 파괴에서 **언마운트**로 뒤집히며 portal이 별도 기능이 아니라 그 귀결이 됨(`state<Frame>`와 동일한 시맨틱). `base/slot-plan.md`에 히스토리로 남아 있던 세 덩어리(확정 문단 + `State<Slot?>` 왕복 분석 + 포탈 검토와 숙제 셋)를 원문 그대로 이전, 숙제 셋이 각각 어떻게 결말났는지도 정리 |
|
||||
| `question-resolved.md` | **[해소 아카이브, 2026-08-13 여덟 번째 세션 신설]** `question.md`에서 걷어낸 **결정 완료** 항목 전부(당시 32개 `[해소됨]` 마커) — 추가 프리미티브 필요성 라운드, 구현 착수 직전 감사 요약, 확정된 용어들(`State`/`Relate`/`List`/`canBound`/`Ref`/`PreRef`/`Peek`/`isState`/`None`/`Handler`), 포탈·`State<Slot?>` 왕복 해소 등. 분리 직전 전문을 그대로 보존. **`question.md`는 이제 사용자가 답해야 할 것만 담음** — 항목이 해소되면 여기로 옮길 것 |
|
||||
| `question-resolved.md` | **[해소 아카이브, 2026-08-13 아홉 번째 세션 신설]** `question.md`에서 걷어낸 **결정 완료** 항목 전부(당시 32개 `[해소됨]` 마커) — 추가 프리미티브 필요성 라운드, 구현 착수 직전 감사 요약, 확정된 용어들(`State`/`Relate`/`List`/`canBound`/`Ref`/`PreRef`/`Peek`/`isState`/`None`/`Handler`), 포탈·`State<Slot?>` 왕복 해소 등. 분리 직전 전문을 그대로 보존. **`question.md`는 이제 사용자가 답해야 할 것만 담음** — 항목이 해소되면 여기로 옮길 것 |
|
||||
| `checkpoint-handler-pattern-reversed.md` | **[역전됨, 2026-08-13 다섯 번째 세션 신설]** `AttributeGroupHandler`의 이름 소유권 충돌을 고치려고 만든 `Dispatch.processAs`/`Dispatch.retractSelfAndUnder` 체크포인트 핸들러 패턴(같은 날 네 번째 세션 신설) — `chains`를 핸들러 identity가 아니라 재귀 깊이 인덱스로 추적하는 더 근본적인 재설계로 대체되며 같은 날 바로 불필요해짐. `State<State<T>>`도 이 재설계로 UB에서 정상 지원 대상으로 바뀜 |
|
||||
|
||||
## 참고
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# [해소 아카이브] `question.md`에서 걷어낸 결정 완료 항목
|
||||
|
||||
**분리 시점**: 2026-08-13 여덟 번째 세션. 사용자 지적 —
|
||||
**분리 시점**: 2026-08-13 아홉 번째 세션. 사용자 지적 —
|
||||
|
||||
> "question.md 또한, 사람이 봐야하는 문서인데 해결된 것이 많아서 필터해서
|
||||
> 필요한 부분만 읽어보기 힘듦. archive 되어야할 요소는 archive 에
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# gcconn 트릭 — 부분 실측 검증 결과
|
||||
|
||||
**상태**: 부분 확인(2026-08-13). `luau-test/10-roblox-studio-checks.server.luau`의
|
||||
**상태**: 부분 확인(2026-08-13). `10-roblox-studio-checks.server.luau`(`luau-test/not-run/`)의
|
||||
공식 스크립트가 아니라 사용자가 별도로 작성한 저수준 검증 스크립트로
|
||||
확인됨 — `bindLifetime`/`canBound`/`unbindLifetime` 자체의 이중 바인딩
|
||||
로직(A-1/A-2)과 Part B/C는 여전히 미검증. **아래 "아직 확인 안 된 것"이
|
||||
|
|
@ -32,7 +32,7 @@ Studio에서 실행된 사용자 자작 스크립트(공식 `10` 파일이 아
|
|||
트릭과 동일한 신호를 구독, 콜백 클로저가 `target`을 업밸류로 캡처.
|
||||
- Connection을 변수로 안 잡는 경우(Test 1)와 잡는 경우(Test 2) 둘 다 확인.
|
||||
- `triggerGC()`로 GC 완료를 간접 관찰(기법 상세는
|
||||
`luau-test/gc-trigger-helper.server.luau`).
|
||||
`gc-trigger-helper.server.luau`, `luau-test/not-run/`).
|
||||
|
||||
## 확인된 것
|
||||
|
||||
|
|
@ -54,8 +54,8 @@ Studio에서 실행된 사용자 자작 스크립트(공식 `10` 파일이 아
|
|||
|
||||
- **A-1/A-2 (`canBound` 이중 바인딩 게이트, unbind 후 재바인딩 허용)** —
|
||||
`bindLifetime`/`canBound`/`unbindLifetime`/`Subscribed` 로직 자체는
|
||||
이 스크립트에 없음(순수 GC/Connection 메커니즘만 테스트함). `luau-test/
|
||||
README.md`가 명시한 두 번째 "심각한 발견" 트리거 조건(A-2 실패 시
|
||||
이 스크립트에 없음(순수 GC/Connection 메커니즘만 테스트함). `luau-test/README.md`가
|
||||
명시한 두 번째 "심각한 발견" 트리거 조건(A-2 실패 시
|
||||
`canBound`/`unbindLifetime` 설계 재검토)은 미해소 — 공식 `10` 파일을
|
||||
그대로 실행해서 확인해야 함.
|
||||
- **Part B (Attribute의 Instance 참조 타입 지원)**, **Part C
|
||||
|
|
@ -80,7 +80,7 @@ Studio에서 실행된 사용자 자작 스크립트(공식 `10` 파일이 아
|
|||
결론은 이번에 반증됨** — weak-value 테이블에 canary를 넣어두고
|
||||
할당 압력(`table.create` 반복)을 걸며 `task.wait`로 기다리면, incremental
|
||||
GC가 실제로 완료되는 시점을 간접 관찰 가능함(사용자가 이번 검증에서
|
||||
확인). `07`의 docstring과 이 기법 자체는 `luau-test/gc-trigger-helper.server.luau`로
|
||||
확인). `07`의 docstring과 이 기법 자체는 `gc-trigger-helper.server.luau`(`luau-test/not-run/`)로
|
||||
분리해뒀음 — Studio 기반 스파이크(`10` 등)가 GC 완료를 기다려야 할 때
|
||||
그 파일의 `waitForGC`를 그대로 복붙하면 됨.
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ quad는 이제 "스크립트"가 아니라 **라이브러리**다. DOMless Roblo
|
|||
복잡도가 너무 올라간다고 판단 — 당장은 `CollectionService` 그대로 사용. **대신
|
||||
Ref가 도입됨** — 단 Ref의 용도는 "id로 조회"가 아니라 "외부에서 이미
|
||||
관리되고 있는 instance를 quad로 점진적으로 마이그레이션/래핑하기 위해
|
||||
직접 참조를 얻는 것"(`base/bind-system-plan.md`의 Ref 절 참고) — 둘을
|
||||
직접 참조를 얻는 것"(`base/ref-plan.md`의 Ref 절 참고) — 둘을
|
||||
혼동하지 말 것.
|
||||
- **2026-08-04 6차: 네임스페이싱 충돌을 심각하게 안 보는 이유 확정.**
|
||||
충돌을 피해야 하는 단위는 보통 컴포넌트 단위로 나오고, 그 경우는 Ref로
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Bind 시스템 — pluggable key/value 핸들러 (base로 승격됨)
|
||||
|
||||
> **📄 [2026-08-13 여덟 번째 세션] 이 문서는 분할 중입니다 — 1단계 완료.**
|
||||
> **📄 [2026-08-13 아홉 번째 세션] 이 문서는 분할 중입니다 — 1단계 완료.**
|
||||
> 2989줄까지 불어나 사람이 검토할 수 없고 한 곳의 실수가 미치는 범위가
|
||||
> 너무 크다는 사용자 지적으로 쪼개는 중. **1단계로 분리된 것(내용/결정은
|
||||
> 하나도 안 바뀜, 순수 이동)**:
|
||||
|
|
@ -164,8 +164,8 @@ retract 클로저를 반환하는 1-메소드 계약으로 합쳐짐 — 이 절
|
|||
- 모든 핸들러는 대상 **Instance를 직접, 항상** 받는다. quad는 "인스턴스를 생성하고
|
||||
그 인스턴스를 처리하는" 라이브러리다 — 다른 라이브러리가 만든 값(예: Store)을
|
||||
그 인스턴스에 적용하도록 돕는 역할에 가깝다. 그래서 핸들러가 "나중에 생길
|
||||
대상"을 비동기로 기다릴 필요 자체가 없음(아래 Ref 절 참고 — Ref는 다른 이유로
|
||||
존재).
|
||||
대상"을 비동기로 기다릴 필요 자체가 없음(`ref-plan.md`의 Ref 절 참고 — Ref는
|
||||
다른 이유로 존재).
|
||||
- **보강(2026-08-04)**: `inst`가 항상 살아있는 엔진 객체(Roblox Instance)일
|
||||
필요는 없음 — 특정 백엔드에서 실제 엔진 객체 생성/바인딩 비용이 비싸면
|
||||
(예: 웹 DOM) 중간 표현으로 평범한 테이블을 만들고 나중에 그 테이블을
|
||||
|
|
@ -329,8 +329,8 @@ retract 클로저를 반환하는 1-메소드 계약으로 합쳐짐 — 이 절
|
|||
키(프로퍼티/이벤트)를 다른 의미로 취급해야 하니 구분 비용이 이미 드는
|
||||
참에 순서까지 명시적으로 고정하는 게 거의 공짜. **결과적으로 배열
|
||||
슬롯에 놓인 어떤 값(Ref 포함)이든 모든 프로퍼티/이벤트 세팅보다 항상
|
||||
먼저 처리된다는 게 base 자체의 보장**이 됨 — 아래 "Ref 일반화" 절 뒤에
|
||||
이어지는 "PreRef" 절이 이 보장 위에서 성립. **M0 스파이크에서 실제
|
||||
먼저 처리된다는 게 base 자체의 보장**이 됨 — `ref-plan.md`의 "Ref 일반화" 절
|
||||
뒤에 이어지는 "PreRef" 절이 이 보장 위에서 성립. **M0 스파이크에서 실제
|
||||
Luau로 이 순회 동작 자체를 검증할 것**(지금까지 추론/관찰만으로 확정된
|
||||
항목 — `research/pre-implementation-audit.md`가 짚은 "실제 Luau로
|
||||
부딪혀본 적 없는 것" 범주와 같은 급이라 신중하게 다룸).
|
||||
|
|
@ -860,7 +860,7 @@ lazy 생성.
|
|||
`nil`을 넣으면 (1) 그 자리가 "안 채워짐"과 구별이 안 되고 (2) 배열이
|
||||
구멍 나면서 순수 array 취급이 깨져 접근 비용이 올라감(해시 파트로 밀림)
|
||||
— `None`은 실재하는 값이라 자리를 "채워짐"으로 유지시켜줌, PreRef
|
||||
pre-pass 소진 슬롯에 이미 적용된 것과 같은 원칙(위 "PreRef" 절의
|
||||
pre-pass 소진 슬롯에 이미 적용된 것과 같은 원칙(`ref-plan.md`의 "PreRef" 절의
|
||||
"왜 `None`이 아니라 `nil`인가" 참고 — **단, 그 절에서 최종적으로 `nil`로
|
||||
되돌아간 건 Ref 콜백/대기자 배열 한정**이고 `sourceList`/PreRef
|
||||
pre-pass처럼 순서가 실제로 중요하거나 "채워짐 여부"를 엄밀히 구별해야
|
||||
|
|
@ -1098,8 +1098,8 @@ end
|
|||
- **반환하는 클로저가 할 일은 `unbindLifetime(inst, observer)` 호출뿐 —
|
||||
위임 대상까지 수동으로 안 쫓아가도 됨.** `Dispatch.retractFrom`이 자기
|
||||
밑에 위임된 걸 알아서 정리해주므로(위 "Dispatch 체인" 절), 이
|
||||
클로저는 정확히 자기 자신의 자원(Observer)만 정리하면 끝 — 이게 위
|
||||
"이벤트도 store-bind 가능" 절에서 이미 "엔지니어링 비용이 낮다"고
|
||||
클로저는 정확히 자기 자신의 자원(Observer)만 정리하면 끝 — 이게
|
||||
`event-plan.md`의 "이벤트도 store-bind 가능" 절에서 이미 "엔지니어링 비용이 낮다"고
|
||||
서술한 것과 같은 이유(새 디스패치 메커니즘 없이 기존 계약만 구현).
|
||||
**[2026-08-13 다섯 번째 세션] 별도 `Relate`가 더 이상 필요 없음** —
|
||||
`observer`는 `process` 안의 로컬 변수를 반환 클로저가 upvalue로 그대로
|
||||
|
|
@ -1146,14 +1146,14 @@ ref 타입처럼 생각하는 게 맞는 거 같음 — 그걸 처리하는 플
|
|||
의미가 "조용히 UB"도 "즉시 실패"도 아니라 "그냥 정상적으로 동작함"으로
|
||||
다시 한번 바뀜.
|
||||
|
||||
## Ref / PreRef — 전용 문서로 분리됨 (2026-08-13 여덟 번째 세션)
|
||||
## Ref / PreRef — 전용 문서로 분리됨 (2026-08-13 아홉 번째 세션)
|
||||
|
||||
`Ref`/`PreRef`(용도 재정의, `.Value`/`:Set`/`:Callback`/`:Wait` API,
|
||||
`Ref`의 retract, 이중 바인딩 금지, PreRef 호이스팅/1회용 가드)는
|
||||
**`base/ref-plan.md`로 분리**됨 — 이 문서가 3000줄에 육박해 분할한
|
||||
1단계. 내용/결정은 안 바뀜.
|
||||
|
||||
## 이벤트 바인딩 — 전용 문서로 분리됨 (2026-08-13 여덟 번째 세션)
|
||||
## 이벤트 바인딩 — 전용 문서로 분리됨 (2026-08-13 아홉 번째 세션)
|
||||
|
||||
"이벤트 핸들러는 self(Instance)를 받지 않는다"와 "이벤트도 store-bind
|
||||
가능 — `false`로 disconnect" 두 절은 **`base/event-plan.md`로 분리**됨
|
||||
|
|
@ -2243,7 +2243,7 @@ vs `[BooleanAttribute "name"]`)뿐 아니라 `None`/`process`/`retract` 동작
|
|||
동형)가 추가되며, 단일 키 생성자는 이름 충돌 방지로 `AttributeKey<<T>>`로
|
||||
리네임됨.
|
||||
|
||||
## `Brand` — 전용 문서로 분리됨 (2026-08-13 여덟 번째 세션)
|
||||
## `Brand` — 전용 문서로 분리됨 (2026-08-13 아홉 번째 세션)
|
||||
|
||||
런타임 nominal 타입 판별 통합 메커니즘(`Brand.set`/`Brand.get`, `isState`를
|
||||
10종 branded 타입 전부로 일반화)은 **`base/brand-plan.md`로 분리**됨 —
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# `Brand` — 런타임 nominal 타입 판별 통합 메커니즘
|
||||
|
||||
> **[2026-08-13 여덟 번째 세션] `bind-system-plan.md`에서 분리됨.**
|
||||
> **[2026-08-13 아홉 번째 세션] `bind-system-plan.md`에서 분리됨.**
|
||||
> 자기 완결적인 유틸이라 디스패치 코어와 같은 파일에 있을 이유가 없었음.
|
||||
> **내용은 옮기기만 했고 결정은 하나도 안 바뀜.**
|
||||
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ caller가 named parameter 하나에 여러 modifier를 몰아넣고 싶을 때
|
|||
내부는 항상 이미 합쳐진 단일 값만 받으므로 컴포넌트 저작자가 배열 처리를
|
||||
신경 쓸 필요 없음. Ref는 필드 충돌 개념이 없어 이 문제 자체가 없음(여러
|
||||
Ref를 받으면 그냥 전부 실행하면 됨 — Ref 콜백 리스트는 애초에 여러 등록을
|
||||
누적하도록 설계돼 있음, `bind-system-plan.md`의 Ref 콜백/대기자 절) — 별도
|
||||
누적하도록 설계돼 있음, `ref-plan.md`의 Ref 콜백/대기자 절) — 별도
|
||||
결합 유틸 불필요. **정확한 동작(baked 값 교체 경고, 순서 의존성, `Apply`와의
|
||||
역할 구분, `:Peek`/`isState`)은 `base/modifier-plan.md` 9번 절이 최종
|
||||
소스** — `Merge`로 전부 대체해 `Apply`만 강제하는 방안도 이번에 검토했으나,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 이벤트 바인딩 — self 미전달, `false`로 disconnect
|
||||
|
||||
> **[2026-08-13 여덟 번째 세션] `bind-system-plan.md`에서 분리됨.**
|
||||
> **[2026-08-13 아홉 번째 세션] `bind-system-plan.md`에서 분리됨.**
|
||||
> 사용자가 "이벤트 연결은 다른 base 문서가 되어야 할 듯"이라고 직접
|
||||
> 지목한 부분. **내용은 옮기기만 했고 결정은 하나도 안 바뀜.**
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ function bindLifetime(inst, value)
|
|||
local _ = gchold -- 발화 안 함, 클로저 생존이 곧 gchold 생존
|
||||
-- 2026-08-13 부분 실측 확인(미발화 + Destroy 시 Connected 즉시
|
||||
-- 전환) — audit/gcconn-trick-verification.md. canBound 이중
|
||||
-- 바인딩 게이트(A-1/A-2)는 아직 공식 luau-test/10으로 미확인.
|
||||
-- 바인딩 게이트(A-1/A-2)는 아직 공식 10(`luau-test/not-run/`)으로 미확인.
|
||||
end)
|
||||
relate:SetStrong(inst, GCCONN, gcconn)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ self 최상위가 아니라 **내부 저장소**에 써야 함 — 역시 아래
|
|||
> 패턴**이라 실사용에서 바로 터지는 경로임. 해법: 필드 데이터를 유일 테이블
|
||||
> identity 키(`FieldsKey` 등)로 분리된 내부 테이블에 담고, `table.clone`이
|
||||
> 얕은 복사라 setter 안에서 그 내부 테이블도 따로 `table.clone` 할 것.
|
||||
> `luau-test/17`이 이 구조를 실측 검증함(원래 스파이크가 리터럴 키 방식으로
|
||||
> `17`(`luau-test/done/`)이 이 구조를 실측 검증함(원래 스파이크가 리터럴 키 방식으로
|
||||
> 짜여 있다가 바로 이 이유로 크래시했고, 그 과정에서 이 문서의 "데이터를
|
||||
> 테이블에 직접 두고"라는 표현이 두 가지로 읽힌다는 게 드러남). 즉 `:FontSize`/
|
||||
`:Round`/앞으로 생길 어떤 필드 이름이든 전부 이 **하나의 제네릭 `__index`
|
||||
|
|
@ -537,7 +537,7 @@ Modifier 값을 변수/모듈 상수로 만들어 재사용하는, 기존에도
|
|||
### 9-2. `Overridden`가 서로 다른(그러나 상하위 관계인) Modifier 타입을 섞는 경우 —
|
||||
타입 시그니처 미확정 (2026-08-07 다섯 번째 세션 후속)
|
||||
|
||||
**[해소됨, 2026-08-13 첫 실측 라운드]** `luau-test/09-type-modifier-overridden-subtype.luau`로
|
||||
**[해소됨, 2026-08-13 첫 실측 라운드]** `09-type-modifier-overridden-subtype.luau`(`luau-test/done/`)로
|
||||
실측 완료 — 아래에서 우려한 지점이 그대로 재현됨(`Overridden`의 리턴
|
||||
타입 불일치로 서브타입이 깨짐), fallback(`any`)은 정상 작동 확인.
|
||||
"실 Luau 테스트 필요"는 더 이상 유효하지 않음 — 아래는 그 결론에 이른
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Ref / PreRef — 지연 없는 확정 값 박스
|
||||
|
||||
> **[2026-08-13 여덟 번째 세션] `bind-system-plan.md`에서 분리됨.** 그
|
||||
> **[2026-08-13 아홉 번째 세션] `bind-system-plan.md`에서 분리됨.** 그
|
||||
> 문서가 2989줄까지 불어나 사람이 검토하기 어렵고 한 곳의 실수가 미치는
|
||||
> 범위가 너무 커진다는 사용자 지적에 따른 1단계 분할. **내용은 옮기기만
|
||||
> 했고 결정은 하나도 안 바뀜.**
|
||||
|
|
@ -210,6 +210,17 @@ tween-plan.md`도 이에 맞춰 갱신됨). Ref의 진짜 용도는 다름:
|
|||
|
||||
### `Ref`의 retract — `State<Ref>` 재바인드 시 이전 Ref에 `nil` (2026-08-12 여덟 번째 세션, `TagHandler`와 같은 메커니즘 재사용)
|
||||
|
||||
> **⚠️ [2026-08-13 감사 보강] 이 절의 "이전 `process`가 반환한 클로저가
|
||||
> `hintValue`로 먼저 불려 언바인딩하고, 그 다음 `process`가 바인딩"이라는
|
||||
> 서술은 곧 교체될 예정 — 아직 반영 안 됨. `research/dispatch-redispatch-diff-plan.md`가
|
||||
> 폐기 대상으로 지목한 바로 그 **선행 `retractFrom` 호출** 패턴이다 — 이 문서가
|
||||
> `bind-system-plan.md`에서 분리(2026-08-13 아홉 번째 세션, 순수 이동)될
|
||||
> 때 원문이 그대로 옮겨오면서 `bind-system-plan.md`/`tag-plan.md`/
|
||||
> `slot-plan.md`/`attribute-plan.md`가 이미 달고 있는 것과 같은 0-Z
|
||||
> 배너가 같이 안 옮겨졌음. `question.md` **0-Z**(Attribute 이름 소유권)
|
||||
> 해소 시 "하강 diff" 모델대로 이 절도 같이 재작성할 것 — **여기 적힌
|
||||
> 대로 구현하면 옛 모델로 짜게 됨.**
|
||||
|
||||
**배경**: `Ref`는 이미 "일반 프로퍼티/Modifier 필드/Store 값 어디든 자유롭게
|
||||
들어감"(아래 "동적 경로 가드" 절)이 확정돼 있어 — `State<Ref>`가 실제로
|
||||
가능하고, 그러면 Store 값이 `refA`에서 `refB`로 바뀌는 경우가 생김. 이때
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ Handler 계약이 "`process`가 자기 retract 클로저를 반환"으로 바뀌
|
|||
- **정리 조건을 실제 정리와 묶을 것.** `Relate` 엔트리를 지우는 코드가
|
||||
"실제로 물러날 때"라는 조건 **밖**에 있으면, spurious 재발행에서
|
||||
기록만 날아가 dedup이 조용히 무력화됨 — `RefLeafHandler`가 실제로 이
|
||||
버그를 냈음(`bind-system-plan.md` "`Ref`의 retract" 절).
|
||||
버그를 냈음(`ref-plan.md` "`Ref`의 retract" 절).
|
||||
- **weak하다고 "언젠간 알아서 사라진다"에 기대지 말 것.** 값이 `SetWeak`
|
||||
이어도 **언제 사라지는지는 GC 타이밍**이라, 그 전에 같은 키를 다시
|
||||
쓰려는 코드가 비결정적으로 실패함 — `Slot`의 `destroySlotTree`가 자식
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ State를 만족하도록 만들고, RefSource라는 별도 타입은 폐기**하
|
|||
반환**하는 것으로 자연히 갱신됨(위 "타입 추론 문제" 절과 연동).
|
||||
|
||||
**[해소됨, 2026-08-13 첫 실측 라운드]** 핵심 질문(Source가 State를 구조적으로
|
||||
만족하는 제네릭 메소드 체이닝)은 `luau-test/08-type-source-satisfies-state.luau`로
|
||||
만족하는 제네릭 메소드 체이닝)은 `08-type-source-satisfies-state.luau`(`luau-test/review-required/`)로
|
||||
실측 통과 확인됨 — 아래 우려대로 "두 제네릭 타입 별칭이 서로를 참조하는
|
||||
상호 재귀"는 실제로 위험했지만, 그 아래 제안한 단방향 의존(`State`가
|
||||
`Source`를 참조 안 함) 회피책이 그대로 맞아떨어짐. **다만 좁은 잔여
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
> README는 각 파일이 **무엇을 왜 검증하는지**(의도·배경)만 담고, 상태는
|
||||
> **폴더 구조 + STATUS.md**가 소스.
|
||||
|
||||
**[2026-08-13 여덟 번째 세션] 폴더가 곧 상태** — 파일이 평평하게 21개
|
||||
**[2026-08-13 아홉 번째 세션] 폴더가 곧 상태** — 파일이 평평하게 21개
|
||||
쌓여 있어 사람이 "지금 내가 볼 게 뭔지" 못 고르겠다는 사용자 지적으로
|
||||
재편:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 스파이크 상태판 — **폴더가 곧 상태**
|
||||
|
||||
> 마지막 갱신: 2026-08-13 여덟 번째 세션(폴더 재편).
|
||||
> 마지막 갱신: 2026-08-13 아홉 번째 세션(폴더 재편).
|
||||
> 첫 실측은 여섯 번째 세션 — 상세 결과는 `.claude/audit/luau-test-first-run-2026-08-13.md`.
|
||||
> 실행법: `luau <파일>` (런타임) / `luau-analyze <파일>` (타입 전용).
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
실행: `luau 11-modifier-illegal-value-error.luau`
|
||||
]]
|
||||
|
||||
-- ===== Brand 흉내 — 실제로는 base/bind-system-plan.md의 Brand 절이 다루는
|
||||
-- ===== Brand 흉내 — 실제로는 base/brand-plan.md의 Brand 절이 다루는
|
||||
-- weak-key 레지스트리 기반이지만, 이 스파이크에선 태그 필드로 단순화 =====
|
||||
|
||||
local function tag(name)
|
||||
|
|
@ -305,7 +305,7 @@ end
|
|||
3. B에서 Slot 같은 "Modifier가 아닌 다른 핸들러 계층 값"은 State/Source에
|
||||
여전히 자유롭게 들어갈 수 있는가(Modifier만의 예외라는 걸 재확인).
|
||||
4. 이 스파이크는 Brand/isState를 태그 필드로 단순화한 것 — 실제 구현은
|
||||
base/bind-system-plan.md의 weak-key 레지스트리 기반 Brand를 씀,
|
||||
base/brand-plan.md의 weak-key 레지스트리 기반 Brand를 씀,
|
||||
여기선 그 판별 로직 자체가 아니라 "체크 지점 배치가 실제로 동작하는가"만
|
||||
검증 대상.
|
||||
]]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
이제 `isHandlable = isRef(v) and not isPreRef(v)`로 **명시적으로
|
||||
좁혀야만** PreRef를 잘못 삼키지 않는다는 것.
|
||||
|
||||
배경: .claude/base/bind-system-plan.md의 `Brand` 절
|
||||
배경: .claude/base/brand-plan.md의 `Brand` 절
|
||||
("isRef(x)는 그 위에 Brand.get(x)==RefTag를 OR로 얹은 상위 개념")와
|
||||
"`(v=Ref)` children 배열 leaf 매치 핸들러... isRef(v) and not
|
||||
isPreRef(v)로 명시적으로 좁혀야 함" 부분.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 확인/결정 필요 목록
|
||||
|
||||
**이 문서는 사용자가 답해야 할 것만 담습니다.** 이미 결정이 끝난 항목은
|
||||
2026-08-13 여덟 번째 세션에 `archive/question-resolved.md`로 옮겼음 —
|
||||
2026-08-13 아홉 번째 세션에 `archive/question-resolved.md`로 옮겼음 —
|
||||
"해결된 게 너무 많아 필요한 부분만 읽기 어렵다"는 사용자 지적에 따른 것.
|
||||
결정 내용은 안 바뀌었고 읽는 자리만 옮겼으니, 어떤 항목이 왜 그렇게
|
||||
정해졌는지 되짚고 싶으면 그 문서를 볼 것(지금 유효한 설계 자체는 항상
|
||||
|
|
@ -241,6 +241,13 @@ Attribute가 직접 해야 함.**
|
|||
엘비스 연산자류) 후보 추가 — Haskell 비교 리서치 중 나옴, 카탈로그 확정
|
||||
규칙에 그대로 맞아 포함 근거는 있음. 상세는 `research/operator-sugar-plan.md`.
|
||||
구현 자체는 맨 마지막 우선순위(순수 슈가, 없어도 무방) — 여전함.
|
||||
- **중첩 State 평탄화 `State<State<T>>` → `State<T>`(2026-08-13 여섯 번째
|
||||
세션 신설, 백로그)** — 인덱스 기반 `Dispatch` 재설계로 `State<State<T>>`는
|
||||
UB에서 정상 지원 대상이 됐지만, 깊이가 늘수록 `retractFrom`의 힌트가
|
||||
더 깊은 인덱스엔 `nil`로 전달돼 `Tag`/`Ref`/`Slot` 등의 힌트 기반
|
||||
최적화(깜빡임 방지)가 무력화되는 실제 기능 손실이 있음 — 값 층에서
|
||||
평탄화하는 `state:Flatten()`류 콤비네이터 아이디어는 나왔으나 착수 안
|
||||
함. 상세는 `research/operator-sugar-plan.md` 마지막 절.
|
||||
- `research/existing-instance-bind-plan.md` — 스코프 논의만 필요, 구현
|
||||
착수를 막지 않음.
|
||||
- **`quad-debug` 세부 API 이름** — `research/debug-tooling-plan.md` 참고.
|
||||
|
|
@ -248,7 +255,7 @@ Attribute가 직접 해야 함.**
|
|||
넘는지)까지 사용자가 Studio에서 직접 실측 검증 완료 — 기술적 불확실성은
|
||||
다 해소됨, 남은 건 세부 API 이름뿐("이벤트 함수가 self로 instance를
|
||||
읽는 게 quad 관습"이라는 언급은 2026-08-06 후속 세션에서 해소 —
|
||||
채택 안 함으로 확정, `base/bind-system-plan.md` "이벤트 핸들러는
|
||||
채택 안 함으로 확정, `base/event-plan.md` "이벤트 핸들러는
|
||||
self(Instance)를 받지 않는다" 절 참고). 사용자가 "quad 개발 완료 전엔
|
||||
착수 못 함"으로 직접 후순위 지정한 건 여전함 — base 설계(M2 Dispatch/
|
||||
M3 Source/M5 DI 생성자) 시점에 훅 확장 지점만 고려해두면 됨.
|
||||
|
|
|
|||
|
|
@ -251,6 +251,11 @@ Dispatch.process(inst, k, realv, index + 1) -- retractFrom 선행 호출 없
|
|||
M6의 "`SlotHandler.process`는 claim 실패 시에도 파괴적 클로저를
|
||||
반환해야 함")이 선행 `retractFrom` 전제로 쓰여 있음 — base 4개를
|
||||
옮길 때 같이 갱신하고 배너를 걷을 것.
|
||||
- **[2026-08-13 감사에서 추가]** `ref-plan.md` — `bind-system-plan.md`
|
||||
1단계 분할(2026-08-13 아홉 번째 세션, 순수 이동) 때 "`Ref`의 retract"
|
||||
절이 옮겨오면서 선행 `retractFrom` 호출 서술도 그대로 딸려왔음. 분할
|
||||
당시 이 문서(section 6, 당시 아직 안 쓰임)가 없어 배너가 안 붙었던
|
||||
것 — 반영 시 나머지 6개와 같이 재작성하고 배너 걷을 것.
|
||||
|
||||
- **[2026-08-13 8차 감사에서 추가] 같은 패스에서 `bind-system-plan.md`
|
||||
2단계 분할도 할 것** — 이 문서가 지시하는 재작성 범위(핸들러 계약 /
|
||||
|
|
@ -259,6 +264,6 @@ Dispatch.process(inst, k, realv, index + 1) -- retractFrom 선행 호출 없
|
|||
전면 재작성하므로, **재작성하면서 새 파일로 옮기면 인바운드 참조
|
||||
(~37곳)를 한 번만 고치면 됨.** 따로 하면 같은 곳을 두 번 만짐.
|
||||
|
||||
**요약**: 배너를 달고 있는 파일 = 반영 대상. 위 6개(`bind-system-plan`/
|
||||
`tag-plan`/`slot-plan`/`attribute-plan`/`architecture`/`ROADMAP`)가
|
||||
전부이고, 반영이 끝나면 각 파일의 ⚠️ 배너도 같이 제거할 것.
|
||||
**요약**: 배너를 달고 있는 파일 = 반영 대상. 위 7개(`bind-system-plan`/
|
||||
`tag-plan`/`slot-plan`/`attribute-plan`/`architecture`/`ROADMAP`/
|
||||
`ref-plan`)가 전부이고, 반영이 끝나면 각 파일의 ⚠️ 배너도 같이 제거할 것.
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ M7의 전제가 Luau 공식 동작대로 성립함. 별도로, 프로퍼티에 A
|
|||
### 2-1. Source가 State를 만족하는 제네릭 검증이 실패했을 때의 대안(Plan B)이 전혀 없음
|
||||
|
||||
**[해소됨, 2026-08-13 첫 실측 라운드]** 검증 자체는
|
||||
`luau-test/08-type-source-satisfies-state.luau`로 실행돼 핵심 질문(Source가
|
||||
`08-type-source-satisfies-state.luau`(`luau-test/review-required/`)로 실행돼 핵심 질문(Source가
|
||||
State를 구조적으로 만족)이 통과했음 — 아래 "검증이 실패했을 때"라는
|
||||
전제 자체가 (핵심 케이스에 한해) 더 이상 미래형이 아님. 다만 통과와
|
||||
별개로 좁은 잔여 케이스(`State<T>`가 자기 자신을 다른 타입 인자로
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
compat.lua나 어댑터 코드는 전혀 없고, README/커밋 메시지에도 "왜 포기했는지"
|
||||
단서가 없음 — 애초에 착수된 적이 없다는 뜻.
|
||||
|
||||
→ `question.md:110`이 "OOP 상속/커스텀 파서/Slot 스텁/`Pipe` COW는 확인된
|
||||
죽은 접근"이라고 명시한 목록에 compat은 **포함돼 있지 않음**(정확한 서술).
|
||||
→ `archive/question-resolved.md`가 "OOP 상속/커스텀 파서/Slot 스텁/`Pipe` COW는
|
||||
확인된 죽은 접근"이라고 명시한 목록에 compat은 **포함돼 있지 않음**(정확한 서술).
|
||||
즉 CLAUDE.md의 "반복 조사 금지"는 compat에는 적용되지 않는다 — 이 문서를
|
||||
쓰는 게 규칙 위반이 아님.
|
||||
|
||||
|
|
@ -242,8 +242,9 @@ v2 트리 안에 과거 v1 컴포넌트를 리프로 박아넣는 것, (B) 기
|
|||
"직접 Destroy 금지, Unmount 경유" 규칙을 Dispatch 엔진의 어느 지점에
|
||||
훅으로 강제할지도 Slot 실제 구현 시점 확인 필요.
|
||||
- **결론: 지금 결정 불가.** M0 이후 Slot 코어 로직 구현 라운드
|
||||
(`question.md`의 "여러 Slot이 형제로 섞일 때 순서 보장" 항목과 같은
|
||||
시점)에서 이 두 가지를 실제 구현과 함께 재확인해야 함.
|
||||
(`archive/question-resolved.md`의 "여러 Slot이 형제로 섞일 때 순서 보장"
|
||||
항목과 같은 시점 — 이미 해소돼 아카이브로 옮겨졌으나 실제 구현 시점의
|
||||
참고 자료로는 여전히 유효)에서 이 두 가지를 실제 구현과 함께 재확인해야 함.
|
||||
|
||||
## 8. 남은 확인 사항 (추가 리서치 후보, 지금 결정 불필요)
|
||||
|
||||
|
|
|
|||
125
.claude/session/2026-08-13-10-corpus-audit-parallel-agents.md
Normal file
125
.claude/session/2026-08-13-10-corpus-audit-parallel-agents.md
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
# 2026-08-13 열 번째 세션 — 병렬 에이전트 코퍼스 감사, 실제 부정확성 7건 발견·수정
|
||||
|
||||
## 배경
|
||||
|
||||
사용자가 "세션 기록들을 전부 읽어보며 문서 전체에 문제가 되는 부분이
|
||||
있는지" 요청 — 단, 미확정 항목(0-Y/0-Z 등)은 문제로 세지 말고 **문서가
|
||||
실제로 부정확한 것만** 짚어달라는 조건. 직전 세션(아홉 번째)이 `luau-test/`
|
||||
상태별 폴더 재편, `bind-system-plan.md` 1단계 분할, `question.md` 트림,
|
||||
`doc-check.py` 신설을 한 번에 처리한 큰 구조 변경 세션이었기 때문에, 그
|
||||
변경들의 반영 누락이 남아있을 가능성이 가장 높은 지점으로 판단.
|
||||
|
||||
## 방법
|
||||
|
||||
1. 먼저 `python3 .claude/tools/doc-check.py`로 기계가 잡는 것부터 확인 —
|
||||
ERROR 0, WARN 60건은 전부 기존에 허용 범위로 확인된 것(패러프레이즈
|
||||
인용, 이미 날짜/범위가 명시된 완결 주장)이라 새 이슈 없음.
|
||||
2. 기계가 못 잡는 의미론적 문제를 6개 병렬 Explore 에이전트로 분담
|
||||
(CLAUDE.md "작업 방식"의 병렬 Agent 원칙 그대로):
|
||||
- A: `bind-system-plan.md` 분할(9차 세션) 정합성
|
||||
- B: `luau-test/` 폴더 재편(9차 세션) 정합성
|
||||
- C: `question.md` 트림(9차 세션) 정합성
|
||||
- D: 배너 달린 base 4종(`bind-system-plan`/`tag`/`slot`/`attribute`)
|
||||
정밀 감사 — 배너 범위 밖 서술이 다른 최근 결정과 모순되는지
|
||||
- E: 나머지 base 16개 문서 전수 — retract-always-fires/
|
||||
`State<State<T>>`/인덱스 기반 chains/Slot 언마운트 전환/and·or
|
||||
금지 등 최근 결정 위반 여부
|
||||
- F: 루트 문서(`ROADMAP.md`/`HUMAN_TODO.md`/`.claude/README.md`)와
|
||||
`archive/` 정합성, 0-Y/0-Z 게이트 표시 여부
|
||||
3. 각 결과를 실시간으로 검토하며 발견 즉시 직접 수정(에이전트에 위임
|
||||
안 함 — CLAUDE.md "중대 변경 핸드오버 체크리스트"의 "그 자리에서
|
||||
닫을 것" 원칙).
|
||||
|
||||
## 발견 및 수정
|
||||
|
||||
**1. `luau-test/` 재편 후 깨진 flat 경로 참조** — `research/
|
||||
pre-implementation-audit.md`, `base/store-semantics.md`,
|
||||
`base/modifier-plan.md`(2곳), `base/lifecycle-pattern.md`,
|
||||
`.claude/README.md`, `audit/gcconn-trick-verification.md`(4곳)가 옛
|
||||
`luau-test/08-...`/`/09-...`/`/10`/`/17`/`/gc-trigger-helper...` 경로를
|
||||
그대로 참조 — 실제 파일은 `done`/`review-required`/`not-run` 하위로
|
||||
이동해 전부 깨진 링크였음. 파일명+실제 소속 폴더 표기로 정정(경로
|
||||
대신 파일명 참조라는 9차 세션 원칙 준수).
|
||||
|
||||
**2. `bind-system-plan.md` 분할 후 참조 정합성 깨짐**:
|
||||
- 분할된 문서 **자기 자신** 안의 "아래 Ref 절"/"위 PreRef 절"/"위
|
||||
이벤트 절" 같은 위치 참조 4곳(167/332/863/1102줄)이 실제로 이동된
|
||||
절을 못 따라감 — "순수 이동"이 텍스트 상호참조까지는 보장 못 한다는
|
||||
사례.
|
||||
- 외부 문서(`architecture.md`/`relate-plan.md`/
|
||||
`component-composition-plan.md`/`question.md`)와 luau-test 파일 2개가
|
||||
여전히 `bind-system-plan.md`의 Ref/Brand 절을 가리킴 — 전부
|
||||
`ref-plan.md`/`event-plan.md`/`brand-plan.md`로 정정.
|
||||
- **가장 중요한 발견**: `ref-plan.md`의 "`Ref`의 retract" 절이 옛
|
||||
재디스패치 모델(선행 `retractFrom` 호출)을 그대로 서술하는데, 분할
|
||||
때 다른 4개 base 문서가 이미 달고 있던 0-Z ⚠️ 배너가 안 옮겨와 있었음
|
||||
— 이 상태로 구현하면 옛 모델로 짜일 위험. `research/
|
||||
dispatch-redispatch-diff-plan.md` 6절 검토로 실제 대상 메커니즘이
|
||||
맞는지 교차검증 후(단순 키워드 매치가 아니라 "선행 호출 후 process"
|
||||
패턴이 정확히 일치함을 확인) 같은 형식의 배너 추가, 반영 대상을
|
||||
6개→**7개**로 `dispatch-redispatch-diff-plan.md`/`CLAUDE.md` 양쪽 갱신.
|
||||
|
||||
**3. 세션 번호 오기(8차→9차) 대량 발견** — `bind-system-plan.md` 분할/
|
||||
`luau-test/` 재편/`question.md` 트림/`tools/` 신설이 실제로는 전부
|
||||
**9차 세션**(`session/2026-08-13-09-structure-and-guardrails.md`) 작업인데,
|
||||
git 커밋 타임스탬프로 교차검증한 결과 총 17곳(`.claude/README.md` 4곳,
|
||||
`question.md`, `archive/question-resolved.md`, `luau-test/STATUS.md`,
|
||||
`luau-test/README.md`, `base/ref-plan.md`/`event-plan.md`/
|
||||
`brand-plan.md`/`bind-system-plan.md`의 분할 배너 6곳, `doc-check.py`
|
||||
자기 설명 2곳)가 "8차 세션"으로 잘못 표기돼 있었음(같은 날 2026-08-07의
|
||||
진짜 8차 세션과 혼동된 것으로 추정) — 전부 정정.
|
||||
|
||||
**4. `question.md` 트림 중 열린 질문 하나 누락** — `State<State<T>>`
|
||||
평탄화(`state:Flatten()`) 백로그 항목이 `research/
|
||||
operator-sugar-plan.md`엔 있는데 트림된 `question.md`에서 빠져 있었음 —
|
||||
3번 절(낮은 우선순위)에 복원.
|
||||
|
||||
**5. 트림 후 깨진 참조** — `research/v1-compat-plan.md`가 이미
|
||||
`archive/question-resolved.md`로 옮겨진 "여러 Slot이 형제로 섞일 때
|
||||
순서 보장" 항목을 옛 `question.md:110` 경로로 가리키고 있었음(그
|
||||
줄번호도 트림 후 빈 줄이 됨) — 2곳 정정.
|
||||
|
||||
**6. `ROADMAP.md`의 M0 섹션에 0-Y/0-Z 게이트 표시 누락** — M2/M4/M6/M10엔
|
||||
"0-Z 먼저 해소할 것" 배너가 있는데, 정작 M0 자체가 두 결정에 막혀
|
||||
있다는 사실이 서두/M0 섹션 어디에도 안 적혀 있었음(`HUMAN_TODO.md`/
|
||||
`CLAUDE.md`/`question.md`는 이미 정확히 서술 중이었음 — `ROADMAP.md`만
|
||||
누락) — M0 섹션 시작 부분에 게이트 배너 추가.
|
||||
|
||||
## 문제 없음으로 확인된 것
|
||||
|
||||
배너 달린 4개 base 문서의 배너 **범위 자체**는 정확 — 배너 밖 서술
|
||||
(retract 항상 호출, `State<State<T>>` 정상 지원, 인덱스 기반 `chains`,
|
||||
Slot 언마운트 전환, `and`/`or` 금지)은 전부 최신 결정과 일치, 모호해서
|
||||
독자를 오도할 소지 없음. 나머지 base 16개 문서, `HUMAN_TODO.md`,
|
||||
`luau-test/STATUS.md`의 상태 표는 실측과 정합. `question.md`/
|
||||
`question-resolved.md` 사이 항목 재분류 오류나 번호 충돌 없음.
|
||||
|
||||
## 교훈
|
||||
|
||||
- **"순수 이동"이라고 선언해도 상호참조 검증은 별도로 필요** —
|
||||
bind-system-plan.md 분할이 "내용은 안 바꿈"을 지켰어도, 그 내용이
|
||||
참조하던 방향(위/아래, 같은 파일 안 절 이름)과 그 내용을 참조하던
|
||||
외부 문서 양쪽 다 별도로 grep 전수 스윕이 필요했음. 이번엔 doc-check.py가
|
||||
없던 시절 방식(agent가 직접 정독)으로 잡았지만, doc-check.py의 절
|
||||
참조 검사가 왜 이 6곳을 못 잡았는지도 짚어둘 것 — "Ref 절"처럼 헤딩
|
||||
전체가 아니라 **파일명이 함께 안 적힌** 참조는 정규식이 "그 파일
|
||||
안에 있다"고 가정하고 검사하므로, 파일명 없는 방향 참조(아래/위)
|
||||
자체가 애초에 이 검사의 사각지대. 파일을 쪼갤 땐 grep으로 "아래/위
|
||||
OO 절"류 방향 참조부터 훑는 걸 체크리스트에 추가할 가치 있음.
|
||||
- **배너가 파일 단위로 붙어있으면, 그 파일에서 분할된 새 파일에
|
||||
배너 대상 내용이 섞여 있는지 별도 확인이 필요** — `ref-plan.md`
|
||||
사례처럼, 분할 시점에 배너 자체를 "옮길지 말지"를 판단할 근거
|
||||
문서(`dispatch-redispatch-diff-plan.md`)가 그 새 파일을 아직 몰랐던
|
||||
경우 특히 위험.
|
||||
- **날짜/세션 번호는 한 번 잘못 적히면 복붙되며 퍼진다** — 이번
|
||||
17곳도 대부분 서로를 참고하며 같은 오기를 반복한 것으로 보임(README
|
||||
색인이 base 파일 배너를 그대로 요약하는 식). 세션 번호는 가능하면
|
||||
파일명(`session/YYYY-MM-DD-NN-slug.md`)에서 기계적으로 뽑아 쓰는 게
|
||||
안전.
|
||||
|
||||
## 반영 상태
|
||||
|
||||
base/README/question.md/archive/ROADMAP/CLAUDE.md/tools/ 전부 이 세션
|
||||
안에서 즉시 반영 완료 — 24개 파일 수정, `doc-check.py` ERROR 0 유지
|
||||
확인. 새로 연 설계 질문 없음(전부 기존 서술 정합성 문제), 0-Y/0-Z 상태
|
||||
불변.
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
검사 항목
|
||||
1. [ERROR] 깨진 파일 참조 — 라이브 문서가 가리키는 .md/.luau가 실제로 없음
|
||||
2. [ERROR] 깨진 절 참조 — `foo.md` "절 제목" 이 그 파일에 없음
|
||||
(문서를 쪼개거나 헤딩을 고칠 때 가장 잘 깨지는 것 — 여덟 번째 세션에
|
||||
(문서를 쪼개거나 헤딩을 고칠 때 가장 잘 깨지는 것 — 아홉 번째 세션에
|
||||
bind-system-plan.md를 분할하며 20곳이 여기 걸렸음)
|
||||
3. [ERROR] 색인 누락 — base/research/archive/reference 파일이 README에 없음
|
||||
4. [WARN] 날짜 없는 시한부 주장 — "아직 안 돌려봄", "열린 질문 없음" 등
|
||||
|
|
|
|||
20
CLAUDE.md
20
CLAUDE.md
|
|
@ -183,9 +183,11 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션
|
|||
새 모델은 `research/dispatch-redispatch-diff-plan.md`에만 있음 —
|
||||
base만 읽고 구현하면 옛 모델로 짜게 됨. 0-Z가 정해지면 그 문서 6절의
|
||||
파일별 반영 목록대로 **한 번에** 옮길 것 — 대상은 ⚠️ 배너를 달고
|
||||
있는 **6개**(`bind-system-plan.md`/`tag-plan.md`/`slot-plan.md`/
|
||||
있는 **7개**(`bind-system-plan.md`/`tag-plan.md`/`slot-plan.md`/
|
||||
`attribute-plan.md` + **`architecture.md`/`ROADMAP.md`** — 뒤 둘은
|
||||
2026-08-13 7차 감사에서 6절 목록에 빠져 있던 걸 발견해 추가),
|
||||
2026-08-13 7차 감사에서 6절 목록에 빠져 있던 걸 발견해 추가 +
|
||||
**`ref-plan.md`** — 9차 세션 분할 때 "`Ref`의 retract" 절이 배너
|
||||
없이 옮겨간 걸 이번 감사에서 발견해 추가),
|
||||
반영 후 각 배너도 같이 제거.
|
||||
- 반대로 **`base/slot-plan.md`의 "언마운트/`dispose`/해제 순서"는 이미
|
||||
확정 반영됨**(재디스패치 모델과 독립적인 결정이라 먼저 들어감).
|
||||
|
|
@ -1020,3 +1022,17 @@ Slot 언마운트 전환 미반영 6곳. 뒤집힌 "폐기, 옮기지 않음 + p
|
|||
누락, 날짜 없는 시한부 주장, 미반영 배너). **같은 세션에 실효 증명**: 분할
|
||||
중 "이중 바인딩 금지" 절 참조 4곳을 잘못 옮긴 걸 스크립트가 잡아내 되돌림.
|
||||
CLAUDE.md "작업 방식"에 중대 변경 핸드오버 체크리스트 6단계도 명문화.
|
||||
|
||||
**2026-08-13 열 번째 세션 — 병렬 에이전트 코퍼스 감사, 실제 부정확성 7건**
|
||||
(`session/2026-08-13-10-corpus-audit-parallel-agents.md`)
|
||||
사용자 요청으로 세션 기록 대조 전수 감사(미확정 항목은 문제로 안 셈,
|
||||
`doc-check.py` 선실행 후 기계가 못 잡는 것만 6개 병렬 Explore 에이전트로
|
||||
분담). 아홉 번째 세션의 구조 변경(폴더 재편/분할/트림) 반영 누락이
|
||||
대부분: luau-test 재편 후 깨진 flat 경로 참조 9곳, `bind-system-plan.md`
|
||||
분할 후 자기참조/외부참조 깨짐 8곳, **`ref-plan.md`에 0-Z 배너가 안
|
||||
옮겨와 옛 재디스패치 모델을 무배너로 서술 중이던 것**(반영 대상
|
||||
6개→7개로 정정), "8차 세션"으로 잘못 표기된 9차 세션 작업 17곳(git
|
||||
커밋 타임스탬프로 교차검증), `question.md` 트림 중 빠진 열린 질문 1건,
|
||||
트림 후 깨진 참조 2곳, `ROADMAP.md` M0 섹션의 0-Y/0-Z 게이트 표시 누락.
|
||||
발견 즉시 24개 파일에 직접 반영, `doc-check.py` ERROR 0 유지 확인. 새로
|
||||
연 설계 질문 없음.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@ quad-v2 구현 단계 실행 계획. 설계 근거/아키텍처 자체는 여기
|
|||
확정될 때마다 각 마일스톤 체크박스가 계속 갱신돼왔음 — 그래도 아직 M0
|
||||
자체는 시작 안 함.** 다음 세션은 바로 M0부터.
|
||||
|
||||
> **⚠️ M0 착수 자체가 두 결정으로 막혀 있음 — `.claude/question.md` 0-Y
|
||||
> (`:Compute(fn)` lazy 핸들 계약과 Luau 타입 추론 충돌)/0-Z(Attribute
|
||||
> 이름 소유권). 둘 다 "M0 착수 전에 정할 것"으로 명시돼 있음 —
|
||||
> `HUMAN_TODO.md` 4번, `CLAUDE.md` "지금 할 일" 0번 항목 참고. 아래
|
||||
> M0 체크리스트 자체는 이 두 결정과 무관하게 유효하지만, 순서상 이
|
||||
> 둘이 먼저.**
|
||||
|
||||
## M0 — 스켈레톤 + 기술검증 (스파이크, "진짜" 마일스톤 아님)
|
||||
|
||||
최종 소스 트리를 그대로 만들기 전에, 지금까지 **추론만으로 확정하고 실제
|
||||
|
|
|
|||
Loading…
Reference in a new issue