From 500ae298aa0b934478db0539a5ad9ef5a7306209 Mon Sep 17 00:00:00 2001 From: qwreey Date: Fri, 28 Aug 2026 20:40:21 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EB=8B=A8=EC=9C=84=202=20=EA=B0=90?= =?UTF-8?q?=EC=82=AC=201=EB=9D=BC=EC=9A=B4=EB=93=9C=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20=E2=80=94=20H-176=20=EC=8B=A4=EC=B8=A1=20=EC=A0=84=20?= =?UTF-8?q?=EC=84=9C=EC=88=A0=20=ED=91=9C=EC=8B=9C(ROADMAP=C2=B7source-sta?= =?UTF-8?q?te-plan),=20STATUS=20=EC=8A=A4=ED=8C=8C=EC=9D=B4=ED=81=AC=2015?= =?UTF-8?q?=20=ED=8F=90=EA=B8=B0=C2=B7=5Fhold=20=EC=8A=A4=ED=8C=8C?= =?UTF-8?q?=EC=9D=B4=ED=81=AC=20=EB=8B=AB=ED=9E=98,=20state-epoch=20=C2=A7?= =?UTF-8?q?8=20=EB=8B=A4=EC=9D=B4=EC=95=84=EB=AA=AC=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=8C=8C=EC=9D=B4=ED=81=AC=20=EB=8B=AB=ED=9E=98,=20H-84=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=99=84=EB=A3=8C=20=ED=91=9C=EA=B8=B0=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qwreey --- .claude/base/source-state-plan.md | 5 +++-- .claude/base/state-epoch-plan.md | 4 ++++ .claude/luau-test/STATUS.md | 4 ++-- ROADMAP.md | 6 ++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.claude/base/source-state-plan.md b/.claude/base/source-state-plan.md index 8497804..8b52e65 100644 --- a/.claude/base/source-state-plan.md +++ b/.claude/base/source-state-plan.md @@ -780,8 +780,9 @@ Tag/Modifier의 클론은 호출 즉시 결과가 확정되는 값이라 "-ed"( > **[2026-08-13 열세 번째 세션, 해소]** 이 절이 얹혀 있던 "self도 lazy > 핸들로 통일" 계약(구 `question.md` 0-Y)이 **그대로 유지로 확정**됨 — > 전제가 안 흔들리므로 이 절의 결론도 유효. 다만 이 절이 남겨둔 실측 -> 항목(이형 다중 deps를 제네릭 팩으로 표현 가능한지)은 **여전히 -> 미검증**임: 그 스파이크(`15`)가 파싱 실패 상태라 재작성이 필요하고, +> 항목(이형 다중 deps를 제네릭 팩으로 표현 가능한지)은 **[2026-08-28 해소, +> 아래 `H-176` 문단 — 안 된다, deps 자리는 `...any`]** 이 배너 시점(2026-08-13)엔 +> 미검증이었다: 그 스파이크(`15`)가 파싱 실패 상태라 재작성이 필요했고, > 재작성해도 반환 타입 쪽은 `base/typing-limits.md` 1번 한계에 똑같이 > 걸림(명시 주석 바인딩으로 대응). diff --git a/.claude/base/state-epoch-plan.md b/.claude/base/state-epoch-plan.md index 4157be2..678018d 100644 --- a/.claude/base/state-epoch-plan.md +++ b/.claude/base/state-epoch-plan.md @@ -533,6 +533,10 @@ State 층 dedup이 못 닫던 갭이다 — `Effect`가 자기 맵을 들면 그 걸려 정상화된다 — 별도 조치가 필요 없다. - **`luau-test` 스파이크 하나**: §1의 다이아몬드를 그대로 짜서 (a) 리비전 비교 없이는 섞인 값이 실제로 관측되는지, (b) 비교를 넣으면 사라지는지 대조. + **[2026-08-28 (b)는 닫힘]** M2 단위 2의 `quad-base/test/spec.state.luau` 3번이 실제 + 구현에서 다이아몬드 두 번째 도착이 규칙 3으로 삼켜지고 조인 노드가 한 번만 + 계산되는 것을 고정한다. (a)의 음성 대조군은 따로 짜지 않았다 — 구현이 비교 + 없는 경로를 갖지 않는다. - **기각된 대안 — 게이트를 에포크 경계로.** 게이트가 **자기 자신을 하나의 `Epoch`로** 내세우고(자기 `Revision`은 유보를 풀 때만 갱신) 하류가 상류 원천 대신 **그 게이트만** 추적하게 하는 안. 배치를 나를 필요가 없어져 diff --git a/.claude/luau-test/STATUS.md b/.claude/luau-test/STATUS.md index 5a24c56..71e65ac 100644 --- a/.claude/luau-test/STATUS.md +++ b/.claude/luau-test/STATUS.md @@ -148,7 +148,7 @@ | `05-store-state-diamond-propagation.luau` | 2026-08-19 재작성분은 그 시점 모델 기준 ✅ 통과였음 | **[2026-08-21] 모델이 또 바뀌었다** — 소스 에포크 비교 채택(`base/state-epoch-plan.md`)으로 다이아몬드에서 **두 번째 통지가 접힌다**. 그래서 이 스파이크의 핵심 assert("`:Get()`을 안 부르는 Observer가 변경당 경로 수(2)만큼 운다")가 **정반대**가 됐다 — 이제 **변경당 1회**여야 한다. **살릴 것**: `invalid` 기반 dedup이면 두 번째 변경부터 침묵하는 것을 잡는 음성 대조군(그 금지는 지금도 유효). **새로 넣을 것**: DFS 도중 `Get()`이 섞인 값을 캐시하던 glitch가 에포크로 사라지는지(그 문서 §1의 시나리오) | | `04-dispatch-chain-retractFrom.luau` | 옛 모델 기준으로는 ✅ 통과였음 | (1) `chains` 슬롯이 `{handler, retractor}`가 되고 `Dispatch.process`가 핸들러를 먼저 비교하는 **하강 diff**로 재작성, (2) `retractFrom`은 **3-인자**(힌트 인자 없음), (3) "힌트가 target 인덱스에만 간다"를 검증하던 부분은 **정반대**로 뒤집힘 — 이제 각 레벨이 자기 값을 받는지를 검증해야 함. **살릴 것**: `chains:SetStrong` 순서 음성 대조군(그 버그는 새 모델에서도 그대로 유효) | | `19-ownership-refcount-relate-patterns.luau` | A/C ✅ 유효, **B 섹션이 낡음** | B가 검증하던 "공개 `AttributeKey(name)` + 인덱스 1 점유 체크"가 폐기됨 — **그룹 전용 키 + `AttributeKeyHandler`의 이름 claim**으로 재작성하고, 음성 대조군도 "두 그룹이 같은 이름 → 즉시 error", "그룹↔직접 쓰기 → 즉시 error"로 바꿀 것(0-Z 확정 내용). A/C는 손댈 것 없음 | -| `15-type-compute-trailing-deps-typepack.luau` | **파싱 실패**(SyntaxError) | 음성 대조군의 타입 표기가 `TypeError`가 아니라 `SyntaxError`로 걸려 **파일 전체가 아무것도 검증 못 함** — 대조군을 별도 파일/블록으로 격리 | +| `15-type-compute-trailing-deps-typepack.luau` | **[2026-08-28 폐기 — 재작성 안 함]** M2 단위 2가 실제 `quad-types` 선언에서 타입팩 형태를 실측해 기각했다(`round11.md` `H-176`: strict에서 콜백 dep 추론이 깨져 정상 호출까지 막힘 → deps 자리 `...any`). 이 스파이크가 물으려던 (B)의 답이 나왔으므로 파일은 역사로만 남긴다. 아래는 폐기 전 상태: **파싱 실패**(SyntaxError) | 음성 대조군의 타입 표기가 `TypeError`가 아니라 `SyntaxError`로 걸려 **파일 전체가 아무것도 검증 못 함** — 대조군을 별도 파일/블록으로 격리 | | `22-runtime-ref-preref-postref-brand.luau` | 옛 `Brand` API 기준으로는 ✅ 통과였음 | **[2026-08-21] `Brand`가 인스턴스 브랜드로 재작성됨** — 파일 안의 `Brand.set(x, tag)`/`Brand.get(x)`/`XxxTag` 변수를 `Brand()` + `SomeBrand:register(x)`/`SomeBrand:is(x)`로 바꿔 쓸 것(`base/brand-plan.md`). **검증 대상(`isPreRef`/`isPostRef` 배타 + 둘 다 `isRef`엔 `true`, Leaf 핸들러 흉내)은 그대로**라 assert는 손댈 게 없다. **새로 넣을 것**: 다중 태깅이 실제로 되는지 — 한 값을 두 브랜드에 등록하고 양쪽 `:is`가 다 `true`인지(`Source`가 `SourceBrand`+`EpochBrand`인 자리, `base/state-epoch-plan.md` §2) | | `16-type-store-key-typefunction.luau` | 옛 접근 기준으로는 ✅ 통과였음 | **[2026-08-25] 검증 대상이 폐기됨** — `WrapStore`/`ProcessStoreType` 합성 자체가 사라졌다. **재작성 지침**: 타입 함수 없는 평범한 레코드 모양(`base/store-plan.md`의 "`store.key` 레코드 필드 타이핑" 절)을 검증하고, 음성 대조군에 **예약 키 충돌**(`CheckReservedKeys>`가 `types.never`로 무너뜨리는지 — **[2026-08-26 `H-112`]** 인자가 `T`가 아니라 `keyof`다)과 **없는 키 접근**을 포함할 것 | | `11-modifier-illegal-value-error.luau` | 옛 형태 기준으로는 ✅ 통과였음(16개 케이스 전원) | **[2026-08-26, 8라운드 `H-122`/`H-123`] 검증 코드가 폐기된 모델을 박제하고 있다** — 그 파일의 Store 생성자가 **eager `Source(v)`** 모델이다. 명시적 초기화 확정(2026-08-25) 이후 **`defaults` 경로에선** Store가 `Source`를 만들지 않는다(동적 키 창구 `store:Of(name)`은 여전히 만든다 — 그래서 가드가 `Source` 생성자로 갔다). **재작성 지침**: `isModifier` 가드의 새 자리는 **`Source` 생성자**(+`Source:Set`, `:Compute` 결과 캐싱)이고, Store 생성자가 하는 건 `defaults`의 **`isSource` 화이트리스트 검증**(error level 2)이다 — 둘을 각각 양성/음성으로 볼 것. **검증 대상(핸들러 계층 값 즉시 error)은 그대로**라 결론이 바뀌는 건 아님 | @@ -245,7 +245,7 @@ inst 5개만 살린 상태 → 살아남은 payload 5 / 엔트리 5 (기대치 | 검증할 것 | 왜 | 출처 | |---|---|---| | ~~`table.insert`가 배열 중간의 구멍을 재사용하는가~~ **[2026-08-24 폐기]** | **전제 자체가 없어졌다** — 6라운드 `H-7`로 `Ref.Callbacks`가 배열에서 `{[callback\|thread] = true}` **해시맵 셋**으로 바뀌었고, 해시맵엔 border 개념도 구멍도 없다(`base/ref-plan.md`). 이 스파이크는 만들지 말 것 | QA 4라운드 `R-11`(폐기), 6라운드 `H-7` | -| 중간 State가 `_hold`(하류 → 상류 강함) 불변식으로 실제로 살아남는가 | **[2026-08-25] 설계는 확정됐다** — 각 파생 노드가 자기 상류를 `_hold`로 강하게 든다(사용자 확정). 남은 건 실측뿐이고 **M2 착수 게이트는 아니다**(`question.md` 최우선 절에서 내려감). 음성 대조군으로 "`_hold` 없이 짜면 중간 노드가 수거돼 전파가 끊긴다"까지 볼 것 | `base/source-state-plan.md`의 "해소됨 — 중간 State는 `_hold`로 살아남는다" 절 | +| 중간 State가 `_hold`(하류 → 상류 강함) 불변식으로 실제로 살아남는가 | **[2026-08-28 닫힘 — `quad-base/test/spec.state.luau` 11번이 양성(체인 생존)·음성(하류를 놓으면 수거) 둘 다 실측]** 아래는 닫히기 전 서술: **[2026-08-25] 설계는 확정됐다** — 각 파생 노드가 자기 상류를 `_hold`로 강하게 든다(사용자 확정). 남은 건 실측뿐이고 **M2 착수 게이트는 아니다**(`question.md` 최우선 절에서 내려감). 음성 대조군으로 "`_hold` 없이 짜면 중간 노드가 수거돼 전파가 끊긴다"까지 볼 것 | `base/source-state-plan.md`의 "해소됨 — 중간 State는 `_hold`로 살아남는다" 절 | | `Relate` 값/내부 키가 바깥 키를 되참조하면 새는가 | **[2026-08-25 신설, 7라운드 `H-71`/`H-77`]** `done/07`은 **안전한 모양만** 봤는데 여러 문서가 그걸 "GC-native 아키텍처의 핵심 전제 검증"으로 인용한다. 실제로는 (a) `SetStrong`의 **값**이 되참조하면 100% 새고, (b) **내부 키**가 되참조하면 `SetStrong`/`SetWeak` **둘 다** 샌다. `07`에 음성 대조군으로 추가할 것 | `base/relate-plan.md`의 "위험한 패턴" 절 슬롯 표 | | **[2026-08-26 신설, 8라운드 `H-112`]** `CheckedQuad`이 M2 표면 추가 후에도 사는가 | 8라운드에 **한 번 실측해 통과**했지만(배선이 격리형이라 `Quad`에 `Source` 필드를 더해도 클린), 실제 M2 반영 뒤 `Quad` 타입의 선언 스타일이 정해지면 다시 봐야 한다. `23`(`done/`에서 **통과** 상태)이 `CheckedQuad`를 쓰므로 그걸 다시 돌리는 배치. **[2026-08-26 정정, `/code-review high`]** 여기 한때 "`rewrite-required/23`의 재작성과 같은 배치"라고 적었는데 **`rewrite-required/`에 `23`은 없다** — 일어나지 않을 재작성에 실측을 매달아 고아가 될 뻔했다 | `ROADMAP.md` M2의 `H-80` 체크박스, 8라운드 `H-112` | | `Visible = false`인 GuiObject의 `AbsoluteSize`/`AbsolutePosition`이 갱신되는가 | `quad-roblox-fastscroll` 설계의 선행 실측. **Studio 필요** — 만들면 `not-run/`행 | `research/fastscroll-plan.md` | diff --git a/ROADMAP.md b/ROADMAP.md index 37539fd..59cc9ce 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -660,10 +660,12 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 **앞**에 와야 함, 2026-08-11 후속 세션 제안 → 같은 날 세 번째 세션에 순서 정정, `base/source-state-plan.md` "trailing deps를 fn에 lazy positional 인자로도 노출" 절) — 방향/순서는 확정, + **[2026-08-28 실측 전 서술 — 결과는 위 배너, 아래는 원문]** `luau-test`의 `15-type-compute-trailing-deps-typepack.luau`로 이형 다중 deps를 제네릭 타입 팩으로 표현 가능한지만 실측 필요(안 - 되면 동종 타입 dep 1개로 한정) -- [x] **[2026-08-28 단위 2 — `:With`/`Source:Emit()` 완료, `state:Apply(blocker)`는 `Apply`의 `__apply` 경로로 단위 4에서 실제 Blocker와 합류]** **[2026-08-25 신설, `H-84`]** `:With(...)` / `state:Apply(blocker)` / + 되면 동종 타입 dep 1개로 한정 — 실측 결과 채택된 건 이 대안이 아니라 + deps 자리 `...any` + 콜백 주석이다) +- [ ] **[2026-08-28 부분 — 단위 2에서 `:With`/`Source:Emit()` 완료, `state:Apply(blocker)`는 `Apply`의 `__apply` 경로로 단위 4에서 실제 Blocker와 합류할 때 닫힘]** **[2026-08-25 신설, `H-84`]** `:With(...)` / `state:Apply(blocker)` / `Source:Emit()` — `:Compute`/`:Apply`/`:Observer`는 각각 체크박스가 있는데 이 셋만 빠져 있었다 - [x] **[2026-08-28 완료 — 단위 2]** **[2026-08-25 신설, `H-81`; 2026-08-26 자리 정정 `H-122`]**