fix(docs): missing :Get() on :Compute callback args across base docs
state:Compute(fn)'s fn receives lazy State handles, not raw values, per the confirmed self/with contract. Found and fixed the same class of bug the user caught in the Animate example in three more spots (slot-plan.md x2, tag-plan.md). Added a warning note near the contract since this is an easy mistake to repeat.
This commit is contained in:
parent
a1f8601cc7
commit
34ded8b953
6 changed files with 73 additions and 5 deletions
|
|
@ -1994,6 +1994,15 @@ Modifier처럼 플래튼하지 않는가"는 설계 근거를 알고 싶은 사
|
|||
key1:Get() + store.key2:Get() end)` — `key1`은 이제 raw 숫자가 아니라
|
||||
State.
|
||||
|
||||
**[2026-08-12 세션 감사에서 확인] `:Compute` 콜백 인자에 `:Get()`을 빠뜨리는
|
||||
실수가 반복되기 쉬움 — 실제로 `.claude/` 문서 예시 코드 4곳(`tag-plan.md`,
|
||||
`slot-plan.md` 2곳, `research/tween-plan.md`)에서 발견·수정됨.** `fn(self,
|
||||
...)`의 모든 인자가 raw 값이 아니라 lazy State 핸들이라는 원칙(바로 위 절)을
|
||||
사람도 에이전트도 코드 작성 중에 잊기 쉬운 지점 — `:Compute`/`:With` 콜백
|
||||
안에서 인자를 비교(`==`)/연산(`+`)/테이블에 담기 전에 항상 `:Get()`부터
|
||||
거쳤는지 확인할 것. 예: `function(name) return name == "x" end`(버그) vs
|
||||
`function(name) return name:Get() == "x" end`(올바름).
|
||||
|
||||
**State는 쓰기 대상이 아님 — 확정, Source는 독립 공개 프리미티브로 격상**
|
||||
|
||||
- `state:Get()`은 항상 읽기 전용. State에는 쓰기 API가 아예 없음. "State에
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ function updateFn(item, index, offset, prev, ud)
|
|||
-- 다시 그림(새 원소) — 이전 Source 재사용/Set 없이 처음부터 올바른 값으로 생성
|
||||
local layoutOrder = Source(index)
|
||||
return Frame {
|
||||
LayoutOrder = layoutOrder:With(offset):Compute(function(i, o) return i + o end),
|
||||
LayoutOrder = layoutOrder:With(offset):Compute(function(i, o) return i:Get() + o:Get() end),
|
||||
...
|
||||
}, { layoutOrder = layoutOrder }
|
||||
end
|
||||
|
|
@ -963,7 +963,7 @@ function Slot:Single(state, updateFn)
|
|||
updateFn = updateFn or identityUpdateFn -- [2026-08-11 일곱 번째 세션] 기본값 추가
|
||||
|
||||
local data = isState(state)
|
||||
and state:Compute(function(v) return v == nil and {} or { v } end)
|
||||
and state:Compute(function(v) return v:Get() == nil and {} or { v:Get() } end)
|
||||
or (state == nil and {} or { state })
|
||||
|
||||
return self:List(data, function(item, index, offset, prev, ud)
|
||||
|
|
@ -1215,7 +1215,7 @@ sugar가 성립하려면 `:Single(state)`(updateFn 생략)이 유효해야 함
|
|||
(`:List`의 reconcile은 `key` 기준으로 독립 동작, `sub`가 바깥에서
|
||||
어느 인덱스에 있든 상관 안 함).
|
||||
- **`State<T?>`(nilable)도 특별 취급 없이 그냥 됨** — `:Single`이 이미
|
||||
`v == nil and {} or {v}`로 nil을 "빈 리스트"로 흡수하므로, raw 직접
|
||||
`v:Get() == nil and {} or {v:Get()}`로 nil을 "빈 리스트"로 흡수하므로, raw 직접
|
||||
전달 요소(`Add(element)`, State로 안 감싼 경우)에만 여전히 non-nil이
|
||||
요구되고, `State`/`Source`로 감싼 값은 내부적으로 nilable이어도 아무
|
||||
문제 없음 — 위 "요소 타입 제약" 절의 nil/None 금지는 **State/Source로
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ API처럼 보이기 때문** — 실제로는 항상 `table.clone` 후 반환(Mo
|
|||
"하나의 Tag 값을 프로그래밍적으로 조립"하는 용도).
|
||||
|
||||
**동적 토글은 `Source`/`State`로, `None` 불필요** — 상호배타 상태 전환은
|
||||
`store.activeTag:Compute(function(name) return name == "btn1" and
|
||||
`store.activeTag:Compute(function(name) return name:Get() == "btn1" and
|
||||
Tag("selected") or nil end)`처럼 그냥 `nil`을 리턴하면 됨. `None` 센티널은
|
||||
"정적 테이블 리터럴에서 `키 = nil`이 키 없음과 구별 안 되는" 문제의
|
||||
해법이지(`bind-system-plan.md` "`None` 센티널" 절), 이건 함수 리턴값이
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ reduceMotion류 접근성 우회가 이 필드 하나로 바로 표현됨:
|
|||
-- reduceMotion: State<boolean>
|
||||
Position = mySource:Compute(Animate{
|
||||
Style = Enum.EasingStyle.Bounce,
|
||||
CanAnimate = reduceMotion:Compute(function(r) return not r end),
|
||||
CanAnimate = reduceMotion:Compute(function(r) return not r:Get() end),
|
||||
})
|
||||
```
|
||||
|
||||
|
|
|
|||
50
.claude/session/2026-08-12-04-compute-self-get-audit.md
Normal file
50
.claude/session/2026-08-12-04-compute-self-get-audit.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<!-- quad-v2 세션 로그 원문 — CLAUDE.md에서 이전됨(2026-08-11 정리 세션에서 확립된 관례를 따름). -->
|
||||
<!-- 이 파일은 quadnomicon 개발로그 소재용 원자료로, 당시 시행착오(정정 전 서술 포함)를 그대로 보존함. -->
|
||||
<!-- 현재 유효한 설계는 이 파일이 아니라 base//research//archive/가 최종 소스 — 이 파일 안의 판단이 이후 세션에서 뒤집혔을 수 있음. -->
|
||||
|
||||
## 2026-08-12 네 번째 세션 — `:Compute` 콜백 인자 `:Get()` 누락 버그 전역 감사
|
||||
|
||||
앞선 세션(`2026-08-12-03`)에서 추가한 `Animate`의 `CanAnimate` 예시가
|
||||
`reduceMotion:Compute(function(r) return not r end)`으로 돼 있었는데,
|
||||
`r`이 raw boolean이 아니라 lazy State 핸들(`bind-system-plan.md`의
|
||||
"self/with 값 둘 다 lazy State 핸들로 통일" 확정 계약)이라 `not r`은 항상
|
||||
`false`(State 객체는 절대 nil/false가 아니므로)로 새는 버그라고 사용자가
|
||||
직접 지적. 같은 클래스의 실수가 다른 곳에도 있는지 `.claude/` 전체를
|
||||
`:Compute(function(`/`:Observer(function(`/`:Apply(function(` 그렙으로
|
||||
감사.
|
||||
|
||||
**발견된 버그(전부 수정)**:
|
||||
- `research/tween-plan.md` — `not r` → `not r:Get()`(사용자가 직접 지적).
|
||||
- `base/slot-plan.md:578` — `layoutOrder:With(offset):Compute(function(i, o)
|
||||
return i + o end)` → `i:Get() + o:Get()`(`LayoutOrder` 계산 예시).
|
||||
- `base/slot-plan.md:966` — `Slot:Single`의 `state:Compute(function(v)
|
||||
return v == nil and {} or { v } end)` → `v:Get() == nil and {} or
|
||||
{ v:Get() }`. 프로즈로 같은 패턴을 다시 언급하는 1218행도 동기화.
|
||||
- `base/tag-plan.md:42` — `store.activeTag:Compute(function(name) return
|
||||
name == "btn1" and ...)` → `name:Get() == "btn1"`.
|
||||
|
||||
**감사 방법과 스코프**: `grep -rn ":Compute(function("` 등으로 `.claude/`
|
||||
전역(`initreq/` 제외)을 훑고, 히트마다 콜백 파라미터가 비교/연산/테이블
|
||||
삽입 등 "raw 값이어야 말이 되는" 방식으로 쓰였는지 확인. `:Observer`/
|
||||
`:Apply` 콜백은 전부 인자 없이 외부 변수를 클로저로 캡처하는 관용구라
|
||||
(`function() state:Get() ... end`) 이 클래스의 버그 자체가 성립하지
|
||||
않음 — 확인만 하고 수정 없음. `archive/batch-rejected.md:29`(`function(av,
|
||||
bv) return av + bv end`)는 self/with-lazy-핸들 확정 이전의 기각된
|
||||
초안이라 원문 그대로 보존(archive는 원문을 안 고치는 게 원칙).
|
||||
`bind-system-plan.md:1993`의 예시는 이미 올바르게 `key1:Get()`을 쓰고
|
||||
있어 수정 불필요.
|
||||
|
||||
**일반 규칙 문서화**: `base/bind-system-plan.md`의 "self/with 값 둘 다
|
||||
lazy State 핸들로 통일" 절 바로 뒤에 "이 실수가 반복되기 쉬움 —
|
||||
`.claude/` 문서에서만도 4곳 발견"이라는 감사 결과+주의 노트 추가 —
|
||||
`:Compute`/`:With` 콜백 인자를 비교/연산/테이블 삽입에 쓰기 전엔 항상
|
||||
`:Get()`부터 거칠 것.
|
||||
|
||||
**반영된 파일**: `research/tween-plan.md`, `base/slot-plan.md`(2곳+프로즈
|
||||
1곳), `base/tag-plan.md`, `base/bind-system-plan.md`(감사 결과 노트).
|
||||
|
||||
**여전히 열려있는 것**: 안 바뀜 — 자연 완료(Completed) 시 per-instance
|
||||
북키핑 정리 여부 하나(`research/pre-implementation-audit.md` 2-10번).
|
||||
|
||||
**다음 세션이 할 일**: 안 바뀜(`ROADMAP.md` M0부터, `.claude/luau-test/`
|
||||
결과 확인 우선).
|
||||
|
|
@ -458,3 +458,12 @@ reduceMotion류 우회가 이걸로 표현됨). `base/architecture.md`에 "코
|
|||
스타일 — Luau 문법 관례" 절 신설 — `if-then-else`(2021년 정식 도입)와
|
||||
`const` 바인딩 둘 다 공식 Luau 문법임을 명문화(에이전트가 모르고
|
||||
`and`/`or`로 되돌리는 회귀 방지), `const`는 툴링 미성숙으로 지금은 보류.
|
||||
|
||||
**2026-08-12 네 번째 세션 — `:Compute` 콜백 인자 `:Get()` 누락 버그 전역 감사**
|
||||
(`session/2026-08-12-04-compute-self-get-audit.md`)
|
||||
사용자가 `Animate`의 `CanAnimate` 예시(`not r`)가 `r:Get()`이어야
|
||||
한다고 지적 — `:Compute`의 `fn(self, ...)` 인자가 raw 값이 아니라 lazy
|
||||
State 핸들이라는 기존 확정 계약을 놓친 버그. 같은 클래스의 실수를
|
||||
`.claude/` 전역에서 찾아 `base/slot-plan.md` 2곳(`LayoutOrder` 예시,
|
||||
`Slot:Single`)과 `base/tag-plan.md` 1곳에서 추가로 발견·수정.
|
||||
`bind-system-plan.md`에 "이 실수가 반복되기 쉬움" 주의 노트 추가.
|
||||
|
|
|
|||
Loading…
Reference in a new issue