quad/.claude/session/2026-08-12-07-preref-single-use-no-cancel.md
qwreey cdbbdba4fb
decide(bind-system): PreRef is single-use, no cancel concept, reuse errors
PreRef never enters the normal retract dispatch chain (consumed via None
in the pre-pass), so "cancel" was never structurally possible. The real
hazard is reuse across constructions (stale .Value silently firing
callbacks) — guard it with an explicit error on re-fire instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 13:26:46 +09:00

3.9 KiB

2026-08-12 일곱 번째 세션 — PreRef는 1회용, 취소 개념 없음, 재사용은 error

배경

이전 세션(대화 초반)에서 사용자가 "지금 확정이긴 한데 다른 의견 나오면 뒤집힐 만한 부분이 뭐가 있을지" 물어봐서 서브에이전트로 .claude/ 전체를 감사했음. 그 결과 중 하나가 research/documentation-content-map.md 262-269행에 명시적으로 미정으로 표시돼 있던 항목: PreRef의 취소 가능성 — "PreRef는 fire와 동시에 소진되는 1회성 pre-pass 참가자라 '취소'라는 개념 자체가 성립하는지부터 다시 볼 것"이라고만 적혀 있고 실제 결론은 없었음.

논의

사용자 제안: PreRef는 취소 불가능하게 두는 게 나을 듯 — 동적으로 쓰일 수 있는 예외적 경우(Slot의 updateFn처럼 반복 호출되는 자리에서 컴포넌트가 내부적으로 PreRef를 만드는 경우)도 State/:With처럼 "매번 새로 만드는" 패턴을 따르는 게 맞다. 이전 콜백이 다시 실행되는 건 코드가 꼬이고 디버깅이 어려워지는 원인이 될 것. Ref와는 다른 결 — use only once.

Claude가 확인한 구조적 근거: Ref가 "다른 값으로 교체되면 retract로 취소됨"이라는 취소 개념을 가질 수 있는 건 정상 우선순위 스캔의 (inst,k) 디스패치 체인에 실제로 참여하기 때문(Dispatch.retractUnder가 그 체인 대상으로 동작). PreRef는 pre-pass에서 fire와 동시에 flattened[i] = None으로 소진되고 정상 두 패스는 아예 건드리지 않음 (bind-system-plan.md "호이스팅의 실제 구현" 절 — 기존에 이미 확정돼 있던 메커니즘) — 그래서 "취소"가 애초에 도달할 방법이 없는 값이었음, 사용자의 직관이 기존 구조와 정확히 들어맞음.

더 나아가 진짜 위험은 "취소"가 아니라 재사용이라는 걸 짚음: 이미 fire된 PreRef 객체를 두 번째 construction에 다시 놓으면, 거기서 등록하는 :Callback(fn)이 "이미 채워져 있으면 즉시 1회 호출"이라는 기존 규칙 때문에 의도한 새 인스턴스가 아니라 첫 번째 fire 때 남은 stale .Value로 조용히 호출됨 — 에러 없이 엉뚱한 값을 들고 실행되는, 디버깅하기 아주 어려운 버그. 사용자가 이 진단에 동의, "에러 가드 구현이 거의 공짜니까 재할당을 아예 불가능하게 두자"로 확정.

결정

  1. PreRef는 취소 개념이 없음 — 구조적으로 이미 그랬던 사실을 명문화.
  2. 이미 fire된 PreRef를 재사용(두 번째 construction에 다시 놓기)하면 pre-pass가 즉시 error — 내부 _fired 플래그로 구현, 위 "동적 경로 가드" Handler와는 별개의 코드 경로(pre-pass 자신 안에 위치).
  3. 관용구: Slot:ListupdateFn처럼 반복 호출되는 자리에서 PreRef가 필요하면 호출마다 새 PreRef()를 만들 것 — 클로저 캡처로 재사용 금지. (Slot 자체는 이미 요소 타입으로 Ref/PreRef를 금지하고 있어, 이 관용구가 실제로 문제되는 자리는 updateFn 안에서 호출하는 컴포넌트 함수 내부뿐.)

반영

  • base/bind-system-plan.md — "동적 경로로 도착한 PreRef는 런타임에도 명시적으로 에러" 절 바로 아래에 새 항목 추가(구조적 근거, 재사용 위험 시나리오, 구현 메커니즘, 관용구 전부 포함).
  • research/documentation-content-map.md — 심화 후보 6번과 "문서화 아직 보류" 목록 두 곳에서 취소 가능성 항목을 [해소됨]으로 정정, "hook"/ "pre-hook" 용어 채택 여부만 계속 열린 채로 남김. 두 항목 다 "이미 question.md에도 열려있음"이라던 서술이 실제로는 부정확했던 것도 같이 발견·수정(grep 결과 question.md엔 해당 항목이 없었음).