quad/.claude/archive/preref-order-unguaranteed-withdrawn.md
qwreey f9f0babc87
docs(base): PreRef/PostRef 계열 안 fire 순서 미보장안 철회 — 배열 index 순서 보장 유지
직전 커밋(bcd02f1)에서 미보장으로 뒤집었던 것을 같은 세션에 철회.
반례는 `FastQuery(...) -> PreRef`류 조합 — 앞자리 항목이 뒤 항목의
전제를 만들어주는 정당한 합성이고, children 마운트 선후가 배열 위치로
정해지는 것과 같은 성격. 보장 비용 0(pre-pass가 어차피 index 순서)이고
배열 파트 index 순서는 이미 백엔드 이식성 때문에 명시적 계약이라 새로
내주는 자유도 없음. 보장 + 스타일 권고를 같이 기재.

- archive/preref-order-guaranteed-reversed.md → preref-order-unguaranteed-withdrawn.md
  (제안·철회 양쪽 논거 보존)
- OnRendered의 "부모에 붙기 전에 불림" 캐비엇은 사용자 지시대로 이름 유지 +
  명시만(ref-plan "보장 범위" 항목, lifecycle-hooks-plan ⚠️ 항목)
- ref-plan/lifecycle-hooks-plan/ROADMAP/README/CLAUDE.md/세션 로그 동기화

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:54:05 +09:00

75 lines
4.2 KiB
Markdown

# [철회됨] 복수 `PreRef`/`PostRef` 간 fire 순서를 "미보장"으로 두려던 안
**제안·철회 모두 2026-08-14 아홉 번째 세션**(원 결정: 2026-08-07 아홉 번째
세션). **현재 유효한 계약은 "배열 index 순서 그대로 보장"** — 즉
2026-08-07 결정이 그대로 살아 있음, 정본은 `base/ref-plan.md`
"`phase` 옵션 폐기 → 위치로 표현, `PreRef` 신설" 절(복수 `PreRef` 간 순서
항목)과 "`PostRef`" 절. 이 파일은 **한 세션 안에서 뒤집었다 되돌린 왕복의
기록**이고, 남겨두는 이유는 양쪽 논거가 나중에 비슷한 판단(“보장할까
말까”)에서 다시 쓸 만해서임.
## 원래 계약 (2026-08-07 아홉 번째 세션, 지금도 유효)
> 복수 `PreRef` 간 순서 — 새 규칙 불필요, **배열 index 순서 그대로**.
> 이 pre-pass는 "배열 파트는 index 순서대로" 계약을 그대로 재사용해
> 리터럴 순서대로 fire하면 됨.
## 미보장으로 바꾸자던 안 (제안 → 같은 세션에 철회)
사용자 원 메모:
> 각 PreRef 간의 순서는 보장 안함. PostRef간 순서는 보장 안함(실제로
> 하더라도, 안 한다고 두는게 버그를 차라리 덜 만든다고 생각함. 같은 계열
> 내 Ref 등록 순서에 의존하는 무언가가 생겨선 안된다는 생각, 그건 구조부터
> 잘못된거니까)
논지: (1) 순서에 의존하는 훅 코드는 애초에 설계가 잘못된 것이니 보장을
제공하면 그 구조를 권장하게 됨, (2) 보장을 안 하면 나중에 pre-pass 구현을
바꿀 자유가 남음, (3) 그 순서에 기대는 사용자 코드가 안 생겨 버그가 덜 남.
**구현은 어차피 안 바뀌고 계약만 좁히는 변경**이었음(pre-pass는 미보장
상태에서도 index 순서로 훑음).
## 왜 철회했나
**결정적 반례 — `FastQuery(...) -> PreRef`류 조합(사용자 제시).**
어떤 팩토리가 `PreRef`를 반환하면서 뭔가를 미리 해결해두면, **배열에서
그 뒤에 오는 `OnCreated`가 "그게 이미 끝났다"를 전제로** 동작할 수 있음:
```lua
Frame {
FastQuery(...), -- PreRef를 반환하는 팩토리
OnCreated(function(inst) -- 위가 끝난 뒤에 불림
...
end),
}
```
이건 "잘못된 구조"가 아니라, **이 배열이 원래 제공하는 정당한 합성
방식**임 — children의 마운트 선후가 배열 위치로 정해지는 것(`base/ref-plan.md`
"`phase` 옵션 폐기 → 위치로 표현, `PreRef` 신설" 절이 `phase` 옵션을
없앨 수 있었던 바로 그 이유)과 정확히 같은 성격이고, 서로 다른 저자가
쓴 항목(팩토리 제공자 vs 호출자)이 한 배열에 섞이는 유일한 자리이기도 함.
곁들여 확인된 것들:
1. **보장 비용이 0** — pre-pass가 어차피 index 순서로 훑고, `PostRef`
`postRefList`도 그 스윕이 만든 목록이라 push 순서가 곧 배열 순서.
2. **미래 구현 자유를 내주는 것도 없음**`base/dispatch-core-plan.md`
이미 "배열 파트는 index 순서대로"를 **백엔드 이식성 때문에 명시적
계약**으로 못박아 뒀으므로, 어떤 백엔드든 index 순서를 제공해야 함.
PreRef 순서 보장은 새 약속이 아니라 그 계약의 자동 귀결.
3. **미보장인데 결정론적이면 실효가 없음** — 런타임이 항상 index 순서로
주는 이상 위반이 테스트에서 절대 안 걸림. (Go의 map 순회 무작위화처럼
디버그 모드에서 일부러 역순으로 돌려 노출시키는 방법은 있으나, 이
사소한 규범 하나를 위해 장치를 더 만들 가치는 없다고 판단.)
4. **계약 표면에 예외가 하나 느는 비용** — "배열 파트는 순서 보장, 단 그
안의 PreRef끼리는 아님"을 읽는 사람이 따로 기억해야 함.
## 남은 것
보장은 유지하되 **스타일 권고**만 문서에 남김 — 순서로 조율해야 할 만큼
얽힌 훅이면 대개 하나의 훅 안에서 순서대로 부르는 게 낫고, 위
`FastQuery`처럼 "앞의 것이 뒤의 것의 전제를 만들어주는" 명시적 합성이
아니면 순서에 기대지 말 것(`base/ref-plan.md`/`base/lifecycle-hooks-plan.md`
양쪽에 기재).