최종 소스 Native QA 재실행
현재 production 캐러셀 SHA256 7e25db3076d545ffc61ea3a1c5585e7b8a617964ef406d7570286d75a75e010a로 기존 native matrix 재실행과 평가·정리를 완료했다. 실행한 시나리오는 PASS이며 physical tap/swipe와 Reduce Motion ON은 NOT RUN이다. REV-P1-001의 현재 소스와 캡처 연결을 보완하는 증거이며 독립 reviewer의 종료 판정을 대신하지 않는다.
출처와 변경 범위
- 실행일: 2026-10-30 KST. 부모 소유 iPhone SE3/iOS 18.3
482F7827-2E3A-4559-BAF4-48B68CC5725B, 375×667pt, 2x를 재사용했다. Xcode 26 SDK, Swift 5,x86_64-apple-ios16.6-simulatorcompile이다. iOS 16.6 런타임 실행은 아니다. - 기존 native/source의
run.py,assess.py,cleanup.py,Doubles.swift,Harness.swift를 그대로 재사용했다. 변경은 evidence root, own temporary root, own bundle뿐이다. provenance-before.json과 provenance-after.json의harnessCloneChecks가 경로 정규화 후 5개 파일 동일성을 assert했다. 시나리오, 대기 시간, 입력 fixture, geometry 검사는 변경하지 않았다. - 실제 production 9개 파일의 원본 경로를
swiftc입력으로 사용했다. production-source-snapshot은 전체 입력 9개의 byte-identical 보존본이며 컴파일 입력은 이 보존본이 아니다. commands.json에 원본 경로와 실제 native 명령·stdout/stderr·exit가 있다. - source-hashes-before.json, source-hashes-after.json, source-hashes-final.json, teardown 이후 provenance까지 9개 입력과 snapshot의 해시가 일치한다. source-stability.json은
unchanged=true,changed=[]이다. - 기존 native 최종 해시
1bf03b8b1e05310acce09f12b2f09b35af3587f4a7d486b22945ec502cfb506d와 비교하면 9개 입력 중 캐러셀만 다르고 나머지 8개는 같다. 전달받은 delta는@GestureState isSwiping, tap guard,highPriorityGesture→simultaneousGesture, swiping 중 자동 전환 생략, 수평 우세 drag 및onEndedguard이다. 현재 전체 snapshot에서 이 처리를 확인했다. 과거 캐러셀 전체 소스는 기존 evidence에 없으므로 과거 byte 단위 diff를 재구성했다고 주장하지 않는다. 배치·비율 변경은 요청되지 않았고 이번 실행에서 제품 수정은 없었다.
기존 native/ 62개 파일과 PRD·plan·기존 리뷰 3개, 합계 65개 보호 파일의 해시 및 파일 목록이 전후 동일하다. 기존 증거·해시를 덮어쓰지 않았다. 추가한 source/provenance.py는 snapshot·보호 파일·의존성 해시와 소유권을 기록하는 증거 보조 도구이며 UI 하네스 동작은 바꾸지 않는다.
실제 실행 Surface와 명시적 대역
production SubBanner.swift, SubBannerLinkOpener.swift, SubBannerCarousel.swift, 두 recommendation View composition, 실제 spacing/color/hex/font 소스를 원본 경로에서 컴파일했다. 기존 prebuilt Kingfisher object/module을 읽기 전용으로 링크했고 전후 해시 동일성을 확인했다. 실제 KFImage와 downloader를 사용한다. dependency-hashes.json 참조.
기존 FixtureProtocol을 실제 Kingfisher의 ephemeral URLSession에 연결했다. subbanner.qa.invalid만 로컬 생성 PNG로 응답하고 다른 요청은 로컬에서 실패한다. 인터넷·계정·서버는 사용하지 않았다. A=1200×400 teal, B=1200×600 orange이다.
source/Doubles.swift의 하위 추천 섹션은 48pt QA ... bar 또는 EmptyView, VM/DTO는 fixture, refresh wrapper는 ScrollView, toast/purchase/media player는 무효 대역이다. production 두 View의 조건부 삽입과 VStack(s24)는 실행하지만 실제 추천 카드·기존 메인 배너 carousel·API/인증/filter/콘텐츠 isEmpty·구매·refresh 전체를 검증하지 않는다. 오류 격리는 주변 대역 bar 유지에 한정한다.
매트릭스와 실제 관측
captures/actions.json의 finished는 launch 기준 monotonic 210.953초에 기록됐다. 41개 앱 window drawHierarchy PNG와 별도 native-os-final.png, 총 42개 native 원본 모두 750×1334이고 production 소스보다 신선하다. verification.json에 PNG별 hash·크기·freshness와 geometry가 있다. contact-1.png~contact-4.png는 41개 앱 캡처 전체를 포함하는 검토용 축소 배치이며 새로운 UI가 아니다.
| 시나리오 | 판정 | 이번 실행에서 확인한 증거 |
|---|---|---|
| 홈 지정 위치 | PASS | home-first: QA active creators 뒤, debut 앞 |
| 콘텐츠 지정 위치 | PASS | content-first: QA main banner 뒤, exclusive 앞 |
| 전체 폭·원본 비율 | PASS | 양 화면 A: x0/w375/h125pt, B: x0/w375/h187.5pt. Home y280, Content y136 |
| s24·empty 추가 gap0 | PASS | 이미지 위아래 24pt. home-empty, content-empty는 일반 섹션 간격 24pt만 유지 |
| 실제 5초 자동 전환·2항목 wrap | PASS, 정밀도 한정 | Home 시작 후 4.523초 A → 5.374초 transition → 6.118초 B. Content 4.791초 A → 5.640초 transition → 6.387초 B. 두 wrap 캡처는 A/01/02 |
| 단일 고정 | PASS | 양 화면 one과 one-after-6s의 PNG SHA 동일, 01/01. 실제 관측 간격 Home 6.048초, Content 6.069초 |
| 21개·20개 제한 없음 | PASS | many-first 01/21 → many-twenty-first 20/21 → many-wrap 21/21 → OS final 02/21. timer/index를 직접 바꾸지 않음 |
| 컨테이너 resize | PASS | 양 화면 부모 frame 375→320pt, 배너 x0/w320/h106.6667pt. 실제 회전/기기 resize는 아님 |
| 지연 이미지 비율 격리 | PASS | 초기 direct 높이0 → 유효 B 높이187.5 → 지연된 A 도착 뒤에도 B/187.5 유지 |
| 실패 이미지 국소 처리 | PASS | failure-placeholder-other-content: 회색125pt/02/02와 주변 QA bar 유지 → failure-wrap-valid A |
| inactive/active | PASS, 주입 환경 | 실제 scenePhase probe inactive 확인, 6.512초 간격 PNG SHA 동일 B. active 주입 후 4.837초 B, 6.345초 A |
| unmount/remount·목록 축소 | PASS | unmounted 캡처는 하네스 제목만 유지. remount-first A → remount-next B → shrink-one A/01/01 |
| light/dark | PASS, 범위 한정 | 두 화면 light 캡처가 dark first와 동일한 검정 배경·읽을 수 있는 indicator 유지. 하네스 window override이며 전체 앱 system theme 검증 아님 |
| 링크 fallback driver | PASS, 탭 아님 | production opener에 false completion 주입, sodaqa://banner/900 뒤 https://subbanner.qa.invalid/destination 각 1회 |
| physical tap/swipe·세로 scroll 공존 | NOT RUN | 좌표 입력/hit testing 미실행. gesture 소스 존재와 compile을 실제 제스처 성공으로 취급하지 않음 |
| Reduce Motion ON | NOT RUN | OS 관측값 false, 부모 접근성 설정 변경 없음. reduce-* 파일명은 ON 증거가 아님 |
파일명은 예정 촬영 시점명이다. 현재 원본을 직접 열어 many-twenty-first=20/21, many-wrap=21/21, native-os-final=02/21 및 many-2-wide.png를 확인했다. 기존 assess.py에는 이전 실행 관측 native-os-final=01/21이 하드코딩되어 있으므로 script 복제 자체는 유지하고 이번 verification.json의 해당 설명만 실제 캡처에 맞게 수동 정정했다. OS final은 복사와 screenshot 사이에도 timer가 계속 동작한 뒤의 상태다. 21→1 순간 프레임은 없고 21 이후 2가 확인된 범위에서 wrap을 판단한다.
모든 contact sheet와 주요 full-size PNG(두 화면 first/second/transition, 21개 후반 2장, OS final)를 직접 열어 배너·주변 bar 배치, clipping/겹침, fixture 순서와 페이지 번호를 확인했다. 전환 프레임은 A 일부와 B가 함께 보이는 이동 중 상태이며 결함이나 정착 프레임으로 오인하지 않았다. timestamp는 screenshot 완료 후 기록이므로 5.000초 정확도·프레임률·매끄러움·인터럽트·중복 timer 부재를 보증하지 않는다.
명령과 평가
아래 순서로 각 명령 exit0을 확인했다. provenance.py는 Python AST와 clone 동일성도 검사한다. native compile stderr는 비어 있었다. LSP 도구는 제공되지 않았으며 native swiftc 진단으로 대체했다. 전체 앱 build, 집중 CLI checks 재실행, 독립 reviewer 호출은 이번 위임 범위에 따라 하지 않았다.
export TMPDIR=/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/sub-banner-native-final.97cQKj
export NODE_COMPILE_CACHE="$TMPDIR"
export BUN_RUNTIME_TRANSPILER_CACHE_PATH="$TMPDIR"
export PYTHONDONTWRITEBYTECODE=1
python3 docs/20261029_추천_서브_배너/reviews/evidence/native-final/source/provenance.py
python3 docs/20261029_추천_서브_배너/reviews/evidence/native-final/source/run.py
python3 docs/20261029_추천_서브_배너/reviews/evidence/native-final/source/assess.py
python3 docs/20261029_추천_서브_배너/reviews/evidence/native-final/source/cleanup.py
python3 docs/20261029_추천_서브_배너/reviews/evidence/native-final/source/provenance.py --after
assess.py의 assertions PASS: 41 PNG와 OS PNG signature/750×1334/freshness, 원본 소스 해시, 양 화면 전체 폭·A/B 비율·s24·empty·320pt, single 고정, inactive 고정, 지연 이미지 높이 격리, 21개 input, opener 순서. 자동 geometry와 양끝 fixture pixel scan을 교차 검증한다. 페이지 번호 관측은 위 직접 검사와 구분했다.
소유권과 정리
ownership.json에 own bundle qa.sodalive.subbanner.native.final.97cQKj, PID 10884, own root, 부모 device 소유권을 launch 직후 기록했다. cache는 own root 아래 module-cache; shell TMPDIR/NODE/BUN cache 환경은 provenance에 기록했다.
cleanup.json: own app terminate/uninstall exit0, app container 조회 exit2, PID 조회 exit1로 부재 확인, own root와 module-cache 제거, 부모 simulator Booted 유지, production 해시 불변, shared cache 삭제 없음. provenance-after.json은 teardown 이후에도 source/snapshot·기존 native 62개 파일·PRD/plan/review 3개·Kingfisher 입력 해시 불변과 root 부재를 다시 확인했다. device shutdown/delete/reset, 공유 cache 삭제, worktree, commit/push, 의존성 변경은 하지 않았다.
남은 한계: physical tap/swipe/세로 scroll 공존, Reduce Motion ON, 실제 UIApplication.open, OS background/foreground, 전체 SodaLive 앱·실서비스, 실기기/iOS16.6/Dynamic Type/VoiceOver는 미검증이다. 현재 증거 범위의 실행 차단 문제는 없으며 REV-P1-001의 공식 해소 판정은 상위 실행자와 기존 reviewer의 후속 범위다.