P1-T2 제목 전용 롤링 증거
제품 변경은 SodaLive/Sources/MyPage/MyPageView.swift의 UpdateBannerView 표시 구조뿐이다. Text의 identity·기존 비대칭 전환을 제목용 ZStack 안에 두고 그 영역을 clip했다. 화살표는 고정된 HStack 형제이며 Button에는 identity·전환이 없다. 기존 if-let, 현재 공지 상세 callback, padding 이후 contentShape, 글꼴·색상·제목 폭, 5초 Timer·생명주기·Reduce Motion 경로는 유지했다.
제품 SHA-256: af77569942c0bbdbad0242431362b5987dc278d8f70d015ccc1ef675b2b264ed.
작업 전 SHA-256: 7f8ac15573ab4c9fe01508431297e40d2e95a22ad37585859f03224475749d02.
현재 파일의 배너 부분을 기존 retained 배너로 메모리에서 치환한 해시가 작업 전 파일과 일치한다. 배너 밖 기존 작업은 그대로다. 이 확인은 변경 범위 증명이며 UI 동작 테스트가 아니다.
네이티브 확인
기존 ../native-fix/rerun-154222/source/Harness.swift를 재사용하고 임시 복사본의 run() 시나리오만 축소했다. 루트 뷰·캡처 구현은 동일하다. 현재 제품 배너와 실제 helper/DTO/font/spacing/color를 추출하여 UIKit UIHostingController로 컴파일했다. Pretendard-Regular 폰트도 앱에 포함했다. 전체 SodaLive 앱이나 웹 모사가 아니다. 입력과 대체한 AppState sink·LanguageOption은 provenance.json, 실행한 정확한 명령·exit·출력은 commands.json, 컴파일 입력은 source/에 있다.
전용 iPhone SE3 / iOS 18.3 / 375pt 폭에서 새 native drawHierarchy PNG 10장을 생성했다. 모든 PNG의 signature·750×1334 크기·추출 배너 이후 생성 여부를 검사했다. 전체 배너 비교판 및 원본 frames/를 직접 열어 확인했다. 원본 PNG를 수정하지 않았으며 *-banner.png는 명시적인 관찰용 crop이다.
| 시나리오 | 근거와 관측 |
|---|---|
| 2개 첫 교체 | frames/two-rest.png 첫째 → two-end.png 둘째, 제목 영역 변경 2,213px |
| 마지막 → 처음의 rest/mid/end | frames/wrap-rest.png 둘째 → wrap-mid.png 두 제목의 세로 이동·제목 영역 경계 clipping → wrap-end.png 첫째. 제목 변경은 rest→mid 3,857px, mid→end 3,796px |
| 1개 고정 | frames/one-rest.png와 one-after-6s.png의 제목·화살표 영역 동일 |
| 긴 한글 제목 | frames/long-dark.png, long-light.png: 한 줄 ellipsis, 화살표 비겹침, 배너 영역 동일 |
| 화살표 고정 | 10장 모두 crop [654,267,702,339)에서 변경 픽셀 0. 화살표 실제 nonblack 경계 [672,289,689,318)도 동일 |
화살표 RGB 해시: bbea1dbee839fd83d527bd7dedeb600b983053e8ad39b68b23e64c7982410fb6.
제목 관찰 영역은 [48,267,638,339), 배너는 [0,267,750,339)이며 좌표는 px이다. comparison.json에 각 프레임의 해시·신선도·픽셀 수·화살표 경계를 기록했다. wrap 종료 제목은 최초 첫째와 동일하고 wrap 시작은 둘째 종료와 동일하여 실제 순환도 대조했다.
two-mid.png는 예약 시각과 실제 렌더링의 차이로 전환 전에 캡처되어 rest와 같다. 이를 중간 전환의 증거로 간주하지 않는다. 실제 in-flight 증거는 wrap-mid.png이다. 주기를 단축하거나 제품 Timer를 교체하지 않았으며 정밀 5.000초 측정·프레임 성능 보증도 아니다.
명령과 결과
저장소 루트에서 실행:
python3 "docs/20261028_마이_탭_공지사항_롤링/reviews/evidence/title-only/run.py"
python3 "docs/20261028_마이_탭_공지사항_롤링/reviews/evidence/title-only/compare.py"
xcrun swiftc -frontend -parse SodaLive/Sources/MyPage/MyPageView.swift
GIT_MASTER=1 git diff --check
- runner 내부
bash work/tests/check-my-page-notices.sh: exit 0, 기존 실제 소스 회귀 검사 PASS 4줄. focused-check.log. - 실제 추출 배너 native 컴파일
xcrun --sdk iphonesimulator swiftc -sdk <SDK> -target x86_64-apple-ios16.6-simulator -module-cache-path <own-root>/module-cache <source/*.swift> -o <own-root>/NoticeNativeQA.app/NoticeNativeQA: exit 0. 확장된 모든 인자는commands.json참조. - 제품 Swift parse와
git diff --check: exit 0. LSP 도구는 제공되지 않았다. - 비교 스크립트: exit 0, 화살표 불변 10장·2개 순환·1개 고정·긴 제목·배너 밖 변경 없음 확인.
자원 정리와 한계
소유 root는 /var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/notice-title-native.8wiga1c7, device는 25EC20C1-F057-4DAD-BD61-A287C5D942C7였다. TMPDIR·임시 캐시 환경변수를 소유 root 하위로 지정하고 atexit 정리를 등록했다. 앱 종료·전용 device shutdown/delete·root 삭제 후 부재를 확인했다. 실제 launch PID를 ps -p <pid> -o pid=,command=로 재확인하여 exit 1·출력 없음도 기록했다. cleanup.json이 영수증이다. 부모 root notice-title-only.i9lFW3와 공유 simulator/cache는 수정하지 않았다.
물리/좌표 탭·padding hit-test·전체 상세 이동, VoiceOver·Reduce Motion 런타임 설정 변경, 다른 폭·실기기·iOS16.6 실행은 미검증이다. 전체 앱 빌드는 부모 담당이며 수행하지 않았다. API/서버 호출, 다른 제품 코드 수정, 부모 PRD/계획 수정, 새 UI 소스 문자열 테스트, 의존성 추가, 커밋, 다른 에이전트 호출은 하지 않았다. 독립 시각 리뷰 PASS를 주장하지 않으며 이 자료는 지정된 native 범위의 직접 관찰과 픽셀 비교 증거다.