quad/.claude/session/2026-08-27-03-handtrace-round9-h143-h146.md
qwreey 0ec22fbe73
qa: 9라운드 후속 H-143~H-146 확정·반영 + 감사 8라운드·code-review — 잔여 셋은 10라운드 문항지로
- H-143 Rerun 꼬리: 실행 중 사망(wasAlive and not canExecute)이면 cleanup 즉시 소진
  (처음 쓴 not canExecute 판정은 생성자 최초 설치를 죽여 감사 2라운드가 정정)
- H-144 재구독 꼬리(Refresh 먼저) + 진입점은 EffectHandle 자기 것 (b)
  (Observer 함수 배정은 콜론 위임으로 꼬리 2회 — 감사 4라운드, luau 재현)
  → conventions.md 설계 원칙 신설: 하나의 무언가가 두 일을 하지 않는가
- H-145 bk.indexOfElement weak-key / H-146 루트 .Parent는 사용자 몫, Mount 없음
- 감사 1→1→1→1→1→1→1→0, /code-review high 10건 중 7 반영
- H-147~H-149는 qa-request/pre-implementation-handtrace-round10.md §4로 (배치 회신)
- round10 지시서(-brief.md) 신설, 광범위 탐사 예정

Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01546hjsYNLSMZdHdPyTZaGb
2026-08-28 00:28:52 +09:00

5.8 KiB

2026-08-27 — 9라운드 후속: /code-review가 낸 새 메커니즘 넷(H-143~H-146) 결정·반영

무엇을 했나: 앞 세션(session/2026-08-27-02-handtrace-round9-q4-q10.md)이 question.md 최우선 절에 올려둔 넷을 사용자에게 갈래·권고와 함께 제시하고 한 턴에 회신을 받아 base/·ROADMAP.md에 반영했다. 결정과 회신 원문은 qa-request/pre-implementation-handtrace-round9-followup.md의 "H-143~H-146" 절이 소스. 여기는 흐름과 문서에 안 들어간 것.

흐름

  1. 컴팩트 직후 넷의 원문(-round9.md 620행 이하)과 관련 base/ 서술(Rerun· _bindDestroying·Observer 네 진입점·EpochMap API·SlotHandler retractor· H-142 항목·slot-plan.md의 "동적 자식은 반드시" 절)을 읽고, 항목마다 트레이스 → 왜 새 메커니즘인가 → 갈래와 결과 → 권고 → 채택 시 고칠 자리로 정리해 올렸다. 하위 결정 둘을 같이 올렸다 — H-143의 판정 predicate (canExecute 하나 vs 강한 해제만)와 H-144WeakSubscribe 래퍼 여부.
  2. 사용자가 넷 다 (a)에 동의하되 H-144재트레이싱을 요청했다 — "재구독 뒤 emit이 꼬여도 괜찮은가"와 "재구독 시점에 epoch를 다 맞춰두는 게 낫지 않은가(Blocker로 막힌 뒤 늦게 오는 것 처리가 갈린다)", 그리고 Observer도 같은 문제가 있는지.
  3. 재트레이싱 결과(followup에 기록): 첫 질문은 fire의 가드 순서 (canExecute_epochs:Update )로 안전, 둘째는 leaf 경로 _bindDestroying이 이미 Refresh() 먼저라 같은 모양으로 맞추면 된다 — 게이트 유보 중 재구독 케이스가 그 차이를 실제로 드러낸다. Observer는 epoch가 없고 설치 발화도 없어 무관. 래퍼 모양을 제시하고 반영으로 넘어갔다.

시행착오 / 다음 세션이 알아야 할 것

  • 문서에 이미 있는 모양을 먼저 찾았다. H-144의 래퍼는 새로 발명한 게 아니라 _bindDestroying(H-65)의 꼬리를 그대로 옮긴 것이다 — 앞 세션 교훈 ("어디에도 없다"고 쓰기 전에 grep)의 반대 방향 적용: 새 메커니즘을 제안하기 전에 같은 문제를 이미 푼 자리가 있는지 grep했다. 그 덕에 사용자의 "epoch를 맞춰두자"가 곧 기존 캐비엇(287행)의 재발견이라는 걸 바로 연결할 수 있었다.
  • H-145 weak-key는 InstanceChildHandler가 5번째 인자를 안 넘기는 근거 한 줄을 무효화한다(옛 키 잔존) — 결정 하나가 다른 자리의 근거를 바꾸는 패턴이라 그 자리도 같이 고쳤다. 감사자가 잡을 종류의 stale을 반영 시점에 닫은 것.
  • slot-plan.md 233행 *"v2는 mount 함수 자체가"*는 v1식 Mount(parent, tree) 표면이 v2에 있는 것처럼 읽혔다(H-146 발견의 부수) — Slot의 마운트 경로를 뜻하는 문장이라 그렇게 고쳤다.

감사 루프가 뒤집은 것 둘 (같은 날, 반영 뒤)

  • 2라운드: H-143 판정식 not canExecute생성자 최초 설치를 죽였다 (바인드·구독 전이라 항상 거짓 → 첫 cleanup 즉시 소진, _installed 거짓, 첫 바인드에서 fn 재실행 = H-58 재현). wasAlive and not canExecute("실행 중에 죽었는가") + 죽은 핸들의 _pending 버림으로 정정. 사용자: "오 그렇네. 실행중 죽으면 클린업만 하기, 해당 방식 맞아보여".
  • 4라운드: H-144 래퍼가 Q4의 "Observer 함수 배정" 위에 얹히면서 Observer:Subscribe의 콜론 위임 self:WeakSubscribe()EffectHandle 오버라이드로 가 꼬리 2회 + 강한 킵 전 Rerun. 사용자가 "그게 진짜 날 수 있어?"(Effect는 Observer가 아닌데)라 물어 로컬 luau로 재현해 보였고, (a) dot 위임 / (b) 본문 공유 자체를 접기 중 (b) 확정"내 머리에서 나왔던 처음 구조는 그것이였어". 원칙 *"하나의 무언가가 두 일을 동작하지 않는가에 유의하자"*를 conventions.md "설계 원칙"으로 승격. 사용자가 이어서 "그게 정확히 invalid after 문제에서 났던 이야기였어" — 같은 원칙의 첫 사례가 8라운드의 invalidAfter 두 필드 분리였다는 출처를 원칙 항목에 붙였다(필드 하나가 두 뜻 / 함수 본문 하나가 두 타입).
  • 교훈: **두 건 다 "반영분 자체가 만든 결함"**이고, 둘 다 "권고 (a)의 의도는 맞는데 내가 고른 판정식·배선이 틀린" 종류다. 감사 1라운드(문구 잔존)로는 못 잡고 2·4라운드(의미론·수정분 재검토) 각도에서만 나왔다 — 각도를 바꾸는 라운드가 실제로 값을 한다는 재확인.

마무리 (2026-08-28) — /code-review high와 10라운드로의 이관

감사 8라운드 수렴 뒤 /code-review high 10건 — 일곱 반영(-round9-followup.md 마지막 절), 셋은 판단 필요(H-147 죽은 핸들에서 Rerun / H-148 Parent 전용 문구가 새 메커니즘 / H-149 Observer 위임과 level 2). 사용자: "너무 길어지고 있어서, round10 으로 옮기고 싶은데 … 인간을 기다리는거 엄청 비효율이라서 … batch 로 처리될 필요가 있는듯. 지금 결정해야할 분 10 으로 올리자. 커밋하고 정리한 다음 깔끔한 컨텍스트의 fable 탐사자 하나 띄워서 광범위한 핸드트레이싱, 테스팅, 문제 검사를 하도록 해줘."-round10-brief.md/-round10.md 신설, 커밋 후 탐사자 기동. 교훈: 대화형 처리는 발견 하나당 한 왕복이라 사람 쪽 대기 비용이 크다 — 라운드 단위 배치가 이 프로젝트의 기본 리듬이고, 이번처럼 반영분 리뷰에서 문항이 또 나오면 그 자리에서 다음 라운드로 넘긴다.