화면 크롬 기하 소유권 — 도크 4상태 항등에서 크롬 상태 단일 채널까지 (2026-08-27)
- 기간: 2026-08-26 ~ 08-27 (조사 1세션 + 집행 1세션, 오너 결정 D1~D3 + 방향 A→B′ 확정)
- 랜딩: PR #858(Phase 1) · #860(Phase 2) · #861(Phase 3) · #863(Phase 4) · #865(Phase 5) · #867(Phase 6) · #869(Phase 7) · 본 기록 동반 PR(Phase 8) — 마이그레이션 없음
- 설계서: 이슈 #855 계획서(A→B′ Phase 1~8 + 오너 결정 3건) · 조사 정본 = 아티팩트 「도크 높이 항등 대책」(에이전트 12 + 실 CSS 하네스 실측 + B-full 적대 검증)
- 정본: workout.css 도크 기하 계약 C′ 주석 블록 ·
--dock-stage-h/--bottom-chrome-h/--chrome-hush(tokens/nav/core) ·lib/BrandRow.tsx(워드마크 단일 렌더러) ·shell/MobileShellFrames.tsxMobileShellBody(통합 셸) ·shell-frames.md§2-1 - 게이트:
e2e/dock-geometry.spec.mjs(full-ci — 실플로우 4상태 × safe 0/34 실측·항등·오버플로·채널 등가·클리어런스 쌍) +tests/react/dockGeometryContract.test.mjs(scope 레인 — 규칙·스위치 잠금) + DELIVERY-CONTRACT 적용 절차 5항 - 버그리포트: 신규 없음 — BUG-028에 후속 정정 각주(구 실측 "전 도크 166"은 픽스처 케이스 공백). 트랙 밖 수리 2건: CASE-004 스테일 기대(#852 여파)·CASE-019 시간대 시한폭탄(서버측은 이슈 #859 분리)
- 계약: C2′(총높이 소유자 = 도크 프레임 — #801 C2 "높이=콘텐츠" 개정) · 크롬 상태 채널(shell-frames §2-1) · workout-screen-props 도크 기하 절 · CHANGE-NOTES 재싱크 필수 등재 2건
Phase 현황
| Phase | 내용 | 상태 |
|---|---|---|
| Phase 1 | 기반 — 상설 기하 게이트(기록 모드)·계약 C2′ 개정·편집 행 인셋 유도식(D2)·BUG-028 정정 | ✅ #858 |
| Phase 2 | 도크 4상태 항등 — --dock-stage-h 스테이지 + 행 위생, 항등 단언 점등 | ✅ #860 |
| Phase 3 | 탭바 height 소유권 역전 + 워드마크 단일 렌더러(9사이트) + 단언 점등 | ✅ #861 |
| Phase 4 | A 마감 — 정적 계약 게이트 + 훼손 시뮬 + 반입 계약 등재 | ✅ #863 |
| Phase 5 | 크롬 상태 단일 채널(data-bottom-chrome + 높이 사상표) + 등가 게이트 | ✅ #865 |
| Phase 6 | 클리어런스 응집 — 탭바 계열 유도식 1규칙(+화면별 숨 토큰), 쌍 불변 증명 | ✅ #867 |
| Phase 7 | 탭바 숨김 단채널화 — 플로우·친구 스코프 DOM 감지 3규칙 → 채널 2규칙 | ✅ #869 |
| Phase 8 | D3=B 통합 셸 프레임 + 계약문 개정 + 기록 | ✅ 본 PR |
1. 배경
오너 보고 3건이 한 병의 세 발현이었다: ① 운동 진행중 4상태(세트 진행중·세트 휴식·종목 완료 대기·종목 완료 확정) 도크 높이가 "뭐만 바꾸면" 어긋남 ② 우상단 워드마크 위치가 페이지마다 다름 ③ 탭바도 수정하다 보면 높이가 달라짐. 조사(에이전트 12 + 실 CSS 하네스) 결과 병명 하나 — 크롬 기하를 콘텐츠·수기 산수가 소유: 높이는 콘텐츠 파생, 명목 토큰(--dock-h 164·--tabbar-h 68)은 "변경 시 수기 동조" 추종자, 크롬 회피 클리어런스 25규칙이 7파일 분산, 가시성 판단은 JS+CSS :has() 이원 채널, 자동 게이트 0건. 실측(safe=0): 도크 164/164/132/128 — 직전 BUG-028(#801)의 "전 도크 166 동일" 종결 실측은 진행중 픽스처에 텍스트 버튼이 빠진 케이스 공백이었다.
2. 문제 제기
- 4상태 항등은 구조가 보장한 적이 없다: 상태별 콘텐츠 스택 합 + CSS 주석 속 덧셈("16+34+10+4+8+48+32 = --dock-h-12")이 유일한 유지 장치 — 문구·폰트·마진·조건부 요소(세트 실패 = reps 프로필만) 하나로 특정 상태만 이동.
- 리뷰 도크만 폰트 메트릭 파생(웹폰트 미로딩 +2.67px·장문 종목명 랩 +16px — 민감도 10종 중 움직인 유일 상태), border-top 1px 단독 가산.
- 08-11 탭바 64→68 상향 때 소비처 미동조 드리프트가 실증된 전력 — 소비처가 "못 들은" 사고 계급.
- 급진안(B-full: grid 물리 행·상시 상단 슬롯·탭별 스크롤 보존)은 적대 검증에서 기각 — 반투명 블러 언더랩·슬라이드업 기구·"탭 이동=맨 위" 계약과 충돌, 수익 대부분은 소유권 단일화(B′)로 회수 가능.
3. 해결 방안
- 원칙(오너 결정): 방향 = A(표면별 계약+게이트) → B′(크롬 소유권 단일화), 중단 없이 Phase 1~8 완주. D1 도크 슬랙 = 콘텐츠 상단 배치(전환 시 캡션·버튼 y 부동). D2 편집 행 인셋 = 값 불변 유도식
calc(var(--dock-inset)+4px). D3 = B안 운동 이중 프레임 통합을 Phase 8에 포함. - 접근: 물리 배치(오버레이·블러·애니·스크롤 계약) 불변 — 앎의 소유자만 단일화: 총높이 = 프레임(
--dock-stage-h), 탭바 높이 = 토큰, 워드마크 골격 = 단일 렌더러, 크롬 상태·높이 = 채널 1개, 클리어런스 = 유도식 1규칙. 보호는 소재가 아니라 계약 잠금+게이트(v77이 MobileShell.tsx를 배송으로 덮은 실증).
4. 적용한 내용
- Phase 1~2 (도크 항등):
.wf2-stage(height 136 고정·min-height 금지·flex column) 4곳 + 직계 셀렉터 2곳 이전 + 행 위생(리뷰 힌트 46 존·lh 17 핀·.txt말줄임 — 유일한 랩 경로 봉쇄 / nx-go lh 17 = nx-free 동형 존 / 리뷰 행 마진 8→10 = 메인 존 y 4상태 동조 / border-top → inset shadow = 유일한 +1px 채널 폐지).--dock-h는 유도식으로 재정의(값 164 불변 → 소비처 4곳 무수정). - Phase 3: 탭바
height: calc(var(--tabbar-h)+safe)소유권 역전(시각 0 — 현행 실측 정확히 68) + 라벨 lh 13 핀.UiBrandRow신설,.mb-brand9사이트 verbatim 치환(홈 히어로·온보딩·게이트는 의도 별계열 잔존 명시). - Phase 4: 정적 계약 게이트(규칙 + 게이트 스위치 자체 잠금) + 훼손 시뮬 2종 실패 확인 + DELIVERY-CONTRACT 적용 절차 5항.
- Phase 5~7 (B′): 컨테이너가 하단 크롬 열거값 게시(
data-bottom-chrome, 탭 구독 리전 격리 유지 — 레이아웃 이펙트 DOM 속성, 루트 재렌더 0) + nav.css 높이 사상표 → 등가 게이트 점등 → 클리어런스 유도식 1규칙(개별 8규칙 응집, 쌍 불변 136/68/82/68 전후 증명) → 탭바 숨김 DOM 감지 3규칙을 채널 2규칙로(숨은 판 마커 오염·fsb lazy 번쩍임 계급 원천 소멸). - Phase 8 (D3=B):
MobileShellBody통합 — 탭·플로우가 같은.app엘리먼트 공유(모드 전환 = 콘텐츠 교체, 기둥 재마운트 소멸), 계약문 개정(shell-frames §2-1·workout-screen-props C′ 절)·CHANGE-NOTES 재싱크 등재. - 작업 중 드러난 것: ① CASE-004가 main 수준에서 깨져 있었음(#852 피드 세트 축약이 스코프 레인만 돌고 랜딩 — 풀 레인 첫 구동에서 발견, 기대 2곳 수리) ② CASE-019 시간대 시한폭탄(스펙의 서울 오늘 achievedOn vs 서버 UTC current_date — KST 00~09시 창 전 레인 실패; 테스트는 UTC 어제로 수리, 서버측 의미론은 #859 분리) ③ 레포 리네임(lifted→Barbelic) 직후 pull_request 이벤트 유실 창(수동 디스패치 우회, 이후 자연 복구) ④ 소스 앵커 테스트 3건 재조준(변수 추출·규칙 이전·프레임 개명 — manifest 신고 1건 병합).
5. 적용 결과
| 항목 | 전 | 후 |
|---|---|---|
| 도크 4상태 총높이 (safe0) | 164 / 164 / 132 / 128 | 164 × 4 (safe34: 198 × 4) — 오버플로 0 |
| 같은 상태의 종목 프로필 편차 | 유산소 진행중 132 (−32) | 164 (스테이지 소유) |
| 리뷰 도크 폰트·문구 파생 | 웹폰트 스왑 +2.67px·장문 랩 +16px | 0 (lh 핀·말줄임·46 존) |
| 탭바 높이 체계 | 실측 추종 토큰("변경 시 수기 동조") | 토큰이 height 소유 — 4탭 68 == 토큰 단언 |
| 워드마크 | 4계열·13사이트 각자 렌더 | 단일 렌더러 + 의도 별계열, 4탭 y·우측 동일·safe-top 정확 1회 추종 단언 |
| 크롬 가시성·높이 판단 | JS+:has() 이원(숨김 8조건·가드 다수) | 채널 1개(+잔존 :has 4건 명시) — 등가 게이트 상주 |
| 클리어런스 | 개별 규칙 분산(탭바 계열 8) | 유도식 1규칙 + 화면 숨 토큰, 쌍 불변 증명 |
| 기하 회귀 검출 | 0건 (주석 계약 + 실기기 보고) | 2겹 게이트(전 PR 정적 + full-ci 실측), 훼손 시뮬로 발화 확인 |
| 검증 | 유닛 2043 · viewport 레인 13/13 · CASE 스위트(로컬 17/18 — CASE-017은 /api 라우트 부재 환경 요인, CI 그린) · 풀 CI 그린 × 7 PR |
미검증(오너 실기기 일괄 확인 대기): ① 4상태 도크 실기기 시각(완료 대기 +32·완료 확정 +36 커짐 — D1 상단 배치) ② 친구 스코프 열림/퇴장 탭바(채널 전환분 — e2e 미커버, 논리 항등) ③ 이중 프레임 통합 후 플로우 진입/이탈 체감 ④ tabSwitch·renderGranularity 프로파일 전→후 머신 실측은 미수행(구조상 구독 불변·CASE로 행동 검증 — 필요시 후속).
6. 이번 개선으로 향상된 것
- "뭐만 바꾸면 어긋난다"의 종결: 높이·위치·가시성의 앎이 각각 정확히 한 곳(토큰·렌더러·채널)에 있고, 계약은 주석이 아니라 CI가 지킨다(스위치 소등도 위반).
- 사고 계급 3종 구조 소멸: 소비처 미동조 드리프트(08-11류) · 숨은 keep-alive 판 마커 오염(#831류) · fsb lazy 이중 게이트 번쩍임(08-25류).
- 디자인 반입 내성: 구 base 되덮기(#384류)가 사람 눈 → 전 PR CI 실패로 이동, DELIVERY-CONTRACT 절차 5항 + CHANGE-NOTES 재싱크 등재.
남은 것
- 디자인 캔버스 재싱크(대기 중 GroupScreen 델타 배송은 base 교집합 재확인 필수 — CHANGE-NOTES 경고 등재). ui-v80 반입(#862)은 이미 새 구조 위에 정상 통합됨(UiBrandRow children 슬롯 활용 — 게이트 첫 실전 통과).
- 서버측 achievedOn 시간대 의미론(이슈 #859) — 본 트랙 밖.
- 잔존 :has() 4건(상세 3종 시트 스왑 예외·댓글 시트·빈 홈 FAB)은 화면·레이어 로컬 신호라 승격 대상 밖으로 판정 — 계약에 명시.
종결 — 오너 확인 2026-08-27("잘 구현된 거 같으니까 종료할게"), 이슈 #855 닫음. §5 미검증 4건은 오너 확인으로 일괄 갈음.