Skip to content

R05 — v0.18.0 통합 릴리스 리허설

진행 중. 이 문서는 #1544의 후보·검증 장부이며, release 병합·staging 배포·Production 완료를 서로 구분한다. Production과 R06은 오너의 명시적 재개 전까지 대기한다.

1. 입력과 후보

2026-09-12 KST에 실제 원격 ref를 확인했다. 이후 후보 코드 변경 시 그 변경에 필요한 검증을 다시 연결한다.

입력committree / 이관 꼬리
이전 Production main1587cb7aa368294b9390c63f25b139193dd1ceb3e939049ec1d34eb8d5ab4b8e9ee6fb86ba09be04 / 20260914000000
실제 staging (#1572 포함)044a55f861bc82eeb65fc9205e4e02630508d513d32782bd4a4951fbabab1743433b17669649c98c / 20260914000000
선행 완료 release/v0.18.017ce78123bb5297dedf9fbc34f10ea8f62fcf86fc1aa97c20310a0f190b194506a6c0775185d9584 / 20260915053000
main 통합 중간 커밋f9ac9f8d47b8a0dd429dc2309e09fb803f923f68최종 후보 아님; 다음 staging 통합 필요
초기 통합 리허설 후보39add74bc912bb433c5e1342ae5990554870067btree 28986044147aaeee0e0bbe199f9ed522b2f51b62; main/staging/release 조상 확인. 원격 Full·승격·배포 미실행

최종 Phase3 후보는 7c0a697b3cd1b232d4281300d091a08470e4acb7, treebee5422c0449ab9aecf3a47919610bb533157d70이다. 아직 원격 Full·release 병합·staging 배포 전이다.

기존 main/staging 장부는 각각 188개, 후보 장부는 219개다. 기존 migration 원문을 바꾸지 않고 실제 main 이후 31개를 전부 forward 적용한다. 위험 헤더의 high 10개·medium 1개·나머지 low는 실제 장부와 다시 대조한다. D13 과거 도구 결과 또는 R04 일부 migration 실측은 이번 전체 이관의 대체 증거가 아니다.

독립 산출물연결 버전 / 공개 시점
웹·Edge·DB동일 앱 후보 commit의 산출물. staging DB → Edge → 웹 → smoke 순서 확인 후 공개 판정
관리자별도 저장소가 아니라 Barbelic-docs/admin; 입력 docs main 08962db5778a831df838f1a9a2016352ffc90a96. 타입·local 빌드 및 실제 서버 계약을 구분해 기록
문서Barbelic-docs의 R05 문서 PR. 앱과 SHA를 같게 만들지 않는다
랜딩Barbelic-landing main 109c33e69894459f965f8054d5752503ca62fec3; 이번 앱 배포와 별도 공개 경로
Android / iOSB02의 unsigned Android 성공·Windows의 iOS 미실행을 인계. 이번 후보의 연결 증거는 후속 검증 절에 기록

2. 선행의 완료와 한계

선행release 포함 근거후속 검증에 남는 것
R02 #1541PR #1577 4fe99af0aa1df7882cb6007129933bba65ef4875; docs PR #73실제 배포 v0.17.1 bundle 58e9b047eea319e2b1bae986d355ab5158d41c91. old/new 저장은 성공, new/old 전체 여정은 미지원 RPC로 실패. native/provider 인증 전체 미실행
R03 #1542PR #1575 607647efb894404e583df910153b2c0dae0e656e; docs PR #74실제 9/9 사본 복원·선택 가족 원본/관계/통계 보존. 그때 사본 나이 32.27h >24h; 원본 Motra/InBody 파일 미확보
R04 #1543PR #1579 17ce78123bb5297dedf9fbc34f10ea8f62fcf86f; docs PR #77작업 완료와 G04 전체 수락은 다름. mixed write p95 40ms 실패, 10인 작업 확인 종료 지연 악화, freshness 기준선 비동등. 예산 완화 없음
U06 #1540PR #1578 63926b10ddead8db71a5be0458afdb72b7789dd; docs PR #75실제 최종 staging 15 CASE는 R05 배포/smoke 이후, R05 종료 이전에 실행. 이전 53개 검사의 여러 후보 결과를 하나의 최종 후보 성공으로 합산하지 않음
D13 #1287PR #1322 bf9064973d250043351b148336ebc7347f5d6446기존 max lock 5017ms >5000ms는 실패. 이번 31개 전체 populated 이관 별도 실행
B02 #1332PR #1356 7b44295e84bfe7999fd31ecde77ee0ad1659b386Android unsigned와 iOS/provider/native 실제 실행의 범위를 구분

R04의 10년 index fixture는 RPE8이어서 고강도 부분 index 대상 행이 0개였다. 따라서 이번 대표 workload에서 해당 index의 실제 대상 행을 확인하고, 과거 288ms만으로 밀집 index 비용을 합격 처리하지 않는다. R04의 원래 compute 60초 실패·후속 수렴, concurrent source-changed 40001, 모바일 DOM 317>294 및 구 기준선 비동등도 보존한다.

3. 검증 판정표와 중단 조건

검사구분현재 근거 / 종료 조건
로컬 static·unit·웹 빌드필수main 통합 check 3877=3745P+0F+132조건부 제외. staging 통합 마지막 결과는 아래 기록
persistence browser필수main 통합 105P; staging 통합 118P/0F/0skip. 서로 다른 후보를 합쳐 단일 실행으로 세지 않음
DB replay·schema·pgTAP·DB suite필수최종7c0a697b Precheck 전체P: replay219·schema·pgTAP122/2444·전 DB묶음·660세션 수렴
populated main → 후보 31 migration필수실제 사본·4년 이력 모두 수리 후 전체31개 합격. 첫 잠금 실패2회 보존. 아래 실행별 근거 참조. 사실 값·ID·source·자식 관계·receipt·필수 이력 비의도 차이 0, 파일당 ≤60000ms, probe lock ≤5000ms, 오류 0
구형 입력·영수증·worker 전환·full rebuild필수실제배포본 공존8P·사본복구/실패재개P·최종 DB상태전환/복원후재저장/full수렴P. 입력별 증거와 바이트 동등성 연결. 원본파일 파싱/native 미검증 별도
release→staging 원격 Full필수Full 4회: 34639164713 F(브라우저·화면 75=57P+5F+13U) · 34662653471 F(CRUD 2 timeout+정리 hook 1F, 15U) · 34674181914 F(CASE-025 1F) · 34677735108 12/12 성공(head e4cd999a, tree 6ad89619) → staging 0f46583a 병합. 게이트 수리(#1586) 뒤 새 후보 8621d677의 Full 34679429859 12/12 성공(15:56~16:07 KST) → staging 15850e76 병합
DB→Edge→앱→smoke필수2-Staging Deploy 34678245398 실패(database 잡 Remote contract gate 도구 결함, 마이그레이션 33개는 적용) → 게이트 수리 후 2-Staging Deploy 34679946098 성공(database → functions → frontend → smoke, 16:08~16:12 KST; Apply 남은 마이그레이션 0, 게이트 missing 0, smoke TAP 12/12). staging 15850e76 tree = release tree 6d8fcf43
U06 실제 staging 15 CASE필수계정 주입 경로 미확보. 환경 부재를 성공 또는 정책 제외로 처리하지 않음
관리자타입·빌드 필수, 자동 검사 제외#1478의 관리자 CASE·단위·컴포넌트·DB 제외 유지. 별도 관리자 버전과 서버 계약을 연결
와드업 자동 검사정책 제외#1478 자동 제외 유지. 이관 장부의 관련 migration 자체를 건너뛰는 뜻은 아님
일반 Merge Checkrelease 병합 검사Full 성공으로 계산하지 않음
admin backend export소스 산출물 발행정상 push의 기존 자동 부수 산출물. 테스트·DB·Full·배포가 아니며 성공률에 섞지 않음
Production / R06명시적 대기재개 지시 전 staging→main PR·CI·자동화·배포를 발화하지 않음

필수 검사 실패·미실행, 원본 비의도 변경, 부분 공개, 미승인 호환 파괴 또는 후보/검증/배포 tree 불일치는 후보 확정 중단 조건이다. 실패 원인을 확인하고 승인된 R05 범위에서 최소 수리한다. 원격 Full 1회 경계나 예산을 임의로 확대하지 않는다. rollback은 확인된 호환 frontend 버전만 허용하며 DB 전체 downgrade나 운영 사실 UPDATE/DELETE는 하지 않는다.

4. 데이터 사본

읽기 전용으로 최신 성공 Daily data backup 실행 34405355357의 artifact 10125165975 (daily-data-backup-2026-09-09, 4526942 bytes)을 확보했다. 다음 실행 34530746662는 실패했다. 내려받은 원본을 보존하고 검증/복원 산출물은 별도 비공개 작업 경로에 둔다. 원문 값·개인 식별자·키를 이 문서에 싣지 않는다. 이 사본은 당일 사본이 아니며 현재 시점 나이·schema 유효성·전체 이관 결과를 별도로 기록한다.

5. 실행 증거

Phase 1 완료. 앱 39add74b의 로컬 npm run check: 3917=3785P+0F+132조건부 제외, 102.162초. persistence browser 118P/0F/0skip, 21.388초. 웹 BARBELIC_TARGET=local 빌드 성공. 관리자 docs 08962db strict 타입·local 빌드 및 산출물 검사 성공. 모두 staging 또는 Full 실행으로 집계하지 않는다.

통합 과정의 실패도 보존한다. main 첫 check는 14개 실패 후 실제 이동된 기능/테스트 경계를 연결했다. 동일 owner 재요청으로 대체된 전송이 owner 종료·dispose 취소에서 빠지는 resourceStore 문제는 회귀 재현 뒤 활성 요청 추적으로 수정했다. staging 첫 check는 3917=3784P+1F+132조건부 제외였으며 새 통계 준비 helper의 DB 행 타입 직접 import를 기존 화면 모델 타입으로 연결한 뒤 최종 전체 검사가 성공했다. 최초 웹 빌드는 대상 환경 미지정으로 거부됐고, 올바른 local 대상 명시 후 성공했다. 기존 500kB chunk 경고는 남아 있으며 성능 예산 수락 증거로 바꾸지 않는다.

Phase 3/5 완료·Phase 4~5 미완성. 전환·실제 staging·U06 결과와 최종 후보를 계속 갱신한다.

Phase 2 — 실제 사본 첫 전체 이관 (실패 기록)

39add74b / main 1587cb7a, PostgreSQL 17.6.1.127에서 실제 사본 19표 44,357행을 복원했다. 원본 파일 해시를 유지한 파생 작업본만 사용했으며, 기존 seed와 복사본의 공통 종목 793개는 ID가 모두 같았다. 초기 복원은 중복 INSERT 때문에 실패했고, 비어 있는 격리 DB에서 같은 ID의 seed에 복사본 열을 적재한 뒤 19표 모든 복사 열을 양방향 대조했다. 사용자 ID나 관계를 재배정하지 않았다. 초기 fixture 준비 2회 실패(중복 seed, 로깅 설정 권한)는 실제 31개 적용 실행과 구분한다.

첫 전체 적용 결과: SQL 31/31 성공, 사실 23표의 실제 값·ID·관계 비교 차이 0(당시 짧은 요약 해시는 아래 결함 때문에 식별 증거로 사용하지 않음), 값·ID·source·부모/자식 차이 0, definitions 차이 0, 외부 공존 break 0. 20260915033000의 첫 문장 후 rollback→같은 파일 재실행에서도 원본 차이 0. 실제 복사본에서 부분 index 대상 8행과 index 유효성을 확인했다. 복사본 영수증/변경 이력은 각각 0행이라 비어 있는 상태만 확인했고, 초안 checkpoint 1행은 전체 열이 동일했다. 채워진 영수증·이력은 대표 workload에서 따로 대조한다.

전체 판정은 실패다. D08 20260914053000 적용 9803ms, 잠금 최대 9450ms가 기존 5000ms를 초과했다. 전체 적용 SQL 시간 합 22297ms, 적용 구간 wall 85498ms, WAL 43.86MiB, DB probe 945호출(소유자 756) 오류 0. 해당 D08 probe 자체 p95 23ms/max 39ms였으나, 기존 harness 잠금 판정을 임의로 합격 처리하지 않는다. 같은 시간대 cron 실행 기록은 있으나 최초 실행의 잠금 보유 PID를 수집하지 않았으므로 원인은 미확인이다. 대표 workload에서 대기·차단 쿼리를 함께 수집한다.

원래 사본은 2026-09-09T21:12:21Z 복사본이고 최신 성공 artifact와 동일하다. 현재 시점 24시간을 넘겼다는 한계와 실제 snapshot의 schema 꼬리 20260914000000을 유지한다. 내부 함수 삭제 경고 14개는 외부 RPC break 0과 구분하며, 구 worker/publication 조합 검증에 연결한다.

Phase 2 — 잠금 원인과 전환 순서 수리

4년 RPE10 fixture 첫 유효 실행은 1043세션·12516세트·원본33127행이었다. 31개 적용과 원본 보존은 성공했고 1043영수증의 전체 열 해시도 같았지만, D04 lock12777ms/D08 lock24387ms로 전체 실패했다. 독립 DB 관측에서 D04 ALTER user_exercise_stats_refresh_jobs와 D08 ALTER user_stats_projection_runs의 차단 PID가 실제 pg_croncompute_stats_projection_job_v1()임을 확인했다. 첫 실제 사본 실행의 PID를 소급해 확인한 것으로 표시하지 않는다. 해당 실행의 부분 index 대상은12516행, index 유효, index 적용282ms/WAL1.13MiB/lock0이었다. 이 입력은 저장 계약에 없는 상위 set_result를 넣은 최초 적재1043건이 모두 거부된 후, RPE는 세트/완료 결과는 하위 항목에 맞춘 별도 유효 입력이다. 최초 거부 실행은 세션0·신규migration0이다.

b3221dd8에서 기존 rollout 호출 전 동일 worker의 기존 claim/compute advisory key를 한 연결로 잡도록 했다. 실행 중 compute가 끝나고 이미 계산된 결과가 기존 publish로 끝난 뒤 DDL을 요청한다. 새 claim/compute는 기존 busy 응답으로 미뤄지고, 사용자 원본·영수증·pending/claimed/failed 작업은 삭제하지 않는다. 70초 준비 제한에 걸리면 migration 시작 전 중단하며 기존 파일당 60초 적용/5초 잠금 예산은 그대로다. 성공·실패 finally에서 연결을 닫아 재개하고, 연결 유실은 CLI AbortSignal로 전달한다. cron 설정이나 기존 migration은 수정하지 않았다. 기존 migration rollout 단계에 필요한 psql 가용성만 확인한다.

실제 DB 회귀1개와 rollout 단위14개 통과, 전체 check3921=3788P+0F+133조건부 제외(114.562초). 추가 computed→publish 회귀를 포함한 현재 후보는 921047d7f477b4af96495e3de15d9e2ad3c5cc68, tree734a993ba583531e09990a465def246d6376cd52다. 전체31 migration의 바이트·definitions는39add74b와 같다. 수리된 전환 경로의 전체 이관은 이 후보에서 별도로 기록한다.

Phase 2 — 수리 후 전체 이관 결과

실행별 기계 판정과 해시·실패 보존. 개인 식별자·사용자 원문·키를 제외하고 원본/간선/출처 해시와 수량을 남겼다.

입력 / 후보전체 적용최대 파일 / 최대 잠금WAL / 조회보존·중단
4년 RPE10 + 정상 수정 1회 / 921047d731/31, 합계8330ms, wall69825ms346ms / 0ms6.31MiB / 635호출 중 오류0(소유자508)원본33127행·23표 차이0, 영수증1044·변경 이력31 전체 열 해시 동일, index 첫1/4문장 rollback→재실행 보존
실제 9/9 사본 / 3f635b7e865d10e2b1e5addd38491c71e7864eef31/31, 합계8281ms, wall70191ms359ms / 0ms4.94MiB / 500호출 중 오류0(소유자400)원본44357행·23표 차이0, checkpoint1 전체 열 해시 동일, index 중단/재실행 보존

두 실행 모두 기존 시간/잠금 예산으로 passed, definitions 차이0·외부공존break0이다. 고강도 index는 4년 입력12516행/243ms/WAL1.14MiB, 실제 사본8행/263ms/WAL0.06MiB, 모두lock0·유효다. worker 정지 준비는 각각143ms/163ms였고 작업 종료 후 연결 해제를 확인했다. 이관 WAL에는 원래 동시에 돌던 worker의 WAL이 섞일 수 있으므로 이전 대비 차이를 통계 계산 자체의 비용 개선으로 해석하지 않는다.

실제 차단 compute 종료→DDL, 새claim/compute busy→해제, computed 결과 정상 publish→세대 정착을 확인한 실DB 회귀2/2가8.924초에 통과했다. 첫 무보호 실행2회의 FAIL은 그대로 유지한다. 실제 사본에는 영수증·변경 이력이0행이므로 그 채워진 보존 증거는4년 입력의1044·31건으로 보완했다. 사본은 이 실행 시점 약45.3시간 전 데이터이며 새 백업/RPO24h 성공을 의미하지 않는다.

짧은 요약 해시의 결함: 기존 digestFingerprint의 JSON replacer가 표 이름만 허용해 내부 행/값/간선 해시를 누락했다. 수정 전 회귀1실패를 재현하고 중첩 값까지 안정적으로 직렬화한 뒤 관련9검사 통과. compareDigests의 실제 원본·ID·간선·출처 대조는 별도 구현으로 정상이며 이전 보존 판정은 그 실제 비교에 근거한다. 옛 짧은 값을 데이터 식별자로 인용하지 않는다. 새 실제 사본 실행은 표별 before/after를 저장했고 요약은1f5e10560e7f로 일치한다. 921047d7→3f635b7e는 증거 계산/저장과 회귀3파일만 바뀌었고, 두 실행의31개migration/definitions/제품/배포제어는 동일하다.

Phase 2 최종 npm run check: 3923=3789P+0F+134조건부 제외,103.629초. 추가 DB 회귀는 별도2P이며 제외에 합산하지 않는다. 문서 check는 법적 문서4개·경로355개 검사 통과. 앱 후보3f635b7e, 문서는 아래 기록의 독립 커밋으로 유지한다.

시간 판정의 범위: 기존60초는 마이그레이션 파일별 최대 적용 시간이다. 전체31개 wall은4년69,825ms/사본70,191ms로 별도 실측이며, 기존 입력에 전체wall 수락 상한은 정해져 있지 않다. 새 상한을 사후에 만들지 않는다. 준비70초 제한은 worker 종료를 기다리는 전환 제어에만 해당한다.

Phase 3 — 사본 복구·구/신 클라이언트

복사본 복구 증거. 앱 3f635b7e의 전체219개 DB에서 기존 R03 도구를 실행했다. 준비94,650ms와 복구65,022ms를 분리하며, 결과는 passed_with_documented_input_limits다. 원본 파일 불변과 격리 환경 정리를 확인했다. 같은 소유자·다른 소유자의3가족45행을 선택 복원했고 원본 값·ID·관계 차이0이다. 수정 복원/동일 영수증 재전송, 부분 자식 삭제 복원, 전체 가족의 중간 실패→재개3시나리오에서 대상·비대상 사실과 full projection이 모두 같고 미적용 세대0이다. 계획 후 계정 소실은 쓰기0으로 거부하고 손상·장부 불일치 사본을 DDL 전에 거부했다. 실제 사본의 보존된 Motra331개 normalized identity와 파일 해시는 대조했으나 원본 Motra/InBody 파일 재파싱을 수행한 것이 아니다. 사본 나이>24h/RPO 미충족과 원본 입력 부재를 유지한다.

구/신 공존 실행별 증거. 실제 Production v0.17.1 배포의93파일을 SHA 대조한 bundle을 사용했다. d0ff229679c5cb73f55aeefb2c2706b7d5732d38와 새DB219에서 CASE023·039·040을 각각2회, 6P/0F/0S/0U,1.7분으로 확인했다. 구탭의 남은 수정·전송 중 새탭의 후속 수정이 보존되고 서버에 한 번씩 반영된다. 별도 old client/new DB CASE023도2회 2P,25.2초다. 구버전 전체 DB downgrade를 허용하는 근거가 아니며 R02의 new client/old DB 미지원 RPC 실패는 그대로 남는다.

최초 실행6F를 보존한다. Phase1에서 통합한 statsDrainer의 timeout 설정 SELECT가 데이터 행을 하나 추가해 owner generation 결과를2행으로 반환했다. 실제 DB 회귀1F 재현 후 DO/PERFORM으로 설정을 실행하도록 최소 수정했고 실제 DB2P·단위5P가 통과했다. 최초 사용자 정리 오류의 별도 원인은 확정하지 않았으며 최종8P에서는 재발하지 않았다. 첫 scratch 실행의 tsx loader 누락은 CASE 실행 전 실패로 구분한다. 필수 품질 reporter도 최종 두 실행에서 오류0이다.

필수 precheck는 최신 main/staging/release 조상을 포함한 clean d0ff2296에서 시작했다. 기존 DB suite의 pending/processing/computed/failed 전환, dirty·lease·원자 공개, 실제 Chromium 복원 후 재저장, full rebuild/수렴 결과를 이어 기록한다. Phase1의 persistence118P 이후 제품 frontend 바이트는 같으며 후속 변경은 전환 제어·증거 도구·통계 대기 helper다.

Phase 3 — 필수 precheck 실패 수집과 수리

첫 Precheck는 d0ff2296에서521초(8분41초) 실행됐고, 단위3789P/0F/134조건부 제외·전체219replay·schema·pgTAP122파일2444assert·동시 저장/영수증/복구·dirty 범위·worker 임대/유저 트랜잭션·660세션 동시 CRUD/통계 수렴이 통과했다. static의 미사용 import/함수2곳과 순차 묶음의 구computed 전환1CASE는 실패해 전체 판정은FAIL이다. 미사용2곳은 Phase1 통합에서 남은 코드로 제거했다.

구computed 검사 실패는 completed 기대에 idle이었다. 원 실행의 차단PID는 수집하지 않았으며 제품 실패라고 소급 단정하지 않는다. 별도 격리DB에서 독립 publisher가 owner fence로 deferred되어 run행 잠금을 보유하게 하면 같은idle을 재현했다(회귀1F). fixture의 publish 호출과 같은 SQL문에서 그 소유자 computed행을 먼저 잠가 대기하게 하자1P, 해당전체28P/0S(19.546초)다. 실제 publish함수·세대 검증은 그대로 실행하며 재시도/시간 완화로 덮지 않는다. c7edc732c9635483a0622e44aa250b297292393a / treeefd4291d57971b3417e2630cf8410926dd37f664에 최소 수리와 회귀를 커밋했다.

그다음 실행은 편집 도구가 남긴 working-tree CRLF로 static이 즉시 실패해 통제 중단했다. LF정규화 후 내용/HEAD변경은 없었고, index stat 재확인 전의 실행1회는 clean 검사에서 검증 시작 전 거부됐다. 최종 LF/clean 후보의 Precheck 결과를 아래에 이어 기록한다. 원격 Full은 아직 실행하지 않았다.

최종 c7edc732 공존 재실행도6P/0F/0S/0U와 old/new2P/0F/0S/0U(26.8초), 품질오류0이다. 같은 커밋의 필수 Precheck는 전체PASS, 521초: 단위3789P·135조건부 제외, static/unused/웹빌드, 전체219replay·schema·pgTAP122파일2444assert·전 DB묶음과660세션 수렴/실패 재시도/정리 모두 통과했다. 실행별 Precheck 증거에 첫 실패와 이후 성공을 구분한다.

별도 Phase완료 npm run check는3924=3788P+1F+135조건부 제외(107.658초)였다. 구 버전 소스 번들 병렬 격리 검사가 다른 빌드의 .git/worktrees/.../commondir 읽기 ENOENT로 실패했다. 원본 repo의 등록 공간을 함께 사용하는 임시 worktree 대신, lane별 임시 clone에 독립 Git 메타데이터를 두고 원본 objects만 읽기 공유하도록 한 파일을 수정했다. 긴 경로 설정·고정 commit checkout·빌드 출처/캐시 무효화·자기 임시 폴더 정리는 유지한다. 기존 병렬격리·출처5검사 통과 후 7c0a697b3cd1b232d4281300d091a08470e4acb7 / treebee5422c0449ab9aecf3a47919610bb533157d70로 커밋했다. 제품frontend·DB·실제93파일 배포 bundle 공존 경로는c7과 같지만 새 head의 필수Precheck/Phase check는 별도로 확인한다. 시간/재시도를 추가하거나 첫 실패를 성공으로 바꾸지 않았다.

관리자 계약 목록은 docs08962db 서비스가 이름을 직접 지정하는 RPC16개의 실제DB219 서명/결과형/정의 해시다. 누락0이며 앱 api/admin은 현재main과 바이트 동일하다. 동적 호출·테이블 접근·인증된 실제 원격 동작 전체의 성공으로 해석하지 않는다. 관리자 타입·local빌드 입력은Phase1 결과를 연결하고, #1478의 자동동작검사 제외는 유지한다.

HQ가 확인한SDK는 C:/Program Files (x86)/Android/android-sdk에 platform34/35·build-tools35이며 요구36은 없다. B02 이후 Android/iOS native 소스가 바뀌었으므로 과거 unsigned AAB를 이번 후보 산출물로 사용하지 않는다. 최신native빌드·서명·스토어·provider전체는 미검증, Windows에서 Mac/Xcode 실행환경 인계도 없다. 이는 앱/DB/브라우저의 합격과 구분한다.

후보별 검증 입력의 바이트 동등성을 추가했다. 최종7c0a697b의 migration·definitions·schema·DB 계약은4년 이관921047d7 및 실제 사본 이관/복구3f635b7e와 같고, c7edc732 브라우저8P의 제품·DB·배포제어 입력도 같다. 최신 두 커밋의 유일한 차이는 구 버전 소스 빌드 도구이며, 이 비교를 native·원격staging·원본파일 파싱의 실행 증거로 확대하지 않는다.

7c0a697b의 Phase3 최종 npm run check: 3924=3789P+0F+135조건부 제외,110.401초. 실제v0.17.1 태그를 현재 의존성으로 빌드하는 별도 source-rebuild도 성공했다. 이 산출물은 원래 배포된93파일과 별개이며 실제 배포본 공존8P의 출처를 바꾸지 않는다.

Phase 3/5 완료 — 2026-09-12 KST. 최종7c0a697b Precheck 541,266ms(9분1초), 전체PASS. 단위3789P/0F/135조건부 제외·static/unused/웹빌드, DB219replay·schema·pgTAP122파일2444assert·동시저장/영수증/복원후재저장·dirty범위·순차/기간/달력·구형상태전환·worker임대/울타리·660세션 CRUD/통계수렴이 모두 통과했다. 같은head의 Phase check는3924=3789P+0F+135조건부 제외다. 실제 사본/대표 이관과 이번 복구·브라우저용 자체 스택 정리를 확인했다. Phase4는 자기PR의 Merge Check/실제release 병합, 승인된 최종staging Full1회와 배포/smoke·U06실제15CASE를 남긴다. Production/R06은 재개하지 않는다.

Phase 4 — release 병합과 최종 Full 원 결과

PR #1580Merge Check 34638911663 성공 후 release의 411d8abf1b70a94b7bd267a593ac9abcda381b3c에 실제 병합됐다. 검증 head 7c0a697b와 같은 tree bee5422c0449ab9aecf3a47919610bb533157d70다. staging 배포나 Production 성공을 뜻하지 않는다.

staging PR #1581의 base는 044a55f861bc82eeb65fc9205e4e02630508d513, head는 위 release commit이다. 실제 검사 merge candidate a54d6e8a20b3035b0c2317ce36e92f02f6d1cf04의 tree도 같다.

승인된 Full 34639164713 attempt 12026-09-11T19:30:03Z에 시작해 19:42:39Z에 실패로 종료됐다. 원 결과 댓글구조화한 실행 증거를 연결한다.

같은 run의 검사N = P + F + S + U
필수 브라우저·화면75 = 57 + 5 + 0 + 13
단위 검사3924 = 3786 + 3 + 135 + 0
persistence118 = 117 + 1 + 0 + 0
CRUD 본문12 = 10 + 2 + 0 + 0, 별도 cleanup hook 1 F

단위 3 F는 로컬 19시를 가정한 fixture가 UTC에서 10시가 되는 문제였다. CASE-002/016은 삭제된 scrim 선택자, CASE-005/006은 잔존 repository 참조, CASE-010은 적용 영수증의 동기·비동기 계약 불일치였다. 상세 화면은 Linux 글꼴의 폭이 커져 휴식 제목이 오른쪽 칸을 넘었다. CRUD의 두 60초 timeout과 계정 cleanup 실패 원인은 아직 미확정이다.

persistence 실패로 shard 4의 13 CASE가 실행되지 않았다. CRUD 뒤의 empty-account와 cardio 단계도 미실행이다. 두 단계의 개별 분모와 전체 원인 묶음 수는 미확정이므로 전체 성공률을 산정하지 않는다. e2e-evidence·verify는 직접 실패와 누락에 따른 결과이며 별도 결함으로 중복 집계하지 않는다.

로컬 수리 진행률은 원인 묶음 5/G(전체 미확정), 직접 실패 테스트 9/11, cleanup hook 0/1이다. 시간 fixture는 UTC·한국 시간에서 각각 14 P, 브라우저 5 CASE는 실제 결함 주입·복원과 정리까지 5 P, Linux 상세·완료 정렬은 2 P다. 시간과 오차 기준은 유지했다. 원격과 같은 DB 단계 순서 재현 중 임시 계정 삭제와 compute의 교착 상태가 추가로 관측됐다. 이를 원격 cleanup과 같은 원인으로 단정하지 않고 조사 중이다.

승인된 Full 1회는 사용 완료이며 추가 원격 지시는 없다. 새 Full·재시도·자동 Full을 유발하는 #1581 head 갱신·staging 병합·R06 재개를 진행하지 않는다. 다음 Full의 선행 조건은 미충족이다. U06 계정과 실제 staging 15 CASE, 최신 네이티브 검증, 최종 후보 확정도 미완료다.

Phase 4 — 원인 수리와 DB 220개 후보 검증

후속 로컬 후보는 9d6485e632b9d81003f5fbfdb894feea486a9e70이며, 신규 계정 테스트 날짜 수정만 추가한 최종 head는 3bab905c1165bdffcde3f1fe9d85180d74a6a9c5다. 원격 release는 아직 411d8abf이며 두 후보를 병합 또는 배포한 것으로 보고하지 않는다. 아래 검사는 원 Full과 다른 로컬 실행이다.

추가로 관측한 auth 계정 삭제·compute 교착 상태는 독립 DB 재현에서 40P01로 확인했다. 삭제는 auth 부모 행을 잠근 뒤 run 자식을 지우고, compute는 run 자식을 잠근 뒤 출력 trigger의 FK 검증에서 auth 부모를 요구해 순서가 반대였다. compute가 먼저 부모의 key-share 잠금을 획득하고, 삭제 중인 소유자는 건너뛰도록 순서를 고쳤다. 삭제가 먼저 시작되는 경우와 compute가 먼저 시작되는 경우를 모두 검사해 worker 전체 10건이 통과했다. 실패한 계정 정리 후에도 자기 DB 연결을 닫도록 fixture의 finally도 수정했다. 원 Full의 두 timeout과 cleanup hook이 같은 원인이라는 증거는 없으므로 그 원인 판정은 미확정으로 유지한다.

이 변경은 새 migration 20260915063000_r05_compute_auth_owner_lock_order.sql에 있으며 위험 분류는 low/function이다. 기존 migration, 원본 기록, 권한, 시간 예산은 바꾸지 않았다. 정의·schema·계약을 갱신한 뒤 전체 단위 검사는 3926 = 3789 P + 0 F + 137 조건부 제외, 113.101초에 통과했다. 9d6485e6의 필수 precheck도 558.384초, 전체 PASS이며 DB 220개 replay, schema 일치, pgTAP 122파일·2444 assert, 모든 DB 동시성 묶음과 660세션 수렴을 포함한다.

새 DB 후보 9d6485e6의 populated 이관실제 9/9 사본4년 RPE10 이력
적용main 188 → 후보 220, 전체 32개 통과main 188 → 후보 220, 전체 32개 통과
원본44,357행, 23표 차이 033,127행, 23표 차이 0
SQL 합계 / 전체 wall12,080ms / 96,296ms8,864ms / 75,020ms
최대 파일 / 최대 잠금 대기750ms / 14ms327ms / 0ms
WAL / 조회 오류4,378,720 bytes / 505호출 중 06,608,760 bytes / 650호출 중 0
영수증·이력·checkpoint기존 checkpoint 1개 전체 열 해시 보존영수증 1,044개·변경 이력 31개 전체 열 해시 보존
index / 중단 후 재실행대상 8행·valid, 첫 1/4문장 중단 후 보존대상 12,516행·valid, 첫 1/4문장 중단 후 보존

두 실행 모두 정의 차이·공존 오류·원본 변경 0이다. worker 전환 준비는 120ms·156ms였으며 종료 시 잠금 해제와 자체 스택 정리를 확인했다. 기존 파일별 60초·잠금 5초 예산을 유지했다. 사본의 나이와 원본 import 파일 부재는 이전과 같으며 새 백업 성공으로 해석하지 않는다. 실행별 원자료 요약에 기존 31개 실행과 이번 32개 실행을 따로 보존했다.

원 Full에서 실행되지 않았던 브라우저 shard 4는 13 P / 0 F / 0 S / 0 U, 2.5분이다. 수정 후보의 CRUD는 12 P, 3.451초이며 원 Full timeout의 원인 입증과 별개다. 미실행이던 empty-account/cardio의 분모는 15건으로 확인했고, 첫 실행은 14 P + 1 F였다. PR snapshot은 고정 SESSION_DATE=2026-09-07에 준비하면서 한 조회만 UTC 오늘 2026-09-11을 요구해 55000이 났다. 기존 fixture 날짜를 조회에도 사용하도록 한 곳을 수정하자 15 P, 6.932초였다. 서버 날짜나 제품 fallback을 변경하지 않았다.

추가 로컬 실행의 환경 실패도 보존한다. Linux persistence는 결과 폴더 쓰기 권한과 Windows worktree Git 경로 때문에 별도 실패가 있었고, 환경을 바로잡은 해당 3건은 통과했다. 이를 단일 Linux 118건 전체 성공으로 합산하지 않는다. 실제 구 배포본 공존의 첫 DB220 실행은 본문 6 P였지만 도중 head 변경으로 품질 reporter의 SHA 일치 검사가 실패했다. 이 실행은 합격 증거에서 제외하고 커밋을 고정한 뒤 다시 확인한다. 후속 후보 증거는 원 run의 실패 집계를 그대로 유지하며 이 결과를 구분한다.

현재 원 Full의 확인된 수리는 원인 묶음 5/G(전체 미확정), 본문 9/11, cleanup hook 0/1이다. 별도로 새로 발견한 두 원인(auth/compute 잠금 순서, empty-account 날짜)은 수정·로컬 회귀를 확인했다. 추가 Full 선행 조건, U06 실제 staging 15 CASE, 최신 native 검증, staging 배포·후보 확정은 여전히 미완료다.

최종 고정 head 3bab905c의 필수 precheck는 534,750ms(8분55초), 전체 PASS다. static, 단위3789 P/137조건부 제외, DB220 replay/schema/pgTAP122파일2444assert, 전 DB묶음과660세션 수렴을 포함한다. 실제 v0.17.1 배포 bundle과의 공존6 P(101,895.833ms), old/new 저장2 P(26,197.866ms), 품질 오류0·후보 SHA 일치를 확인했다. 신규 계정/cardio도 다른 여정과 겹치지 않는 최종 단독 실행15 P(6,061.3703ms)로 확인했다. 구/신 버전 증거precheck에 연결한다.

HQ는 기존 release 병합 권한과 추가 Full 금지를 구분했다. policy-contract.yml은 staging/main 대상 PR의 opened/synchronize/reopened/ready_for_review 및 수동 dispatch만 받고 closed와 release push는 받지 않는다. 자기 승격 PR #1581을 원 실패 기록과 함께 임시로 닫으면 추가 Full 없이 정상 Merge Check로 수리 PR을 release에 반영할 수 있다. 보존 댓글 후 #1581 CLOSED와 release/v0.18.0을 head로 하는 열린 승격 PR 0개를 확인했다. 브랜치와 원 실행은 보존했다. 후속 수리 PR #1582의 정상 Merge Check를 요청했다. PR 재개방·새 승격 PR·추가 Full·staging/main 승격 금지는 유지한다.

수리 release 반영 — 2026-09-12 05:50:41 KST. Merge Check 34646255331 성공 후 PR #1582가 6ea9b2fb5401c25c9146159b6ba0c0f5d2d5a548로 실제 병합됐다. 검증 head 3bab905c와 release merge의 tree는 모두 8d3b495b644358ef3bc7d0c701ba338f8bd56fa6다. 후속 버그 보고 BUG-135·136·137·138·139·140·141를 같은 턴에 작성했다. 세션의 v0.18.0 반영완료는 이 release 병합만 의미한다. Phase 4의 staging Full 성공·배포·U06와 Phase 5 후보 확정은 미완료이며 이슈를 닫지 않는다.

Phase 4 — Linux 원본 재현과 claim/auth 삭제 수리

원 Full의 CRUD 두 timeout과 GoTrue cleanup은 후속 조사 댓글에서도 원인이 확정되지 않았다. 당시 runner에는 실패 순간의 SQL·blocker·job/run·Auth 로그가 보존되지 않았다. 테스트 60초 예산 뒤 120초 drainer가 계속 실행될 가능성은 축소한 도구 실험에서 확인했으나, 원 Full에서 실제로 기다린 SQL을 입증한 결과는 아니다.

Linux 원본 재현은 원 head 411d8abf, DB219, Node 22.23.2와 동일 Postgres 이미지 digest로 수행했다. Ubuntu 24.04.4와 원격 24.04.5, Windows Docker host 및 bind 경로 차이는 남았다. 첫 시도는 container 내부 경로를 Docker host에서 볼 수 없어 pgTAP가 Files 0/Tests 0/NOTESTS였고, 후속 단계 일부가 실행됐어도 전체 시도를 무효로 보존했다. 자체 스택을 재생성한 유효 실행 한 번만 아래 결과로 집계한다.

유효 실행은 DB219 replay, schema, pgTAP 122파일·2,444단정 PASS 뒤 concurrency에서 중단됐다. 27 P와 1 F를 관측했으며 실패한 fixture cleanup의 연결이 남아 기존 180초 단계 상한으로 종료됐다. 최종 TAP 합계가 없어 이를 전체 28건의 완료 결과로 표시하지 않는다. 뒤의 dirty·worker·maintenance·convergence·CRUD는 모두 미실행이다.

해당 DB 로그의 21:25:54.678Z에는 auth 삭제와 compute의 교착, 21:25:59.989Z에는 claim과 auth 삭제의 별도 교착이 있었다. 두 번째에서는 claim의 run INSERT/ON CONFLICT가 FK 검사로 auth 부모를 요구했고, 삭제는 부모를 이미 잠근 뒤 job/run 자식을 요구했다. 이 로컬 SQL 삭제 실패를 원 Full의 GoTrue cleanup과 같은 원인으로 소급하지 않는다. 비공개 원본 로그·계정 식별자·키는 게시하지 않는다.

원본과 당시 최신 release 6ea9b2fb의 claim 함수는 바이트가 같았다. 현재 DB220 최소 회귀에서도 삭제 선행/claim 선행 두 검사 중 1 P/1 F로 실제 교착이 재현됐다. pending 후보의 auth 부모 key-share를 job/run보다 먼저 확보하고 삭제 중인 부모를 SKIP LOCKED로 건너뛰게 하자 2 P, 관련 worker 전체 12 P가 됐다. 후보 순서·한도·lease·재시도·권한과 사용자 원본을 유지했다. timeout 확대·재시도 추가는 반대 잠금 순서를 남겨 채택하지 않았다.

새 migration 20260915073000_r05_claim_auth_owner_lock_order.sql은 함수 한 개 재발행이며 위험 분류는 low/function이다. DB221 전체 replay와 SQL source/schema/registry/DB 계약 일치를 확인했다. 이전 DB220의 실제 사본·4년 입력 32개 populated 이관은 그 후보의 과거 증거다. 이번 DB221과 바이트가 같거나 33개 populated 이관이 실행됐다고 보고하지 않는다.

최종 check·precheck·release 병합은 아래 확정 결과에 연결한다. 후속 구조화 증거에 원본 Linux 실행과 현재 후보 회귀를 분리한다. 원 Full은 그대로 본문 수리 9/11, 원인 묶음 5/G(전체 미확정), cleanup 0/1이다. 추가 Full, staging/Production 배포, U06 실제 staging 수락, 최신 native 검증, Phase 5 후보 확정은 미완료다.

최종 head 95f3b6f7의 필수 precheck local-1789163370759-27704534,610ms, 전체 PASS다. 정적·빌드·단위 3789 P/139 조건부 제외, DB221 replay/schema/pgTAP 122파일·2444단정, 모든 DB 동시성·worker 묶음과 660세션 수렴 검사를 포함한다. 자체 회귀용 스택과 precheck 스택은 정리했다.

claim 수리 release 반영 — 2026-09-12 KST. PR #1583Merge Check 34651970271 성공 후 2026-09-11T22:00:32Z7ab3dcdf709cc8ecd3d99a855b8c7b8013434731로 실제 병합됐다. 검증 head 95f3b6f7와 merge의 tree는 417f325c4b75b843d2f5393f8d175ed1a42b6b8f로 일치한다. 자기 #1581 CLOSED와 열린 동일 release 승격 PR 0개를 확인하고 정상 Merge Check를 사용했다. BUG-142를 같은 턴에 기록했다. 추가 Full·승격·staging/Production 배포는 실행하지 않았으며 R05 Phase 4·5는 미완료다.

Phase 4 — 고정 release DB221의 전체 33개 이관

HQ 조율 후 기존 R05 계획의 최신 후보 증거를 7ab3dcdf / tree 417f325c4b75b843d2f5393f8d175ed1a42b6b8f에 맞춰 갱신했다. 앱·SQL 수정 없이 기존 실제 사본과 4년 RPE10+수정 이력 입력을 각각 새 전용 스택에 준비해 main188→221 전체33개를 한 번씩 적용했다. 기존 32개 실패/성공 기록은 그대로 보존했다.

고정 DB221 후보실제 9/9 사본4년 RPE10+수정 이력
적용33/33 PASS33/33 PASS
원본 행 / 표 차이44,357행 / 23표 차이033,127행 / 23표 차이0
SQL 합계8,734ms8,898ms
전체 적용 wall74,291ms75,001ms
최대 파일 / 최대 잠금299ms / 0ms317ms / 0ms
WAL / 조회 오류4,744,208 bytes / 470호출 중 04,327,792 bytes / 675호출 중 0
중단 후 재개대상 첫1/4문장 롤백 후 보존·재적용 PASS대상 첫1/4문장 롤백 후 보존·재적용 PASS
대상 인덱스8행 / valid12,516행 / valid

원본 값·canonical ID·부모/자식 관계·source identity의 전후 차이는0이다. 영수증·수정 이력·checkpoint·fence는 이관 전 존재하던 모든 열의 해시와 행 수를 대조해 보존했다. 실제 사본 checkpoint1개, 4년 입력 영수증1,044개·수정 이력31개를 포함한다. 정의 차이·공존 위반·조회 오류도0이며 worker 준비는 각각 140ms·158ms였다. 종료 시 worker 잠금 해제와 자체 스택 정리를 확인했다.

파일당60초·잠금5초 기준은 유지한다. SQL 합계와 probe·잠금 샘플링을 포함한 전체 적용 wall은 서로 다른 값이며 전체 wall에 새 상한을 만들지 않았다. 준비·복원 시간도 migration 파일 시간과 구분한다. 9/9 사본은24시간을 넘은 기존 입력이고 최신 백업·현재 RPO 충족을 증명하지 않는다. 원본 Motra/InBody 파일 부재 등 기존 입력 한계도 유지한다.

실행별 전체33개·보존 증거후보/입력 바이트를 연결한다. 실제 사본 SQL SHA는 기존 사본과 같고, 검증 시작·종료의 앱 HEAD/tree와 clean 상태를 확인했다. release tree는 claim precheck head 95f3b6f7와 같다. 이번 두 결과는 과거 DB220 증거의 재명명이 아니라 DB221의 별도 실행이다.

원 Full 본문 수리9/11·cleanup0/1과 CRUD 원인 미확정은 그대로다. 원본 Linux 전체 순서·원인 조사를 반복하지 않았고 추가Full·승격PR재개방/생성·staging/main배포·R06도 수행하지 않았다. R05 Phase4 staging 수락과 Phase5 후보 확정은 미완료다.

Phase 4 — 두 번째 Full 34662653471과 CRUD 대기 경계 수리 (#1584)

오너의 "일단 다시 돌려서 고쳐줘" 지시로 release 7ab3dcdf709cc8ecd3d99a855b8c7b8013434731 / tree 417f325c4b75b843d2f5393f8d175ed1a42b6b8fFull 34662653471 attempt 1을 실행했다(재개방 전이 run 34662652541은 옛 head로 자동 취소, 제품 테스트 0건). 잡 12 = 성공 10 + 실패 2(migration-smoke, verify). 단위 3928 = 3789P + 0F + 139S, DB 동시성 51P, pgTAP 122파일/2444단정, persistence 118P, 브라우저 53P + viewport 22P. 실패는 CRUD 본문 12 = 10P + 2 timeout(조회·삭제 각 60초)과 계정 정리 hook 1건(Database error deleting user), 후속 신규 계정·cardio 15건 미실행. 실행 슬롯 합계 4199 = 4043P + 2F + 139S + 15U, 96.28%. 원 집계.

원인·수리(기록): e2e의 통계 대기가 모든 계정의 pending/processing 잡이 0이 될 때까지 claim→compute→publish를 반복하는 전역 방식(예산 120초)이라 다른 계정 잡 하나에 묶였다. 실제 DB에서 다른 계정 pending 잡 1개를 사용자 잠금으로 붙잡으면 10P + 2 timeout(185.6초)이 재현됐다. PR #1584가 대기를 그 계정의 통계만 완료되면 끝나는 방식(10초 예산, 시간 초과 시 자기 DB 연결 취소)으로 바꾸고 계정 삭제 직전에도 자기 통계를 먼저 마무리하도록 했다(수리 후 같은 조건 12P / 8.0초). 취소된 테스트의 전역 대기 연결이 백그라운드에서 120초까지 compute/publish를 계속 돌려 GoTrue의 연쇄 삭제와 잠금 순서로 충돌한 것이 정리 hook 실패의 코드 경로상 유일한 후보이며(원격 DB 로그 부재로 확정 아님), DB 진단 단계를 CRUD·신규 계정·cardio 뒤로 옮겼다. Merge Check 후 release 7add2144b0db1106bf8d4552315bd9570443543c(tree 44128f7116394d77a89b256e330eeafd5f5002ff)로 반영, 자기 승격 PR #1581은 추가 자동 Full 방지를 위해 닫았다.

Phase 4 — 승격 세션 인계와 세 번째 Full 34674181914 (Claude 세션)

2026-09-12 13:00 KST부터 Claude 세션 080ed475-8da1-4c65-8675-fcf1e584801f가 이어받았다(이어받기). 오너 지시: staging 병합 + Full 통과, 원격 Full은 로컬 원인 수리·확신 뒤 세션 판단으로 1회. 실행 전 로컬 재검증(기록): CI와 같은 DB 순서 ci:full-local --only db,local,empty,cardio 7분 41초 전체 PASS(마이그레이션 221·pgTAP 122/2444·DB 묶음·660세션 수렴·CRUD 12P·신규 계정 9P·cardio 6P), 같은 스택에서 e2e 3종 5회 반복 15/15, 다른 계정 pending 잡 잠금 조건 통과, CRUD 직전 큐 pending/processing 0·만료 lease 0 확인.

PR #1581 재개방 → Full 34674181914 attempt 1(head 7add2144, tree 44128f71, base staging 044a55f8; 13:53~14:02 KST) 실패. 잡 12 = 성공 9 + 실패 3(브라우저 조각 2, e2e-evidence, verify). 단위 3929 = 3789P + 0F + 140S · pgTAP 122/2444 · DB 동시성 52P · CRUD 12P·신규 계정 9P·cardio 6P(직전 2회 실패 지점 통과) · persistence 118P · 브라우저 53 + viewport 22 = 75 = 74P + 1F. 실행 슬롯 합계 4201 = 4060P + 1F + 140S + 0U, 96.64%. 기록.

Phase 4 — CASE-025 원인 확정과 수리 (#1585, BUG-143)

실패 1건은 CASE-025의 두 번째 reload page.reload: Timeout 10000ms였다. 로컬에서 10회 중 1회 재현, reload 직전 RPC 응답을 1.5초 늦추면 6회 중 3~4회로 결정적 재현. Chromium tracing(browser 수준 CDP, 첫 reload 직후부터)으로 멈춘 렌더러 메인 스레드의 미완료 task 사슬 LocalFrame → FrameLoader::ShouldClose(is_reload) → DispatchBeforeUnloadEvent → EventDispatch(beforeunload) → RunMicrotasks가 6초 넘게 React 동기 flush 콜백을 1,787회 반복하는 것을 확인하고 sourcemap으로 소스에 매핑했다. 제품 결함: 저장 직후 피드 새로고침(loadProfileFeed({ force: true }))이 진행 중일 때 문서 이탈 신호(sticky abort)가 요청을 끊으면 피드 상태가 idle로 돌아가고, 화면 로드 정책(screenLoadPolicyController.ts:216)이 즉시 재요청 → 즉시 거절 → 저장소 알림 → 동기 재렌더 → 다시 idle … beforeunload 처리의 microtask 안에서 무한히 돌아 탭이 멈춘다. 사용자에게는 저장 직후 새로고침·탭 닫기·앱 전환 시 화면이 얼어붙는 증상이다. 원인·수리 기록, BUG-143.

PR #1585(커밋 eeda4745): 문서 이탈 신호를 documentLifecycle.ts로 뽑고 자원 저장소 fetch가 이탈 중에는 요청을 시작하지도 구독자를 깨우지도 않게 했다(모든 자원 자동 로드에 공통). 단위 회귀 2건. 검증: 결정적 재현 조건 CASE-025 6회 0/6 멈춤(수리 전 3~4/6), 지연 없는 CASE-025 조용한 환경 10회 10/10(그 전 6회 중 1회 첫 reload load 지연 실패는 git 백그라운드 repack과 겹쳐 원인 미확정으로 남김), precheck 전체 PASS 1분 25초(단위 1822P/0F/91S · 1969P/0F/49S). Merge Check 34677624110 성공 → release e4cd999afe69a49fb750a7101be06a5d046a281e(06:17:11Z). 이 PC의 self-hosted runner가 이전 세션 종료 뒤 offline이었던 것을 다시 띄웠다.

Phase 4 — 네 번째 Full 34677735108과 staging 승격

수리 PR #1585의 release 병합 push로 승격 PR #1581의 Full 34677735108 attempt 1(head e4cd999afe69a49fb750a7101be06a5d046a281e / tree 6ad89619b0183b3b608ef758cd077e426842ddfc, base staging 044a55f8; 15:17~15:27 KST)이 자동 실행돼 성공했다. 잡 12 = 성공 12. 단위 3931 = 3791P + 0F + 140S(조건부) · pgTAP 122파일/2444단정 · DB 동시성 52P · CRUD 12P·신규 계정 9P·cardio 6P · persistence 118P · 브라우저 53P + viewport 22P. 실행 슬롯 합계 4203 = 4063P + 0F + 140S + 0U, 96.67%(실행분 100%). 직전 3회 Full의 실패 지점이 전부 통과했다. 집계.

병합 직전 main 1587cb7a·staging 044a55f8가 release의 조상임과 PR mergeable/CLEAN을 확인하고 gh pr merge 1581 --merge(merge commit)로 승격했다: staging 0f46583a7051e0e279343b35180edd4993f601eb(15:28 KST), staging tree = 검증한 release tree 6ad89619….

Phase 4 — staging 배포 34678245398 실패와 원격 스키마 게이트 수리 (#1586)

승격 직후 자동 실행된 2-Staging Deploy 34678245398(staging 0f46583a, 15:29~15:32 KST)이 실패했다. 잡 8 = 성공 1(resolve) + 실패 1(deploy / database (staging)) + 미실행 6(functions·frontend·smoke, production 전용 3). database 잡은 사전 게이트·link·dry run·Apply migrations(release 가 더한 49개 중 이미 staging 에 있던 16개를 제외한 33개 적용, worker 잠금 1.09초)·롤아웃 기록 보존까지 성공하고 마지막 Remote contract gate(check:remote-schema)에서 missing 1 — function:public.start_wodup_import_batch(release contract failures 0)로 멈췄다. 그 시점 staging DB 는 v0.18.0 장부 221개가 전부 적용된 상태, Edge·프런트는 이전 배포 그대로였다. 기록.

원인은 게이트 도구 결함이다. 20260914010000(#1404 D09)이 옛 클레임 문을 dump 꼴 drop function if exists "public"."start_wodup_import_batch"("uuid", "text", bigint, "uuid") 로 지웠는데, 게이트 파서는 함수 create/drop/rename 문장을 따옴표 없는 public.fn( 꼴로만 읽어 없어야 할 함수를 계속 기대했다. 이 게이트는 배포 database 잡에서만 돌아 Full 4회로는 드러날 수 없었다. 로컬 샌드박스(마이그레이션 전체 적용)에 같은 카탈로그 조회와 같은 파서를 돌려 run 과 동일한 판정을 재현했고, PR #1586(커밋 bd47b35b)이 함수 문장의 스키마·이름 따옴표를 허용하고 인자 타입의 따옴표를 시그니처 비교 전에 벗기도록 고쳤다(회귀 1건: 따옴표 없는 create + 따옴표 있는 drop / 반대 / dump 꼴 create / 따옴표 있는 rename). 수리 후 샌드박스 missing 0·failures 0(기대 함수 489 = 원격 489, dump 꼴 베이스라인 함수까지 대조 전수화), Production 읽기 전용 조회(main 1587cb7a 장부 188개 + 새 파서) missing 0·failures 0(406 = 406), 게이트 단위 5파일 31/31, ci:precheck-local 전체 PASS 1분 24초(unit-1 1822P/0F/91S · unit-2 1970P/0F/49S). 문장 전체에서 따옴표를 벗기는 넓은 안은 다중 drop column 문장(20260901995000)을 파서가 첫 열만 읽어 샌드박스에서 헛 missing 20건이 나 기각했다. Merge Check 34679287538 → release 8621d6771d11a6abe198888c75bb24b0bf20e5d8.

Phase 4 — 다섯 번째 Full 34679429859와 staging 배포 34679946098

PR #1586의 Merge Check 34679287538 성공 → release 8621d6771d11a6abe198888c75bb24b0bf20e5d8(tree 6d8fcf43ef5ba0bf9818cd4f44d4dd7ead5c37ed, 15:53 KST; staging 0f46583a와의 차이는 게이트 스크립트 1파일 + 테스트 1파일). 새 승격 PR #1587Full 34679429859 attempt 1(head 8621d677, tree 6d8fcf43, base staging 0f46583a; 15:56~16:07 KST) 성공. 잡 12 = 성공 12. 단위 3932 = 3792P + 0F + 140S(조각 1: 2031 = 1982P + 49S · 조각 2: 1901 = 1810P + 91S; 직전 Full 대비 +1 = 회귀 테스트) · pgTAP 122파일/2444단정 · DB 동시성 52P · CRUD 12P·신규 계정 9P·cardio 6P · persistence 118P · 브라우저 53P(14+13+13+13, CASE-025 포함) + viewport 22P. 실행 슬롯 합계 4204 = 4064P + 0F + 140S + 0U, 96.67%(실행분 100%). 직전 Full 4회의 실패 지점이 모두 통과했고, 실행 간 결과는 합산하지 않는다.

mergeable/CLEAN 확인 후 gh pr merge 1587 --merge(merge commit)로 병합해 staging 15850e76009a6ceb331d2c76c25323520fadcde3(16:08 KST, tree = release tree 6d8fcf43…)가 됐다. 이어 자동 실행된 2-Staging Deploy 34679946098(16:08~16:12 KST)이 성공했다: resolve → database(dry run Remote database is up to date, Apply 남은 마이그레이션 0 — manifest 49개 전부 기적용, Remote contract gate 통과: 기대 함수 489 = 원격 489·missing 0·release contract failures 0, 로컬 샌드박스 예측과 동일) → functions → frontend → smoke(smoke:prod 배포 스택 CRUD 왕복 TAP 12/12) 성공, production 전용 3잡 skip(잡 8 = 성공 5 + 실패 0 + skip 3). 이로써 승격 ①(release → staging)의 조건인 같은 tree 6d8fcf43의 Full 성공 기록과 staging 배포·smoke 증거가 갖춰졌다. 기록. staging → main·R06·U06 실제 15 CASE 는 오너 재개 지시 전까지 대기한다.