렌더 입자성 캠페인 Phase 4-2·4-3 — 달력 판정(이관 안 함) · 로그테이블 분리
통합 기록(형식 표준, Phase 현황·결과·남은 것): 2026-08-24-render-granularity.md
- 날짜: 2026-08-23 (Phase 4-1 위에 스택, 오너 결정 D2 (나))
Phase 4-2 달력 — 판정: 이관하지 않는다 (중단 규칙)
미적재 월 이동 1회의 루트 커밋 6회를 스토어 통지 시간선으로 풀어 보면(임시 진단, 개발 React):
| t | 통지 | 루트 커밋 |
|---|---|---|
| 25 ms | 선택 일 상세 로딩 시작(selectedDayLoadingDate) | 1 (클릭의 React 상태와 같은 커밋) |
| 32 ms | 인접 월 프리페치 시작(loadingMonthKeys) | 1 |
| 48 ms | 프리페치 결과 발행(monthModels, startTransition) | 1 |
| 56 ms | 프리페치 완료(loadingMonthKeys 해제) | 1 |
| 63 ms | 일 상세 발행 + 로딩 해제(같은 틱 → 배칭) | 1 |
| — | 클릭(setVisibleMonth·setSessionDate) | 1 |
여섯 커밋이 각각 화면이 보여야 하는 별개 상태 전이다(달력 스켈레톤·인접 월·일 상세). 합칠 수 있는 것은 "프리페치 발행 + 완료" 한 쌍(6 → 5)뿐이고, 달력 모델은 홈·일 요약·쓰기 커맨드 env 등 루트 소비자가 넓어 루트 구독을 뗄 수 없다. 효과가 실측되지 않는 화면은 이관하지 않는다는 Phase 4 중단 규칙에 따라 달력 바인딩은 하지 않는다(통지 한 쌍 병합도 계약 재조준 대비 이득이 작아 보류).
Phase 4-3 로그테이블 — 루트 구독 분리
루트는 로그테이블 상태를 렌더에 쓰지 않고(데스크톱 셸만 소비) env 주입·커맨드·dataTick 정리만 한다 → 토스트와 같은 완전 분리.
| 항목 | 파일 | 내용 |
|---|---|---|
| 어댑터 | controllers/logTableController.ts | uSES 구독 제거 — env 주입 + 커맨드(월 행·셀 상세 로드·정리·리셋)만 반환 |
| 조립 루트 | appController.tsx | renderCtx 5키 은퇴: logTableRowsByMonth logTableCellDetailsByKey logTableCellDetailLoadingKeys logTableCellDetailErrorsByKey logTableLoadingMonthKeys (164 → 159). 커맨드·라벨 키는 유지 |
| 데스크톱 셸 | desktopApp.tsx | useOwnerStores().logTable을 uSES로 직접 구독(기존 memo·이펙트 무변경) |
검증
npm run check1807/1807 ·check:unused. 재조준 0(계약은 데스크톱 셸의 memo 호출 형태를 읽고 있어 그대로 통과).- 브라우저 회귀 CASE-002·016(데스크톱)·004(모바일) 3/3(프로덕션 빌드).
- Phase 0-2 계측 시나리오 ③(프로파일 런이 로그테이블 탭·셀 드로어를 실제로 구동).
전 → 후 (개발 React · CPU 4×)
| 상호작용 | 루트 커밋 | 커밋 | 커밋 시간 합 |
|---|---|---|---|
| ③ 로그테이블 탭 진입 | 4 → 1 | 6 → 6 | 270 → 142 ms |
| ③ 셀 열기 (×2) | 2 → 0 | 4 → 4 | 154~162 → 53~63 ms |
남은 커밋은 데스크톱 셸(GymDesktopApp)의 재렌더 — 루트(약 1,900줄 훅)와 모바일 몫이 빠진 값이다.