발견 17건(H-107~H-123)의 사용자 결정을 base/ 전체에 반영. 7라운드 확정 중 뒤집힌 건 없고, 고친 건 전부 7라운드가 base/에 내려앉을 때 생긴 누락·충돌 (하루 차로 확정된 결정들이 서로를 못 본 자리)이다. 결정의 소스는 qa-request/pre-implementation-handtrace-round8-followup.md. 계약 변경 넷: - Ref 콜백이 fn(value, ref) — 2번째가 곧 출처 Epoch. Effect가 Update(from)에 넘길 유일한 통로였다(k(value)뿐이면 Update(nil) 크래시, 실측 재현). - Observer fn이 세 자리 fn(targetState, self, emitFrom) + observer._state 강참조. 옛 2-인자는 "self는 리시버" 계약과 정면 충돌해 무인자 state:Observer()의 내부 콜백이 즉사했다. - WeakSubscribe도 .Subscribed를 세운다. 안 그러면 Effect의 State dep 전량이 조용히 침묵. 해제는 "건 경로로 푼다"(양방향 fail-fast). - 예약 키 진단이 CheckReservedKeys<keyof<T>> — T를 통째로 넘기는 배선은 실사용 T에서 아예 안 돈다(Source<T>가 *error-type*을 품어 유효한 Store 전부에 스퓨리어스 에러). 사용자가 문항의 전제를 두 번 정정: Ref 콜백과 Observer 콜백은 이질적이라 애초에 통합 대상이 아니었고(Observer엔 자기 epoch가 없다), H-118은 소유권 문제가 아니라 gate-plan 5번의 문장이 틀린 것이었다(🟡→🟢). 커밋 전 검증 — 감사 11라운드(44건, 0건으로 수렴) + /code-review high 7라운드(42건) = 86건. 감사가 0으로 수렴한 직후 code-review가 42건을 냈고, 그중 하나가 H-101의 "새 필드를 안 만든다"를 역전시켰다: getOffsetAt의 부수효과가 splice의 되감기 신호를 지우는 경로가 실재해, 부기 필드를 offsetCacheValidUpTo(캐시)와 offsetSetUpTo(:Set 완료) 둘로 분리했다. "Set을 해줬느냐"와 "캐시가 유효하냐"를 한 값이 쥔 게 원인이었다. 그 외: splice 무효화 i-1, 명시 recompute 호출부 전부 재진입 게이트, recompute 되감기 클램프, Store defaults isSource 검증, isModifier 가드를 Source 생성자로, 훅 슈가 nil 가드, pesde.lock 커밋 확정, :Single 3-인자. 2026-08-25 session/ 원문 공백은 2026-08-19 선례대로 재구성 없이 기록만. doc-check ERROR 0 / WARN 기준선 유지. Claude-Session: https://claude.ai/code/session_01F9zgJ4c4kDitAoQMm9qxKn Co-authored-by: qwreey <me@qwreey.moe>
286 lines
19 KiB
Markdown
286 lines
19 KiB
Markdown
# 2026-08-26 — 8라운드 손 트레이싱 처리 (Q1~Q10)
|
|
|
|
**무엇을 했나**: `qa-request/pre-implementation-handtrace-round8.md`의 발견
|
|
17건(`H-107`~`H-123`)을 사용자와 대화형으로 처리하고 `base/`에 전량 반영,
|
|
`-round8-followup.md`를 신설했다. **결정과 근거의 소스는 그 followup 파일**
|
|
이고 여기선 진행 방식과 그 과정에서 드러난 것만 남긴다.
|
|
|
|
## 진행 방식
|
|
|
|
1. 라운드 문서를 전량 읽고, **물어보기 전에 🔴 다섯의 핵심 주장을 `base/`에서
|
|
직접 재확인**했다 — `Ref:Set` H-53 블록에 `Revision` 갱신·Weak 순회가
|
|
없는 것, 전파 루프가 `sub.fn(sub, from)`인 것, `CheckReserved`가 `T`를
|
|
통째로 받는 서술. 전부 그대로였다.
|
|
2. §4의 문항 Q1~Q10을 세 배치로 물었다(🔴 넷 → M3/백로그 넷 → 나머지).
|
|
3. 사용자 회신을 받는 즉시 `base/`에 반영하고, 인덱스 레이어
|
|
(`question.md`/`todos.md`/`README.md`/`ROADMAP.md`/`CLAUDE.md`/
|
|
`project-context.md`)도 갱신했다. **다만 첫 패스에서 인덱스 쪽이 덜
|
|
닫혔다** — 아래 "감사 루프" 절 참고.
|
|
|
|
## ⭐ 이 세션의 실질적 소득 — 사용자가 **문항의 전제를 두 번 정정했다**
|
|
|
|
권고안이 그대로 채택된 항목이 대부분이었지만, 배울 게 있었던 건 그 둘이 아니다.
|
|
|
|
### (1) Q2-후속 — "클로저를 통일한다"는 목표 자체가 없었다
|
|
|
|
Q1(a)로 `Ref` 콜백의 출처가 2번째 자리, Q2로 Observer의 출처가 3번째 자리가
|
|
되면서 `Effect`의 단일 `onDepFire`가 성립하지 않게 됐다. 나는 이걸
|
|
**"자리를 어떻게 맞출까"**라는 문항으로 냈고, (a) `Ref`도 3슬롯으로
|
|
(`k(value, self, self)`), (b) `or`로 흡수, (c) 클로저 2개를 갈래로 세웠다.
|
|
사용자 회신:
|
|
|
|
> *"애초에 둘을 같게 두려는 목적 자체가 없었음. Ref 의 callback 과 observer 의
|
|
> 콜백이 아주 헤테로지니어스한 개념이라, 둘을 전혀 합치고자 한 적 없고, 원
|
|
> 아이디어는 달랐음. 아주 중요한 부분이 있는데, observer 에는 epoch 란게
|
|
> 존재하지 않음. emit 으로 온 epoch 를 넘겨줄 뿐, 그러나 ref 는 그 자체로
|
|
> epoch임. 처음부터 둘 처리를 묶어보는 시각 자체가 잘못되었는것."*
|
|
|
|
즉 `effect-plan.md`에 있던 *"⭐ 클로저는 **하나**로 통일한다"* 주석이 애초에
|
|
근거 없는 서술이었고, 8라운드가 그걸 "확정"으로 읽고 갈래를 그 위에 세운
|
|
것이다. **문서에 적힌 "⭐ 확정"이라도 그 근거가 문서 안에 없으면 확정이 아닐
|
|
수 있다** — 라운드 문서가 `H-107` (b)를 *"'클로저는 하나로 통일' 주석과
|
|
표면상 어긋난다"*는 이유로 낮춰 본 것도 같은 함정이었다(실제로는 dedup을
|
|
클로저 identity가 하는 게 아니라 `_deps`/`_epochs` 맵이 한다는 걸 그 문서
|
|
자신이 괄호로 적어놓고도).
|
|
|
|
### (2) Q7 — 문항이 없는 대립을 세웠다
|
|
|
|
`H-118`은 *"`Debounce`/`Throttle`은 `emit`을 아예 안 쥔다"*(gate-plan 5번)와
|
|
*"정책이 `emit()` 반환값과 `emit(false)`를 직접 쓴다"*(2번, `H-55`/`H-86`)를
|
|
**미조정 충돌**로 보고 "누가 쥐는가"를 갈래로 냈다. 사용자 회신:
|
|
|
|
> *"둘다 쥔다는 의미를 모르겠음. epoch|{epoch} 를 모아두는 부분은 gate 쪽이긴
|
|
> 한데(각각 본인껀 본인이 모아야하니까), emit 을 blocker 가 쥔다는건
|
|
> 정확하게는, 'emit 된 적 있던가?' 를 저장하기 위함 아님? 그 구현을 나눠 쓰지
|
|
> 않기 위함일 뿐 아녔음?"*
|
|
|
|
원문을 다시 읽으니 그대로였다 — `setup(emit)`이 계약이므로 `emit`은 정의상
|
|
정책 손에 있고, `blocker:Policy(emit)`이 위임받는 건 **보류 부기**뿐이다.
|
|
설계는 아무것도 안 바뀌고 **5번의 머리 문장만 틀렸다.** `H-118`은 🟡 계약
|
|
결정에서 🟢 문서 정합으로 강등됐다.
|
|
|
|
**교훈**: "두 확정이 충돌한다"는 발견을 낼 때, **둘 중 하나가 그냥 틀리게
|
|
쓰인 문장일 가능성**을 갈래에 넣어야 한다. 8라운드는 두 문장을 각각 유효한
|
|
설계 입장으로 대우해 없는 선택을 만들었다.
|
|
|
|
## 반영 규모
|
|
|
|
- `base/` **14개 파일**(위 12개 — `ref-plan`/`source-state-plan`/
|
|
`lifecycle-pattern`/`effect-plan`/`store-plan`/`state-epoch-plan`/
|
|
`dispatch-core-plan`/`slot-plan`/`gate-plan`/`modifier-plan`/
|
|
`lifecycle-hooks-plan`/`project-setup-plan` — 에 감사 루프가 더한
|
|
`architecture.md`/`typing-limits.md`), `ROADMAP.md`, `luau-test/STATUS.md`,
|
|
`research/documentation-content-map.md`, `audit/type-recursion-issue/spikes/`
|
|
2개(배너), 인덱스 레이어 6개.
|
|
- `doc-check.py` ERROR 0.
|
|
|
|
## 안 한 것
|
|
|
|
- **8라운드 §6의 "못 본 것"은 그대로 유효**하다 — 특히 M5+ 구간이 문서 정독
|
|
수준이고 값 단위 트레이싱을 안 했다.
|
|
- 남은 의심 하나(게이트 `emit(false)` 직후 다이아몬드 두 번째 경로 도착)는
|
|
8라운드 스스로 "판단이 안 서서 발견으로 안 올렸다"고 적은 것이라 여기서도
|
|
열지 않았다.
|
|
|
|
## 검증 (커밋 전) — 감사 11라운드 + `/code-review high` 7라운드
|
|
|
|
**합계: 감사 44건 + code-review 42건 = 86건.** 감사는 0건으로 수렴했고,
|
|
code-review는 마지막 라운드 HIGH 0으로 마쳤다(항목별 처분은 followup이 소스).
|
|
|
|
**⚠️ 감사가 0건으로 수렴한 *직후* code-review가 42건을 냈다.** 두 도구는
|
|
대체 관계가 아니고, 그 실측이 `conventions.md`에 반영됐다.
|
|
|
|
### 감사 루프 — 11라운드, 발견 44건, 마지막 0건으로 수렴
|
|
|
|
`quad-doc-auditor`를 한 턴에 하나씩(병렬 금지), 라운드마다 각도를 바꿔 돌렸다.
|
|
새 발견 추이: **9 → 10 → 7 → 4 → 2 → 2 → 2 → 1 → 4 → 3 → 0.**
|
|
|
|
| 라운드 | 각도 | 발견 |
|
|
|---|---|---|
|
|
| 1 | `base/` 정합성 | 9 |
|
|
| 2 | 인덱스 레이어(`README`/`ROADMAP`/`architecture` 요약) | 10 |
|
|
| 3 | 스파이크·실측 기록(`audit/`·`luau-test/`) + 1·2라운드 수정분 재검 | 7 |
|
|
| 4 | **오늘 쓴 문장 자체의 정확성**(누락이 아니라 오기·과장·의사코드 결함) | 4 |
|
|
| 5 | 오늘 *안 만진* `base/` 문서가 바뀐 계약을 전제하는가 | 2 |
|
|
| 6 | "한쪽만 고치고 짝을 안 고친" 쌍 | 2 |
|
|
| 7 | 오늘 바뀐 `base/` 파일 **전량 정독**(diff 아님) | 2 (`base/` 안쪽 0) |
|
|
| 8 | 미사용 문서군(`conventions`/`agents`/`research`/`HUMAN_TODO`) + 수정분 재검 | 1 |
|
|
| 9 | **`H-111` 하나를 토큰 전수 추적** | 4 |
|
|
| 10 | 오늘 확정 12개 계약 전부를 토큰 전수 추적 | 3 |
|
|
| 11 | "확정/새 모델/해법" 권위 표지가 붙은 폐기 블록 | **0** |
|
|
|
|
### 이 루프가 알려준 것 셋
|
|
|
|
**1. 계약을 고칠 때 가장 새기 쉬운 자리는 `base/`가 아니라 그걸 요약·복사해
|
|
든 곳이다.** 1·2라운드 발견 19건 중 15건이 `ROADMAP.md`의 체크박스 인라인
|
|
사본, `README.md`의 `base/` 표, `architecture.md`의 소스 트리 주석이었다.
|
|
그중 몇은 **그대로 구현하면 그날 고친 버그를 재현**했다(전파 루프 2-인자,
|
|
`Ref:Set`의 `k(value)`, 훅의 `Callback(fn)`). `base/`를 고칠 때 그 세 곳을
|
|
같은 배치에 넣는 걸 기본으로 할 것.
|
|
|
|
**2. ⭐ 문서군 각도로는 구조적으로 안 잡히는 잔재가 있다 — 토큰으로 범위를
|
|
잡아야 한다.** `H-111`(`WeakSubscribe`도 `.Subscribed`를 세운다)이 6·8라운드에
|
|
연속으로 새 잔재를 냈고, 그때마다 "그 문서는 고쳤다"고 넘어갔다. 9라운드가
|
|
문서가 아니라 **토큰**(`Subscribed`/`isBoundAlive`/`canBound` 계열)으로 전수
|
|
grep하자 **4건이 한 번에** 나왔다 — 전부 *"`.Subscribed`는 전역
|
|
`:Subscribe()` 전용"*이라는 **똑같은 어구**였고, 앞의 여러 라운드가 각자 다른
|
|
문서를 보느라 계속 지나쳤던 자리다. 10라운드가 같은 방법을 나머지 계약에
|
|
적용해 3건을 더 냈다. **넓게 퍼진 계약을 바꿀 땐 옛 표기의 토큰을 정해
|
|
전수 grep할 것.**
|
|
|
|
**3. 고치는 과정이 새 결함을 만든다 — 수정분도 감사 대상이다.** 이 루프에서
|
|
메인 세션이 **회귀를 6건 만들었다**: `reference/`의 blockquote가 기존 문장을
|
|
반토막 냄, `lifecycle-pattern.md`에 `Subscribe`가 서로 다른 구현으로 **두 번
|
|
정의**됨(+ 산문이 약속한 `WeakUnsubscribe` 코드 부재, `Unsubscribe`가 약한
|
|
레지스트리를 안 지우는 반쪽 해제), 새 의사코드 아래 결론 문단이 옛 주장을
|
|
유지, 정정 배너 3건이 **엉뚱한 문단**에 붙음(문단 끝 자동 탐색이 다음 bullet으로
|
|
넘어감). 4·8·9·11라운드가 이걸 잡았다 — **"수정분 재검"을 별도 각도로 두는
|
|
게 값을 했다.**
|
|
|
|
### 부수로 드러난 기존 부채 둘 (오늘 작업과 무관)
|
|
|
|
- **`HUMAN_TODO.md`가 이미 닫힌 게이트를 열려 있다고 서술**(2자리) — 관례가
|
|
요구하는 인덱스 4개 층 중 거기만 2026-08-25 갱신을 안 받았다.
|
|
- **2026-08-25의 `session/` 원문이 통째로 없다** — 그날 커밋 9개로 지금 M2
|
|
계약의 상당 부분이 확정됐는데 로그가 없다. **그 규칙 자체가 2026-08-18/19의
|
|
같은 공백에서 만들어진 것이라 재발이다.** 2026-08-19 선례대로 재구성하지
|
|
않고 `session-summary.md`에 공백을 명시했다(결정 내용 자체는 followup·발견
|
|
문서·참조 구현에 남아 있어 유실이 아니고, 없는 건 논의 과정뿐이다).
|
|
|
|
`doc-check.py` ERROR 0 / WARN 43(전부 기존 부채, 이번 작업이 늘린 것 없음).
|
|
|
|
### `/code-review high` 1차 — 감사 11라운드가 못 본 7건
|
|
|
|
사용자가 직접 호출(이 명령은 세션이 못 부른다). **7건 전부 유효.**
|
|
항목별 처분은 followup 문서의 "반영 후 검증" 절이 소스 — 여기선 교훈만.
|
|
|
|
**⭐ 감사자와 code-review는 대체 관계가 아니다(2026-08-18 실측의 재확인).**
|
|
감사 11라운드가 44건을 잡고 0건으로 수렴한 **직후에** 7건이 더 나왔고,
|
|
그중 셋은 감사 각도 어디에서도 안 나오는 종류였다. 축이 다르기 때문이다 —
|
|
감사자는 **코퍼스 전체의 의미론적 정합성**(A 문서의 결정과 B 문서의 서술이
|
|
어긋나는가), code-review는 **diff 자체의 결함**(새로 쓴 서술 안의 모순,
|
|
새 계약이 기존 계약과 충돌하는가).
|
|
|
|
**⭐⭐ 가장 무거운 발견(HIGH)은 이 라운드의 *처방들이 겹쳐서* 생긴 것이다.**
|
|
`H-113`(splice 무효화를 `index - 1`로)과 `H-119`(`_baseObserver`에
|
|
`bk.invalidAfter = 0`)는 각각 독립적으로 옳은데, 둘이 겹치면서
|
|
**`invalidAfter`가 0이 될 수 있는 경로가 둘** 생겼고 `recompute`의 되감기
|
|
블록엔 클램프가 없었다 — `sum = prefix[0]`(nil) → `sourceList[0]`이 nil →
|
|
**부기가 멀쩡한데 "부기가 깨졌음"이라는 error로 죽는다.**
|
|
|
|
8라운드 손 트레이싱 자체가 *"반영된 결정들이 서로 겹칠 때 성립하는가"*를
|
|
보는 라운드였는데, **그 라운드의 처방들이 겹쳐 같은 종류를 하나 더 만들었다.**
|
|
교훈: 한 라운드 안에서 여러 결정이 **같은 변수**를 건드리면(여기선
|
|
`bk.invalidAfter`), 각 결정을 개별로 검증하는 것으로 부족하다 — 그 변수의
|
|
**값 범위가 어떻게 넓어졌는지**를 따로 봐야 한다.
|
|
|
|
**계약 결정 둘은 사용자에게 물었다** — `Subscribe`는 idempotent가 아니고
|
|
(`canBound` 게이트에 걸려 error), `WeakUnsubscribe`는 강한 킵이 남아 있으면
|
|
error. 둘 다 fail-fast 쪽. `Unsubscribe`만 idempotent이고 **이 비대칭이
|
|
의도된 것**이라는 것도 같이 명문화했다.
|
|
|
|
### 2차 `/code-review high` — 또 7건, 그중 넷이 1차 수정의 산물
|
|
|
|
1차 반영 **직후** 다시 돌렸더니 7건이 더 나왔다. **폐기된 서술을 만지는
|
|
방식**에 대한 교훈이 둘 나왔다:
|
|
|
|
- **이름만 고치면 죽은 주장이 갓 정비된 것처럼 보인다.** `H-114` 반영 때
|
|
`handle._observers` → `_deps`로 필드명만 바꿨는데, 그 문장이 서술하던
|
|
**동작**(`bindLifetime`이 내부 Observer로 cascade한다)은 `H-58`이 이미
|
|
폐기한 것이었다. 이름이 최신이라 배너도 안 달렸고, 그 결과 살아 있는 확정
|
|
절 안에 **`H-58`이 막은 버그(바인드마다 `Rerun`)를 되살리는 안내**가
|
|
남았다.
|
|
- **폐기 블록에 날짜 마커를 찍지 말 것.** `⛔` 배너 아래 죽은 문단에
|
|
`H-111` 정정 마커를 찍었더니 그 문단만 최신처럼 보였다. 배너만 달고
|
|
본문은 건드리지 않는 게 낫다.
|
|
|
|
나머지 다섯도 전부 "한 곳은 고쳤는데 그걸 요약·인용하는 곳이 안 따라옴"
|
|
계열이다(무효화 절의 머리 문장 vs 표, `rawSwap` 규칙이 표에 없음, 전파 루프
|
|
주석의 `Effect`, 예약 키 개수 2 vs 3, `luau-test` README의 옛 이름).
|
|
|
|
### 3차 `/code-review high` — 7건 더, 그리고 총평
|
|
|
|
**세 차례에서 21건**이 나왔고 **절반 이상이 직전 수정의 산물**이었다.
|
|
(3차는 세션이 직접 호출했다 — `conventions.md`가 *"`/code-review`는 사용자만
|
|
호출할 수 있다"*고 적어뒀는데 **지금은 세션의 skill 목록에 있다.** 그 관례
|
|
문장은 실태와 다르다.)
|
|
|
|
**반복된 실패 모드는 하나다 — 한 자리를 고치면서 그 자리를 요약·인용·정당화하는
|
|
이웃 문장을 같이 안 고침.**
|
|
|
|
- 표에 행만 넣고 헤딩의 개수("인덱스는 셋")와 배치 목록은 그대로 → 새 규칙이
|
|
*"표는 산문뿐이고 코드 경로가 없다"*(`H-3`)는 원래 상태로 되돌아감.
|
|
- 필드 이름만 바꾸고 그 이름이 서술하던 **동작**은 그대로 → 폐기된 cascade
|
|
주장이 갓 정비된 것처럼 보임.
|
|
- 새 dedup의 **근거**를 잘못 적어(*"thread를 두 번 resume"*) 그 근거가
|
|
"thread가 양쪽 테이블에 산다"를 함의하게 됨 → 그 함의를 따라가면 죽은
|
|
코루틴을 영원히 조용히 `resume`하는 경로가 열린다.
|
|
|
|
**감사자는 이 클래스를 구조적으로 못 잡는다.** 코퍼스 정합성(A 문서 vs B
|
|
문서)이 아니라 **방금 쓴 문단 안의 논리**이기 때문이다. 감사 11라운드가
|
|
0건으로 수렴한 뒤에도 code-review가 21건을 낸 이유가 이거다.
|
|
|
|
### 4차 `/code-review high` — 설계 결함 하나가 `H-101`을 역전시켰다
|
|
|
|
**부기 필드가 하나에서 둘로 갈라졌다** — `bk.offsetCacheValidUpTo`(캐시)와
|
|
`bk.offsetSetUpTo`(`:Set` 완료). 옛 단일 `invalidAfter`는 이름째 없앴다.
|
|
결정과 표는 followup의 "`H-101`의 '새 필드를 안 만든다'가 역전됐다" 절이 소스.
|
|
|
|
**이 세션에서 가장 값이 컸던 순간은 사용자가 리뷰를 되물은 지점이다.**
|
|
리뷰가 낸 건 *"`getOffsetAt`이 되감기 신호를 지운다"*였고 나는 그걸 그대로
|
|
옮겨 "(a) recompute 중엔 안 올린다 / (b) 필드 분리" 두 갈래로 물었다.
|
|
사용자 반응: *"그럴리가. getOffsetAt 전부 끝나고 나서야 Set 이 일어나고 …
|
|
순서가 섞일 일이 없어서 되감기 신호가 지워질 일이 안 보이는듯 한데..? 다시
|
|
볼래?"* — **그 지적의 절반이 맞았다.** 한 프리미티브 안에서는 정말 안전하다
|
|
(`rawRemove`가 `getOffsetAt`을 splice **앞**에서 부른다). 다시 트레이싱해서
|
|
**한 콜백에 CRUD 두 번**(`Remove` 뒤 `Add` → `setOffsetSource` → `getOffsetAt`)
|
|
이라는 실제 경로를 찾아내 보이자, 사용자가 **패치가 아니라 근본 원인**을
|
|
짚었다: *"Set을 해줬느냐와 캐시가 유효하지 않느냐라는 다른 목적의 값을 같은
|
|
값이 쥐고 있음. 그것 자체가 문제였는듯."*
|
|
|
|
교훈 셋:
|
|
- **리뷰 결과를 그대로 사용자에게 넘기지 말 것.** 내가 먼저 트레이싱해서
|
|
"어느 경로로 도달하는가"를 확정했어야 했다. 실제로 같은 라운드의 다른
|
|
발견(materialize 꼬리 게이트가 사후조건을 깬다)은 **직접 확인해보니 틀렸다**
|
|
— `bk`가 그 Slot 자신의 부기라 게이트가 발화하면 바깥 루프가 어차피 확정한다.
|
|
- **"두 뜻이 실제로 같다"는 확정은 의심할 것.** `H-101`이 그렇게 적고 새 필드를
|
|
거부했는데, 그 통합이 정확히 버그의 원인이었다. 같은 값이 두 질문에 답하고
|
|
있으면 **언젠가 한쪽만 갱신되는 경로가 나온다.**
|
|
- **이름이 뜻을 겸하면 그 이름부터 없앨 것.** 사용자 지적으로
|
|
`invalidAfter`를 남기지 않고 완전히 치환했다 — 남겨두면 읽는 쪽이 옛 의미를
|
|
그대로 가져온다.
|
|
|
|
### 5~7차, 그리고 멈춘 이유
|
|
|
|
5차 6건 / 6차 8건(**HIGH 3, 전부 5차 수정의 산물**) / 7차 5건(**HIGH 0**).
|
|
항목은 followup이 소스. 6차가 정점이었고, 거기서 나온 규칙 하나를 명문화한
|
|
뒤 7차는 HIGH가 없었다.
|
|
|
|
**⭐⭐ 이 세션 최대의 교훈 — 나는 같은 실수를 네 번 했다.**
|
|
`_observers` → `_deps`(1차), `CheckReservedKeys`(3차), `invalidAfter` →
|
|
`offsetSetUpTo`(5차), 그리고 6차의 인용문 오염. **전부 "토큰을 바꾸고 그
|
|
토큰이 든 문장은 안 읽음"**이다. 6차 건은 한 걸음 더 나아가 **역사 기록까지
|
|
오염**시켰다 — *"옛 이름을 완전히 없앴다"*는 내 선언이 정정 배너 **안의
|
|
인용문**에까지 적용돼, 폐기를 서술하는 문장이 자기가 폐기한 것의 새 이름을
|
|
쓰게 됐다.
|
|
|
|
> **규칙**: 전역 치환은 **인용문·절 제목·정정 배너를 건드리면 안 된다.**
|
|
> 그 셋은 *과거에 무엇이라고 적혀 있었는가*를 보존하는 게 목적이라, 새
|
|
> 이름으로 바꾸는 순간 목적이 무너진다. 치환 전에 제외 목록에 넣을 것.
|
|
> 그리고 치환 뒤에는 **바뀐 토큰이 든 문장 전체**를 다시 읽을 것 — 토큰만
|
|
> 맞추면 그 문장이 설명하던 불변식이 바뀐 걸 못 본다.
|
|
|
|
**7차에서 멈춘 판단**: HIGH가 나온 라운드는 **전부 직전에 구조를 바꾼
|
|
뒤**였다(필드 분리, 새 가드, 게이트 추가). 7차 수정 5건은 문장/줄 단위 국소
|
|
정정이고 새 계약도 대규모 치환도 없어, 반복된 실패 모드가 적용될 표면이
|
|
없다. 커밋 안 된 36파일 diff 자체도 리스크라 여기서 체크포인트를 만든다 —
|
|
이후 검토는 커밋 대상으로 언제든 가능하다.
|
|
|
|
### 남은 미검증
|
|
|
|
- 7차 수정분 자체(위 판단으로 감수).
|
|
- 8라운드 §6의 "못 본 것"은 그대로 — 특히 **M5+ 구간은 문서 정독 수준**이고
|
|
값 단위 트레이싱을 안 했다. 다음 라운드가 있다면 거기가 최우선.
|
|
- 실측 스파이크는 `luau-test/STATUS.md`가 소스. 이 세션이 항목 넷을 더했다
|
|
(`11` 재작성, `16`/`21` 최종형 + 빈 Store 대조군, `CheckedQuad` M2 후 재실측).
|
|
|