렌더 입자성 캠페인 Phase 0 — 계측 기반선
통합 기록(형식 표준, Phase 현황·결과·남은 것): 2026-08-24-render-granularity.md
- 날짜: 2026-08-23 (오너 결정 D1 (가): Phase 0~1 즉시 착수)
- 로드맵: (c) 군집 경계 → (a) 스토어 확산 → 렌더 입자성(이번)
- 계획서: 작업계획서 artifact 2bf2105f (전체 그림 a10c4ec1의 집행 문서)
- 원칙: 숫자 없이는 어떤 Phase도 닫지 않는다 — 이후 Phase의 출구 기준이 되는 "전 → 후" 계측 두 층을 먼저 세웠다.
계측 두 층
| 층 | 무엇을 | 어디에 | 어떻게 읽나 |
|---|---|---|---|
| Phase 0-1 스토어 통지 기반선 | 드래프트 스토어가 콘텐츠 발행 1회에 구독자를 깨우는 횟수 | tests/react/workoutDraftStoreGranularity.test.mjs (React 없이) | 현재 값 3을 고정. Phase 1이 0으로 뒤집을 때 재조준 |
| Phase 0-2 dev 전용 커밋 계측기 | 상호작용 1회당 조립 루트(GymAppController) 커밋 수 · 트리 전체 커밋 수 · 커밋 시간 | main.tsx Profiler(?lgProfile=1, dev 전용) + app.tsx 루트 커밋 카운터 + e2e/profile/renderGranularity.profile.mjs | 로컬 스택 + vite dev 서버에서 스크립트 실행, test-results/render-granularity-profile.json |
실행: E2E_SUPABASE_URL=… E2E_SUPABASE_ANON_KEY=… E2E_SUPABASE_SERVICE_ROLE_KEY=… E2E_APP_URL=http://127.0.0.1:5174 node --import tsx e2e/profile/renderGranularity.profile.mjs (LG_PROFILE_CPU_THROTTLE, 기본 4). 프로덕션 번들에는 두 계측기 모두 들어가지 않는다 (import.meta.env.DEV 분기).
실측 결과 (2026-08-23, 개발 React · StrictMode · Ryzen 5900X)
"루트 커밋" = 조립 루트(useBarbelicController)가 다시 실행된 횟수. "커밋" = 트리 어디서든 일어난 커밋 전부(화면 내부 state 렌더 포함).
| 시나리오 · 상호작용 | 루트 커밋 | 커밋 | 커밋 시간 합 (CPU 4×) | 커밋 시간 합 (CPU 1×) |
|---|---|---|---|---|
| ① 라이브 운동 — 세트 입력 1회 (무게·횟수 변경, ×10) | 2 | 3 | 77~137 ms | 14~18 ms |
| ① 라이브 운동 — 세트 행 추가 | 2 | 3 | 98 ms | 15 ms |
| ① 라이브 운동 — 세트 편집 완료(편집 모드 종료) | 0 | 1 | 6 ms | 1 ms |
| ① 라이브 운동 — 세트 완료 체크 (×2) | 2 | 3~5 | 108~129 ms | 19~24 ms |
| ② 달력 — 홈에서 일지 탭으로 | 8 | 9~10 | 463 ms | 67 ms |
| ② 달력 — 이전 달 이동(미적재 월, ×3) | 6 | 6 | 304~371 ms | 43~65 ms |
| ② 달력 — 다음 달 이동(적재된 월, ×3) | 1~3 | 1~3 | 52~157 ms | 7~25 ms |
| ③ 로그테이블 — 탭 진입 | 4 | 6 | 270 ms | 42 ms |
| ③ 로그테이블 — 셀 열기 (×2) | 2 | 4 | 154~162 ms | 21~23 ms |
단일 커밋 최대: CPU 4× 79 ms · CPU 1× 14 ms. 커밋 수는 두 런에서 동일(결정적).
읽기
- 세트 입력 1회 = 루트 재실행 2회. 편집 표의 입력은 변경마다 드래프트를 갱신하고 스냅샷을 즉시 1회 + 700ms 디바운스 1회 발행한다. 발행 1회에 스토어 통지는 3건 (스냅샷 커밋·잠금 인텐트 객체 교체·동일 제목 재설정)이지만 같은 틱 안이라 React 18 자동 배칭이 루트 커밋 1회로 합친다. 따라서 구조 예측 상한 6은 2로 수렴 — 발행 1회 = 루트 커밋 1회. Phase 1의 출구는 "세트 입력당 루트 커밋 0"으로 그대로 유효하다.
- 달력 월 이동(미적재)은 루트 재실행 6회. 읽기 모델 적재 단계(로딩 키 → 월 요약 → 일 상세 → 전경 키 해제…)마다 루트가 통째 다시 실행된다. 적재된 월은 1회다.
- 절대 시간은 개발 React 값이라 기준선(D2, 16 ms)과 직접 비교할 수 없다. CPU 1×에서 단일 커밋이 7~14 ms, 4×에서 50~79 ms — 전후 비교(상대값)에만 쓴다.
다음
- Phase 1(핫패스 격리)은 D1 (가)에 따라 즉시 착수. 출구: Phase 0-1 단언 3 → 0, 시나리오 ① 세트 입력당 루트 커밋 2 → 0.
- D2(중단 기준선)는 이 숫자와 함께 오너에게 재상정 — 시나리오 ②·③의 Phase 2~4 진행 여부를 정한다.