Skip to content

R04 최종 통합 성능 검증

대상 #1543, release/v0.18.0. 이 문서는 측정 조건과 결과를 구분한다. 측정 전 항목은 미측정이며 릴리스 합격을 뜻하지 않는다.

최신 판정은 문서 마지막의 Phase 5 — 최종 판정과 R05 인계다. 중간 후보의 실패·부분 완료 문장은 당시 기록으로 보존한다. 측정 완료와 전체 G04 수락·release 병합·Production 성공은 서로 다른 상태다.

Phase 1 — 측정 전에 고정한 조건

2026-09-11, Codex 세션 01a08aec-6eb7-7e73-8ade-c9f9f2d30aa6. 후보 849191b54b15682fba001dbde9757f88b76cf580, tree 71773ba55dc3d08756915ecd8d3b73aa35d5dff0. 이후 측정기·제품 변경은 실행별 실제 SHA/tree에 기록한다.

직접 선행최종 merge SHA
R01 #1537849191b54b15682fba001dbde9757f88b76cf580
G04 #1284beff760ba24ae8904e17356a94b8f663bf850719
S07 #133737066827310bb6d86d579ebbf4ca1d6f7320c535
D11 #1422d058cbb7af1e0ae94bed1ade02408ec3301ec1f2
U05 #15362cfeac5327d5f3eb8eeb2ce7cb4e5e709127f6d5
B02 #13327b44295e84bfe7999fd31ecde77ee0ad1659b386
I01 #141555e9fae82340105defa586c572193922b7327793
D12 #1328d1e77113ede1ef101595e5824fb7b4a6d23f9fb7

GitHub compare의 behind_by=0과 동일 merge_base로 8개 모두 현재 release 포함을 확인했다. 선행 타이머는 착수 즉시 PAUSED로 변경했다.

  • D11 직전 release: b0fa93ec97fab41c6bcbc59bd096f3e1926535fd(D11 merge의 첫 부모).
  • D14 직전 release: 290eadb9b808cbbc85d69fde09600e79b925ee9c(D14 merge의 첫 부모). 기존 D14 과거 writer 대조 fixture도 유지한다.
  • G04 역사 기준: 16b8e996. 그때의 저장/worker와 지금의 의미 차이를 숨기지 않고 같은 현재 호스트에서 다시 실행한 비교와 기존 게시 증거를 구분한다.
  • 환경: Windows, Docker Desktop 29.7.2, 24 vCPU / 33,621,192,704 bytes. PostgreSQL 이미지 17.6.1.127, Supabase CLI 2.113.0. 실제 설정과 버전은 각 실행에 수집한다. 다른 담당자의 컨테이너는 조작하지 않으며 호스트 자원 경합은 제한으로 기록한다.
  • 전용 샌드박스: work/r04-sandbox/database, project cil764f4f79, API55721/DB55722. 합성 fixture만 사용한다.
  • G04 생성기 seed1284, 고정 endDate2026-09-06 유지: 1년260/4년1043/10년2609세션, 세션당12세트. multi-owner-10, same-owner-two-devices, mixed-read-write-import도 원래 프로필을 유지한다. 각 opsDigest를 결과와 연결한다.
  • DB 읽기 warm20회(첫 표본 포함), 전체 실행 최소2회. 원본 DML 감사와 시간/WAL 실행을 분리하며 계측으로 생긴 비용을 제품 비용으로 합산하지 않는다. DB cold cache를 임의 주장하지 않는다. 브라우저 CPU4x·mobile390×844/desktop1440×1000, cold/warm각3회가 유효한 U05 증거와 비교 조건이다.
  • 기존 G04 예산과 앱 RELEASE_PERFORMANCE_BUDGETS를 변경하지 않는다. claim3초/compute60초/publish6초/lease300초와 전체 backlog191438ms는 서로 다른 지표다.

검증 범위

  1. 원본 저장, 계산, 최종 게시의 I/U/D·WAL·직렬화·함수/trigger 비용·RPC 시간·generation 수렴을 구분한다. 메모·같은 mutation·같은 내용 새 저장·세트 편집/삽입/삭제/정렬·과거/날짜/최대/복합/체중/계획 전환을 포함한다.
  2. 독립 예상 변경행과 기존 full oracle를 사용한다. D14/D11 무관한 행 쓰기0, receipt/ID/source/revision/generation을 보존한다.
  3. 같은/다른 owner의 읽기·저장·지원 인입과 worker를 겹치고 dirty/실패/삭제/재시도·과부하 회복을 판정한다. 인입 근사와 실제 지원 경로를 구분한다.
  4. 선행 outbox·viewport·feature loading·자원/지원 파일 근거를 재사용하고 실제 달라진 경계만 검사한다. #1478 제외를 복원하지 않는다. D12에서 생략한 과거 운영 측정을 재개하지 않는다.
  5. 원시 분포, 개선/악화, 합당한 suffix 비용, 미측정(null), 실패 및 후보별 결과를 R05에 인계한다. Production 합성 부하·승격·실사용자 원본 변경은 하지 않는다.

알려진 입력과 판정 원칙

U05 최종 증거의 mobile DOM317은 예산294를 초과한 관측이다. 아래 Phase4 입력 정정에 따라 G04와 수집 시점·fixture가 다른 점을 반영하고, 같은 조건의 최종 판정은 아직 남아 있다. 일부 warm/전환 시간 증가, baseline empty get_pr_overview55000, native/Production CDN/HTTPS SW/V8 parse 단독 미측정을 보존한다. D11의 full 계산·전체 temp 복사 잔존 및 과거 검사 실패/한정 precheck 예외를 숨기지 않는다. 부분 DML 절감률을 전체 속도나 지원 사용자 수로 환산하지 않는다.

측정 결과와 각 Phase 검증은 실행 완료 후 추가한다.

Phase 2 진행 중 — 예비 측정과 환경 간섭

2026-09-11 14:20 KST, 아직 최종 전후 판정 전이다. 후보 제품 DB는 계속 849191b54b15682fba001dbde9757f88b76cf580이며 아래 측정기 커밋은 DB migration SHA와 구분한다.

실행계산(ms)게시(ms)관측
후보1년 run-128655.6342020.609게시 후 보고서 위생 검사에서 실패. 읽기 미측정
후보1년 run-227535.8841164.362해당 실행 수렴. G04 전체 합격 판정 아님
후보4년 run-138252.7276034.384게시57014, 기존6초 제한. 미반영 상태
preD11 1년 run-18382.136842.643반복·환경 통제 전 대조 값

이 실행들은 등록된 다른 이력 프로필이 같은 전용 DB에 남아 있었고 호스트 실행 자원을 다른 담당자와 공유했다. 이후 14:17~18 KST CPU100%와 다수 동시 검사 실행을 확인했다. 과거 각 실행 전체의 CPU 시계열은 없으므로 모든 차이를 자원 경쟁 또는 제품 회귀로 단정하지 않는다. full auto_explain 분석을 켠 후속 추적에서 계산60초 초과가 발생한 것은 계측/경쟁이 섞인 관측으로 별도 보존한다.

26개 원본 변경 시나리오의 독립 ID/ctid/변경 행/세대/이전 writer 동치 검사는1년·4년에서 통과했다. 1년26시나리오×20회 시간/WAL 기록도 수집했다. 이것은 롤백 가능한 합성 원본 검사이며 최종 public 통계 쓰기나 전 workload 성능 합격을 대신하지 않는다.

계측기 3e910bb6 이후에는 생성기에 등록된 합성 owner만 정확한 이메일 일치를 확인한 뒤 격리하고 실제 DB SHA를 명시한다. 274a0916은 복구된 과거 실패와 현재 미반영을 분리한다. 084d6c94는 테이블 읽기 행과 직렬화 payload 크기를 추가한다. 예약 작업의 active 상태뿐 아니라 실행 중 SQL backend의 종료를 확인한다. 4년 반복 진단을 위해 자체 두 DB의 통계 예약만 일시 중지했고 원래 상태를 로컬에 저장했다. 다른 담당자의 DB·작업에는 변경하지 않았다.

해석 주의:

  • 실패한 함수에서 pg_stat_xact가 보고한 DML은 롤백된 시도를 포함한다. 커밋된 변경행 수는 별도 행·ctid 검사로 확인한다.
  • 초기 읽기 도구가 이미 비워진 큐를 다시 측정한 짧은 recovery 값과 빈 잠금 근사는 유효한 worker/경합 증거가 아니다. 초기 raw는 보존하고 실제 통합 실행의 integrated.json을 우선한다. 후속 실행은 이 경로를 호출하지 않는다.
  • 저장40ms 기준은 원래 mixed-read-write-import, freshness1101ms는 history-10y에 배정된 기준이다.1년·4년 예비 값으로 해당 workload의 최종 예산 판정을 대체하지 않는다.
  • 처음 게시와 이미 게시된 owner의 재계산은 public 초기화 비용이 다르므로 별도로 비교한다. 예산 상향은 없다.

Phase 2 추가 원인 확인 — 원본 삭제와 계산 교착

2026-09-11 14:31 KST, HQ가 U06의 필수 precheck에서 관측한 교착을 R04 경합 범위로 인계했다. U06 5970a1a5/base849191b5의 SQL123파일2498단언과 동시성5묶음은 통과했지만660세션 계산·CRUD 프로브에서 session DELETE → user_exercise_set_observations FK cascade와 계산이 교착했다. 이후 worker SIGTERM은 정리 과정이며 첫 원인은 DB40P01이다.

같은 제품 DB의 기존 worker concurrency fixture를 세션1건으로 줄여 재현했다. 삭제 연결이 원본 parent의 FOR UPDATE를 보유한 뒤 실제 private compute를 시작하자 pg_blocking_pids로 계산의 부모 FK 대기를 확인했다. 삭제를 계속 실행하면 계산이40P01의 희생자가 됐다. U06에서는 삭제가 희생됐고 이 재현에서는 계산이 희생됐다. 약7.6초이며 타이머를 제품에 추가하지 않았다.

원인: D05 정규화 관측은 기존 staged compute에서도 public에 DELETE/INSERT했다. 계산은 관측행 잠금 뒤 원본 FK를 검사하고, 삭제는 원본행 잠금 뒤 관측행 cascade를 실행하므로 잠금 순서가 뒤집힌다.

채택 초안은 이 관측도 기존 비공개 계산/검증/원자적 게시 경로로 옮기고, 관련 소비자가 임시 관측을 읽도록 하는 것이다. 원본 FK를 없애거나 긴 owner 잠금·deadlock 재시도를 더하는 대안은 기각했다. 초안 상태이며 실제 수리 통과는 아직 주장하지 않는다. 기존6초 게시 문제와 같은 원인으로 단정하지 않고 증가하는 payload·검증·DML 비용 및 full oracle 동치를 함께 확인한다.

고정 종료 구간의 추가 측정

HQ가 U06/R02/R03의 기존 실행 종료를 확인한 뒤14:37:49~14:39:09 KST에 후보 제품849191b5의 적재4년 이력을 다시 계산했다. 시작 CPU18%, 중간28%, 종료 후15%였으며 R02의 자체 DB stop이 일부 겹쳤다. 독점 호스트나 전체5분 연속 시험으로 표현하지 않는다.14:40 재개를 미루지 않았다.

진단 계측계산(ms)게시(ms)게시 결과
33885.1056059.453failed57014
33544.6066093.485failed57014

두 실행 모두 최초 게시에 실패해 해당 owner는 bootstrap 상태를 유지했다. 계측을 켠 계산의 durable JSON은 저장8,571,448 bytes / JSON UTF-8 61,001,588 bytes였다. 게시 함수 자체4350.6ms와 payload validator1593.5ms(1회)가 관측됐으며 완료 guard의 두 번째 검증까지 도달한 성공 실행은 아니다. 단계 원시값, 시작 환경, 종료 환경.

교착 수리의 부분 검증

임시 마이그레이션 20260914223000_r04_observation_compute_isolation.sql은13개 함수 재발행이며 위험 분류low/function이다. D05 관측을19개 원자적 게시 대상에 포함하고 새 임시 관측의 실제 카디널리티를 ANALYZE한다. 예전 computed payload에는 새 격리 증명이 없으므로40001로 재계산하며 원본FK·기존예산은 보존한다.

전체 마이그레이션 재생과 두 번의 상태 스냅샷 생성으로 schema.sql을 갱신했다. 관련 정적27개, D11/worker DB19개가 통과했다. 작은 교착 회귀는 수리 전 parentWait=true/40P01에서 수리 후 parentWait=false/삭제·계산 완료로 바뀌었다. 큰 이력·full shadow·원래 게시예산 및 최종precheck/병합은 아직 별도 검증 중이다.

증거 사본은 원래 scratch 원본을 덮어쓰지 않는다. 공개 사본의 owner 식별자는 SHA-256으로 바꾸고, 기존 시료 배열 키rows는samples로 바꾸며 원본 내용 필드는 포함하지 않는다. 초기 도구가 잘못 기입한 DB SHA는 metadataCorrection에 원래 값과 실제 DB SHA를 함께 남겼다.

게시 비용과 계산 결과 저장 취소

첫 교착 수리 뒤 full/incremental shadow 12개 스냅샷(11회 incremental, 차이0)은 통과했다.660세션 검사에서는 생성64ms·수정49ms·삭제22ms로 교착 없이 실행됐으나, 후속 게시가6,046ms에서57014로 실패했다. 전체 검사는 불합격이며 작은 교착 검사의 통과로 대체하지 않는다.

게시 경로는 동일 payload를 사전 검증과 완료 trigger에서 반복 검증하고, 같은 행도 INSERT trigger·충돌행 잠금까지 통과시켰다. 후속 수정은 성공한 검증을 작업·lease·동일 트랜잭션·payload SHA-256에 묶인 definer 소유 임시 증명으로 재사용한다. 최신 원본·완료 조건과 실제 snapshot membership 검사는 유지한다. 호출자 소유 위조 임시 표와 검증 후 바뀐 payload는 재검증하며, 두 공격/변경 회귀 검사가 통과했다. 동일 행은 public 입력 전에 제외하고 생성 컬럼을 제외한 명시적 컬럼 목록을 유지한다. 게시 예산6초는 변경하지 않는다.

그 상태의 후속660세션 실행은 최초 게시5,857ms를 통과했지만 겹치는 재계산의 마지막 durable 결과 UPDATE에서57014가 기존 예외 처리 밖으로 나왔다. 이 SQL 위치에57014를 발생시키는 회귀 검사는 수리 전 실패했다. 결과 저장을 같은 계산 예외 처리 안으로 옮긴 뒤 failed run·빈 payload·재시도 backoff·미진전 applied 세대를 확인해 통과했다. 이는 시간 초과를 성공으로 바꾸는 수리가 아니며 실제 계산60초 준수는 별도 검증한다.

HQ가 추가 인계한 R02 precheck 실패는 write_session_children_v5 → exercise_set_part DELETE → 정규화 관측 FK cascade 경로였다. 동일 parent 잠금 회귀를 세션 삭제와 세트 제거 두 경로로 확장했고 둘 다 계산의 parentWait=false 및 실제 저장/삭제 완료를 확인했다. R03의 D06 busy 관측은 별도 담당자 진단 범위로 유지한다.

후속 마이그레이션 20260914233000_r04_publication_validation_reuse.sql은4개 함수 재발행(low/function)이다. U06의 공통 제외 정책9f7fa381과 R02의 추가 D09 전용 검사 제외02f8c7a7을 함께 소비했다. 최초 DB 실행143파일2825단언은 이 제외 전의 역사 증거이며 최종 정책에 맞춘 실행으로 표현하지 않는다.

660세션 수리 검증 완료, 장기 통합 판정은 진행 중

최종 후보 0f9e9a5f의 제품 파일과 회귀4파일을 측정기 없이 분리한 전달 커밋은 646f71d65d3208bf52e3349b39816150522789e7이다.26파일 모두 검증 후보와 정확히 같은지 git diff로 확인했다.15:26 KST 기준 release는 여전히849191b5이며 이 커밋의 존재를 release 병합으로 표시하지 않는다.

원래660세션 검사 단계계산(ms)게시(ms)결과
최초 materialization228834849완료
실제 CRUD가 겹친 계산312654994완료
후속 dirty 세대 재계산309595218수렴

실행06:15:31~06:18:34Z,660세션/7920세트, create82/update56/delete24ms·각 receipt1. full maintenance replay와 최종 공개 결과가 같고, 취소 뒤 committed attempt1·backoff·lease 교체·기존 checkpoint 보존을 확인했다. probe clone 정리 성공. 전체 결과CPU 시계열을 함께 보관한다. CPU6~74%로 호스트 독점 시험은 아니며 원래 compute60초/publish6초 예산은 유지했다.

관련 DB24개에는 full/incremental12개 snapshot·11개 incremental 후보의 숫자/논리키/provenance/DTO 차이0, 세션 삭제와 세트 제거 회귀가 포함된다. 정적27개도 통과했다. 결과 저장 취소의 수리 전 실패수리 후 통과를 분리 보관한다. 깨끗한 DB migration 재생→두 번의 snapshot 생성→sql:extract/db:model/sql:check도 통과했다. 검증 fixture가 남은 DB의 snapshot 시도는 도구가 거부했으며, fixture를 참조 데이터로 등재하지 않고 clean reset 후 생성했다.

이 결과는 공통 stats 교착 수리의 검증이며 R04 전체 성능/장기/혼합 합격이나 필수precheck·Merge Check 완료를 뜻하지 않는다. 이후 측정은 후보와preD11 각각 등록된 합성 프로필만 적재하며1/4/10년을 번갈아 두 번씩 실행한다. 첫 반복 실행기의 중첩 cron 제어가 자체 격리 잠금에 거부된 준비 실패는 별도 raw로 보존하고 제품 실패/성능 표본에서 제외한다. 실제 반복에서는 부모가 자체 예약의 원상태를 저장해 중지하고, 자식 실행만 기존 격리 잠금을 소유한다.

통합 fixture 후속 수리와 4년 게시 원인

두 번째 반복 실행기는 후보4년 첫 실행까지 진행한 뒤 알려진 게시 실패의 원인을 수리하기 위해 중단했다. 후보 게시3회는6027.54/6027.67/6032.51ms 모두57014였고 회복 전체237369.49ms에 미반영이 남았다.191438ms는 단계 사이에서 확인하는 회복 상한이라 진행 중 단계만큼 초과할 수 있으며, 이를 예산 충족으로 처리하지 않는다. baseline4년의 첫 계산38005ms/게시5890ms는 완료했다.10년과 두 번째 반복은 이 실행에서 측정하지 않았다. 중단 시점의 마지막 CPU 구간은 저장되지 않아 완전한 시계열로 사용하지 않는다.

R02/U06 precheck의 추가 실패2개는 제품 단언을 유지하며 재현·수리했다. D04의 public 관측 표 잠금은 이제 원본판 캡처 전 임시 표 준비를 막았다. 원본판 이후 관측 함수 진입점에 B 트랜잭션에서만 barrier를 주입하고 실제 advisory 대기를 확인한 뒤 원함수 정의를 복원한다. D11은 실제 경쟁 publisher가 run row를 점유한 채 owner 잠금에서 deferred 되면 본 publisher가 idle이 되는 경우를 재현했다. 원래 R02 실행의 경쟁 PID는 확인하지 못했다. fixture의 행 잠금을 게시 단언까지 유지하며 경쟁 publisher의 SKIP LOCKED도 검증했다. 전달 커밋 ba1914d47946cb0ebdf5142af661be296012f14c는2파일이며 제품기준646f71d6에서21/21통과했다. U06이 발견한 deploymentManifest의 최신 migration 누락은 03dcf548을 소비해 반영했다.

전체 payload를 추가 내부 함수에 전달하던 첫 성능 prototype은4년 게시6103ms로 실패했고 철회했다. 실패 원시값은 보존한다. 이후 같은4년 durable payload(비압축86,101,376bytes)에서13행 표 조회20회를 비교했다. SQL에 전체 payload를 전달하면1350.97ms, PL/pgSQL에서 표 JSON을 먼저 추출해 전달하면0.227ms였다. 작은 결과를 읽더라도 전체 매개변수를 전달하는 반복 비용이 확인됐다.

후속 최소 수리는 기존 validator/publisher 두 함수 안에서 SQL 입력을 해당 표로 제한한다. 동일 결과의 완료 인증도 전체 JSON 문자열·SHA 재생성 대신 definer 소유 임시 표에 작업·lease·트랜잭션·잠긴 run의 물리 행 버전과 검증한 source를 묶는다. 트랜잭션 중 행 버전은 재사용되지 않으며 payload/lease 변경은 새 버전을 만들어 전체 검증을 다시 거친다. 현재 원본·lease·날짜·실제 snapshot membership 검사는 유지한다. 함수 추가나 예산 상향은 없다.

4년 진단 후보의 반복계산(ms)게시(ms)결과
첫 게시39626.9975115.896완료
게시 후 같은 이력 재계산49799.7494591.224완료

후보는 20bf8b9b에 후속2함수 수정이며 원시자료에 source SHA-256과 CPU를 저장했다. 정식 clean migration 후보 측정과 구분한다. 관련 D11/D04 21개, full/incremental shadow와 worker7개가 통과했다. shadow는12개 canonical snapshot/11개 incremental 후보의 숫자·논리키·provenance·DTO 차이0이다.10년·혼합·최종precheck는 아직 이 결과에 포함하지 않는다.

Phase 4 입력의 조건 정정

U05의 DOM317과 G04예산294를 같은 조건의 전후 측정으로 표현하지 않는다. U05는1년260세션·390×844·CPU4배·Chromium151.0.7922.34·local HTTP에서 cold3/warm3 모두317이었다. 수집 시점은 tabbar 후4초와 fonts.ready이며 document 전체 연결 노드(head/script/숨김 포함)를 센다. G04는 tabbar 후3초이며 fonts.ready를 기다리지 않았다. 재현 문서의 seed는120세션이고 최초267의 원시 seed 수는 확인되지 않았다. 현재 자료만으로 증가한 노드23개/50개나342→317 감소분의 구성은 알 수 없다. Phase4는 실제 G04 조건과 최신 후보의 요소별 구성을 확인한 뒤 판정한다. 예산294는 유지하며 제거할 노드 수를 먼저 목표로 정하지 않는다.

Phase 2 — 10년 계산 수리와 게시의 남은 실패

2026-09-11, 작업 HEAD 7fb06e91은 release d63926b1까지 포함한다. 공통 수리646f71d6와 fixture ba1914d4는 앱 PR1577의 merge 4fe99af0로 release 반영을 확인했다. BUG124문서 PR76, merge 8652e2c2에 게시됐다. 새 장기 성능 수리의 release 반영·전체 gate·Production과 구분한다.

10년2,609세션/31,308세트의 최초 계산은60,047ms에57014로 실패했다. 이후 진단은 동일 합성 이력을 유지하고 변경 함수의 SHA-256을 저장했다. 아래는 미커밋 후보의 원인별 측정이며 최종 clean 후보 두 번 반복의 대체가 아니다.

병목수정·동치 확인관측
점수 기준 조회의4개 조인이 같은 운동의 전체 이력을 반복 탐색ordinal별 참조를 한 번 구성; 기존 순서·manual·seed 조건 유지한 운동1,008→76ms,1,206행 digest 동일; 전체 함수21.1→1.85초
선택 세트 UPDATE의 배열 조건으로 대량 조합 후 제거선택 ID를 펼친 equality join첫 운동205→59ms, 선택 ID 동일. 개선안 쪽은 비교·원복 UPDATE 이후의 heap으로 측정했으므로 순수한 cold 전후 비율로 쓰지 않는다
동일 정책 지문을31,308개 checkpoint마다 계산기존 private job context의 캡처 정책 재사용, 종료/게시 source 검사 유지정책 지문31,309→2회. 검증 뒤 정책 변경은40001로 거부하고 applied·정책 상태 불변
순수 분포 함수625,900회 호출내장 함수·연산자를 명시해 호출자 search_path 독립성을 유지하며 식 인라인126,012입력 digest 동일, 진단 반복4,016→287ms; 구간 경계 및 호출자 함수/연산자 회귀27개 pgTAP 통과
표마다 큰 JSON에 결과를 붙이며 전체 앞부분 반복 복사전체 표를 단일 object aggregate로 조립10년 계산56,014ms에 durable 저장 완료. 저장25,925,489bytes / JSON UTF-8 187,321,317bytes

분포 개선 후 projection 자체는46,765ms에 끝났지만 옛 조립 루프는60,449ms에 취소됐다. 단계 시각에서 작은 표의 aggregate가 끝난 뒤 다음 표까지0.2~0.9초가 반복됐고 예외 context가 JSON 결합 assignment를 지목했다. 단일 조립 후 계산은56,014ms, 별도 게시 추적 준비의 계산도55,356ms에 끝났다. 두 값은 정상 전체 파이프라인 두 번 합격이 아니다.

관련 D11/D04/D07/full-incremental shadow/worker DB32개가87.1초에 모두 통과했다. shadow는 기존 독립 snapshot/DTO/provenance 비교를 유지한다. 첫 실행은 sandbox 경로 환경 변수를 빠뜨려22개 skip/10개 준비 실패였으며 제품 검증으로 집계하지 않았다. 함수 재발행6개 후보 20260915013000_r04_long_history_compute.sql은 low/function이며 원본 DML과 기존 예산을 바꾸지 않는다.

정상10년 첫 게시가6,037ms에57014로 실패해 전체 gate는 계속 불합격이다. 게시 단계 진단은 다음을 구분한다.

  • 정상6초 실행은 validation 약1.14초, 전체 임시표·삭제 준비까지4.17초 뒤 첫 정규화 관측 INSERT 약1.45초를 쓰고 세션 요약 FK 검사에서 취소됐다.
  • 임시 native 행 비교의 전체 비용 진단은9.122초였다. 이 한정 진단은 트랜잭션 안에서20초까지 관측한 뒤 항상 rollback했으며, 제품 예산이나6초 합격 결과가 아니다.
  • 공개 결과가 빈 표에 바로 INSERT하는 prototype도 정상6초에 실패했다. 같은 rollback 진단의 전체 비용은8.351초였다. 두 게시 prototype은 제품 파일에 반영하지 않았고 새 저장 표·FK 제거·예산 상향을 시행하지 않았다.
  • 만료 후 동일 계산 결과를 추적한 일부 진단은 정확한 합성 owner/2,609세션을 확인한 뒤 트랜잭션 안에서만 lease를 갱신하고 rollback했다. 이 준비를 실제 claim/retry 회복 검증으로 표시하지 않는다. 진단 run은 별도 보관 후 해당 합성 owner의 파생 작업만 정리했다.

원래 첫4년 timer 로그 하나는 두 번째 계측 때 같은 이름으로 덮어써 파일 대조에 사용하지 않는다. 보존된 payload 입력 미세측정·정상 실패/성공 원시값을 근거로 삼으며 이후 모든 scratch 진단은 기존 파일이 있으면 실행을 거부한다. 정식 두 번1/4/10년·혼합·화면·필수precheck와 자기 release 병합은 여전히 남아 있다.

Phase 2-1 — typed 결과 저장 후보

2026-09-11 18:00 KST. HQ와 조율해 계산 결과의 큰 JSON 저장·재구성을 비공개 typed 표19개와 작은 manifest로 교체했다. 기존 full/pg_temp 계산과 public 원자적 게시·원본FK·세대·source/lease 검사·기본 full 설정·계산60초/게시6초는 유지한다. 정확한 저장/불변성/정리 계약은 D11 운영 문서에 적었다. 아래는 661308a4 이후 미커밋 후보의 진단이며, 최종 같은 커밋 두 번 반복을 대신하지 않는다.

진단계산(ms)게시(ms)결과
typed 최초10년48366.7266295.839게시57014, 실패 정리 포함. public/applied 미반영
typed 통계 준비 후10년51808.7665405.390사전 적재2,609세션/31,308세트, 기존 예산의 연속 committed stage 완료

작은 manifest는 최초 실행에서122,277bytes였다. 비공개 결과128,916행의 datum 합66,315,207bytes는 이전 JSON UTF-8 크기나 WAL과 동일한 측정 단위가 아니다. 각 표의 전체 relation 크기는 인덱스·TOAST·빈/죽은 공간·다른 run을 포함할 수 있어 job별 저장량으로 단정하지 않는다.

새로 대량 적재한 결과에 planner 통계가 없으면31,308행을1행으로 추정해 prior 표를 반복 조회하는 계획이 나왔다. 동일 입력 SELECT 비교는 미분석 사본 nested loop/31,308회 조회45.518ms, ANALYZE 뒤 hash join12.179ms다. 이 작은 SELECT 차이만으로 앞선6초 실패 전체를 설명하지 않는다. 실제 게시 실패 위치와 함께 결과 통계를 compute의 기존60초 예산 안에서 준비하는 근거로 사용했다.20초 rollback 진단 및 진단용 lease 연장을 정상 게시 통과/복구 증거로 합산하지 않았다.

clean migration replay에서 새 표와 run revision을 포함한 스냅샷 생성에 성공했다. D11·worker·D07 DB37개가 통과했고12개 canonical snapshot/11개 incremental 후보의 수치·논리키·provenance·DTO 차이는0이다. computed UPDATE/DELETE 변조, 누락/다른 owner/세대, 완료 후 검증 자료·정책 변경, stale lease, 정리 중 취소의 public/applied 롤백, 실제 두 연결 run 잠금 경쟁, 구 JSON publisher의40001 거부를 포함한다.

실제 DB 재시작 증거는1세션 계산 결과를 커밋한 뒤 전용PostgreSQL 컨테이너를 재시작하고 다른 backend에서 게시했다. postmaster 시작 시각이 바뀌었고, 비공개1행 보존→공개1행/fresh→비공개0행을 확인했다. 장기 성능 표본이 아닌 내구성 검사다.

첫 전체check 실패는 migration의 ADD COLUMN 멱등 구문, 수정 뒤 스냅샷 지문, private 결과를 public 작성자로 오인한 정적 분석과 run 작성자 장부의 차이였다. 실제 target 인자와 LOOP 경계를 해석하도록 보완한 작성자 검사10개가 통과했으며, 재생 후 전체check와 정식 반복을 계속한다. 새 마이그레이션의 위험 분류는low이고 사용자 원본 DML은 없다. 기존 실패 원시자료는 보존한다.

후속 clean 후보는 8a30feb5feea9c4e5033a4331d8720f5eac84a63이다. 멱등 DDL을 포함한 최종 clean 재생·schema/registry/DB 장부 생성 뒤 npm run check가3,627pass/0fail/110skip으로 통과했다(100.360초). skip은 정책 제외와 로컬DB를 지정하지 않은 검사의 미실행이며 DB37개 통과를 대신하지 않는다. 같은 후보와D11직전b0fa93ec의 정식 두 번 반복은18:02KST 시작했다. 코드 release 병합과 전체 성능 판정은 아직 남아 있다.

freshness 시간 지표의 호환성

2026-09-11 HQ가 기준선 문서·계측 SQL·구/현재 worker를 대조했다. G04 기록의10년 drain127,625ms와 job duration0, freshness847ms는 함께 보존한다. 당시와 현재 sync_user_stats_refresh_state_from_job은 모두 applied_at에 트랜잭션 시작 시각인now()를 쓰지만, 이전 worker는 계산·완료가 한 트랜잭션이었고 현재는 claim/compute/publish가 나뉜다. measure/db.mjs의applied_at-requested_at은 이제 compute 시간도 포함한다. 이전847ms를 실제 공개 결과의commit 완료 지연으로 해석할 수 없다.

기존847ms·상한1,101ms와 현재 값의 수치 초과를 삭제하거나 바꾸지 않는다. 원인 표시는 트랜잭션 경계 변화로 기준선과 동등 비교 불가, 해당 항목 합격 미입증이다. 단순 제품 회귀로 단정하지도, 미측정으로 삭제하거나 합격 처리하지도 않는다. R05에 이 호환성 항목을 미해결로 인계하며 전체G04 합격으로 덮지 않는다. 제품timestamp 의미·기본full·전역예산을 바꾸는 작업은 하지 않는다.

보강 관측은 별도 연결이 같은 owner의 완전히 적재된 requested generation을 처음 확인한 때부터 같은 generation의committed applied_version에 도달한 것을 처음 확인한 때까지다. 두 사건에 같은Node 단조 시계를 쓰고100ms 간격과 실제 polling 공백·각 조회 시간을 기록한다. 이는 정확한DB commit 순간이 아니라 외부에서 확인한 완료 시점이다. 이미 완료한 fixture를 처음 본 경우 경과 시간을 만들어내지 않는다. 이 관측과 기존state 시간 차를 분리해 보존한다. b0fa93ec→8a30feb5 비교는 R04 수리 효과의 증거이며 G04 기준16b8e996의 재현이나 새 예산을 뜻하지 않는다.

8a30feb5 고정 반복과 상세 조회 후속 수리

고정 반복 원시 분포·실패·파일 지문은 후보8a30feb5와D11직전b0fa93ec를 각각1/4/10년 두 번씩 실행한 결과다.09:02~09:38Z에 제품 파일을 변경하지 않았다. 후보6회 모두 기존 compute60초/publish6초 안에서 수렴했다.26가지D14 저장×20표본×6회,3,120표본 오류0이며 각 이력 첫 반복의 원본/ID/receipt/세대 동치 검사도 통과했다. baseline의 최초 운동/세트 삽입은 순서값 고유 제약, sparse_positions는 정수 overflow로1/4년 각20회 실패했다. 실패3가지와 나머지23가지 공통 성공을 구분하며, baseline10년 두 번은 계산60초에 실패해 해당 읽기/저장 검사를 실행하지 않았다.

이력·반복계산(ms)게시(ms)전체 회복(ms)상세 조회p95(ms)
1년15019.518536.7405805.11427.67
1년24972.048649.8715832.21320.51
4년117889.2382169.01920258.63036.83
4년218110.0091964.01220266.81940.63
10년149101.5735549.33054910.10566.31
10년249061.5245109.72654403.13561.94

상세 조회는20ms 상한을 넘었다. 외부 완료 관측의10년 첫 반복은54,999.077ms, 실제 최대poll 공백121.412ms였다. observer 시작 전 끝난 첫1/4년은 누락으로 남겼다. CPU 시계열을 보관하며 baseline10년 두 번째 중 다른 전용DB의 짧은 읽기 진단이 겹친 제한을 적었다. 정확한 전후 개선율이나 전체G04 합격을 주장하지 않는다.

HQ가 R04 단독 소유로 배정한 읽기 수리는 set_score_session_v2, 순수 기록 프로필 함수2개와 기존 세트 파트의 실측 적격 부분 인덱스1개다. 실측 후보를 인덱스로 직접 조회하고, 추정 후보는 최신 완료 세션부터 필요한 첫 후보까지만 찾는다. 독립 set_score_reference_v2, 역사 순서·동률·manual·중복 운동 파트·복합·owner·누락 조건·DTO·정책은 유지한다. 추가 covering/시간 인덱스·새 read model·예산 상향은 채택하지 않았다.

진단 원시값·마이그레이션 증거 목록의10년 transaction prototype은 실측 없는 조건p95 50.607→12.516ms, 오래된 실측 있는 조건40.864→11.513ms(각20표본), 각 조건oracle DTO digest 동일이다. rollback을 거친 함수 누적 카운터는 앞선 variant를 포함할 수 있어 variant별 비용으로 해석하지 않는다. per-call 시간·digest와 최종 clean 반복을 별도로 사용한다.

high migration33000의 최종 지문은2c3a6c75다.8a30feb5의2,609세션/31,308세트·원본81,673행 위 적용288ms/WAL0.12MB, 표본lock wait0, 실제 읽기·save rollback7probe 오류0,1/4statement 중단 후 재적용 및 원본 값/ID/관계 보존을 확인했다. 고정fixture는RPE8이라 인덱스 적재행0이며 조밀한 실측 인덱스 생성 비용은 미검증이다. 사전 SQL 구분자 오타로 실패한v2도 보존하고 수정한v3만 적용 증거로 사용한다. 도구의to=8a는dirty worktree의HEAD 표기다. 새 schema 생성 전 provisional 비교 대신 clean reset 실제schema SHA-256·지문을 갖춘 companion 비교로494함수/107표,break/warning0을 확인했다.

후속 후보 1ea1fa1a는 clean migration 재생·schema/registry/DB장부 생성, 관련DB40개, 점수/중복 파트/복합/search_path pgTAP93개가 통과했다. 일반check의 기존IN 문법 전용 단언은 같은 정책의pg_catalog 연산자로 갱신했고3,627pass/0fail/110skip(102.940초)이었다. 최종 같은후보1/4/10년 두 번 반복은10:27Z 시작했으며 이 절은 그 결과나Phase2완료를 미리 주장하지 않는다.

1ea1fa1a 반복 완료 — 상세 조회 통과, 연차 추세는 별도 진단

후보 1ea1fa1a99c0280c70485ef2100f77356c3d4570의 여섯 반복은10:27:31~10:40:40Z에 종료했다. 실행별 분포·단계·DML·WAL·파일 지문, CPU, 별도 연결의 완료 관측을 보존한다. 기존b0fa93ec 대조군과8a 중간 후보는 앞 절의typed-matrix에 남으며 다른 후보 수치로 덮어쓰지 않는다.

이력·반복계산(ms)게시(ms)회복(ms)상세p95(ms)홈p95(ms)볼륨p95(ms)
1년14818.61534.585501.6919.1710.95122.57
4년117028.412057.3319265.9017.5722.481030.19
10년147498.865254.9353007.8716.3642.402715.46
1년24809.94572.245552.6815.4412.53214.96
4년217251.762062.4719538.7116.4322.821027.93
10년246979.705109.5952317.3916.6836.522781.74

상세 조회20ms와10년/1년2배 상한은 두 반복 모두 충족했다. 계산60초·게시6초·전체10년 회복191438ms도 각각 충족했다. 새 후보에서도D14 26종×20표본×6회3,120표본 오류0, 각 첫 반복의독립 ID/원본/receipt/세대 검사가 통과했다. 적재 저장p95는57.50/44.45/44.16/41.67/42.60/43.16ms이며40ms는혼합 프로필에 배정된 예산이므로 이 값으로 혼합 합격/불합격을 대체하지 않는다.

홈10년/1년은3.87/2.91배, 볼륨22.15/12.94배로 기존추세 상한2/10을 넘었다. 월 조회도18.81/6.31=2.98배 및16.66/6.47=2.58배다. 같은 제품·원본의 후속 별도 연결20표본에서는 홈p95 13.79ms·볼륨344.524ms였지만 이 빠른 값을 원 실행의 대체 합격 값으로 사용하지 않는다. 표 자동정비·통계 갱신 시각과함수/계획 캐시 차이는 아직 원인 확인 중이다.

HQ는 사전에자동정비 완료를 기다리는 기존면제 규칙이 없으며, G04볼륨 기준선17.7배 자체가상한10을 넘는 사실도상한 변경/면제 사유가 아님을 확인했다. 원래 초과·상한은 유지한다. 진단 조건은 사전에 고정하고같은역할/SQL/파라미터·계획/추정행/실제행·통계시각을 대조한다. 준비 도구 문제로 확인될 때에만최소도구수정과절차가 명시된재검증으로 연결하며, 다른준비조건의진단을원 G04 결과와섞지 않는다. 추가제품수리·인덱스·새담당자는 배정하지 않았다.

프로필 교체 후 남은 planner 통계 — 준비 도구 수리

진단·실패한 준비·실행 계획 원시값을 보존했다. 동일 후보 1ea1fa1a에서 자동 정비를 전용 DB의 대상 표에서 잠시 중지하고, 4년 이력을 분석한 뒤 10년 이력으로 교체했다. 자동 정비를 끈 설정은 두 진단 모두 원래 값으로 복원했다. 같은 원본·역할·SQL·파라미터에서 새 연결로 각 20표본을 재고, 중간에는 VACUUM이나 원본 수정 없이 ANALYZE만 수행했다.

RPC갱신 전 p95(ms)ANALYZE 뒤 p95(ms)응답 digest
home38.04413.363동일
month22.5907.207동일
volume2775.147364.371동일

별도 계측을 켠 전후 1회 실행에서는 다음 계획 차이를 확인했다. 계측 비용이 들어간 이 1회 시간은 위 p95와 구분한다.

  • 홈의 연간 합계는 실제 11행을 1행으로 추정해 다른 기간 3,293행을 걸렀다. 갱신 뒤에는 추정/실제 11행과 기간 인덱스를 사용했다.
  • 달력의 세션 합계는 매 세션마다 3행을 얻으면서 7,824행을 걸렀다. 갱신 뒤 user_exercise_session_rollups_session_idx에서 추정/실제 3행을 조회했고, 네 번의 불필요한 이력 탐색이 사라졌다.
  • 볼륨의 기간 결합은 owner의 16,860행을 1행으로 추정했다. 해당 계측 쿼리 2,901ms가 갱신 뒤 요청 기간별 인덱스 조회 299회·평균 10행, 58ms로 바뀌었다. 모든 호출의 응답 digest는 전후 같았다.

최초 계획 수집은 일반 postgres 계정의 라이브러리 로드 권한 때문에 실패했고, 다음 시도는 갱신 전 수집 시점을 놓쳤다. 최종 수집은 supabase_admin으로 로컬 계측 모듈을 준비한 뒤 실제 호출을 authenticated로 맞췄다. 실패한 준비를 성공 표본에 합산하지 않았다. 전체 check는 3,627pass/0fail/110skip(105.417초), 마지막 WAL 기록 추가 뒤 문법 검사와 관련 성능 검사 12개가 통과했다. 첫 한정 검사에서 tsx 등록을 빠뜨린 모듈 로드 실패도 원래 로그에 남겼다.

HQ가 확인한 최소 수리는 8a138f9dscripts/performance/measure/integrated.mjs 한 파일이다. 합성 owner를 DELETE하고 다른 이력으로 대량 교체한 뒤에도 이전 owner 분포가 남는 준비 조건을 명시적으로 통제한다.

  • 적재 직후 session, session_exercise, session_exercise_part, exercise_set, exercise_set_part를 ANALYZE한다.
  • 정상 게시와 고정 PR 날짜 창 준비 뒤, 각 DB 버전의 stats_projection_tables_v1()이 반환하는 공개 투영 표를 ANALYZE한다. 대조군 18개/후보 19개라는 제품 계약 차이를 표 목록에 남긴다.
  • 준비 단계의 벽시계와 cluster WAL을 별도로 기록한다. cluster WAL에는 동시 작업이 기여할 수 있다. 이 비용을 전체 비용에서 없애거나 worker/read 시간의 차이를 전체 개선으로 외삽하지 않는다.
  • 이 절차는 고정된 읽기 fixture의 준비에만 적용한다. 혼합 부하 중 실제 저장·게시·읽기 사이에 ANALYZE나 sleep을 끼워 넣지 않는다. 제품 설정·예산·인덱스는 바꾸지 않았다.

r04-statistics-controlled-v1 준비 절차를 양쪽 DB와 1/4/10년에 동일하게 적용한 두 번 반복은 10:57:30Z에 시작했다. 원래 준비 절차의 초과 결과와 구분해 보존하며, 아직 전체 G04 합격이나 Phase 2 완료를 주장하지 않는다.

Phase 2 — 통계 준비를 맞춘 최종 두 번 반복

최종 비교 원시자료 56개·요약, 고정 예산 대조, 별도 연결의 완료 관측. 후보 8a138f9d0809e33f3c85b60e5e1e0dc28a613c38은 제품 SQL 1ea1fa1a와 같고, 추가 변경은 위 fixture 준비의 통계 갱신·비용 기록이다. 10:57:30~11:27:52Z의 12개 실행 동안 제품 정의를 변경하지 않았다. 후보 여섯 실행 모두 수렴했고 D14 3,120표본 오류0, 첫 반복의 이력별 원본/ID/receipt/세대 검사도 통과했다. 수정 전 b0fa93ec의 10년 두 실행은 계산60초에 실패했으므로 그 뒤의 읽기·D14는 미실행으로 남긴다. 1/4년의 기존 D14 실패3종도 원시자료에 보존했다.

이력·반복계산(ms)게시(ms)회복(ms)홈p95(ms)상세p95(ms)볼륨p95(ms)
1년·14801.32610.575562.9811.2716.26134.19
4년·117506.742103.3119789.9211.5817.24259.43
10년·147191.965165.9352581.1213.7216.41341.03
1년·25715.64570.156445.0612.5115.74126.03
4년·216984.302062.3219230.7510.8819.09263.47
10년·247127.625120.1852480.8014.3015.86342.89

9개 RPC×6실행의 각20표본 p95는 모두 고정 절대 상한을 충족했고 두 반복의 10년/1년 조회 증가율도 모두 상한 안이었다. fixture 적재 create p95는 표 순서대로40.62/44.27/43.54/41.18/41.94/44.31ms이며, 각 반복의 10년/1년 쓰기 증가율1.07/1.08배는1.5배 상한 안이다. 이 적재 수치를 아직 실행하지 않은 혼합 저장40ms 기준의 성공으로 사용하지 않는다.

10년 회복은20.15/20.12ms/세션, 단계별 WAL 합은95.30/95.40KiB/세션이었다. 기존191438ms·74ms/세션·233KB/세션 상한을 충족한다. WAL은 별도 트랜잭션의 cluster insert LSN 차이 합이며 동시 내부 작업의 WAL이 포함될 수 있다. 계산60초/게시6초를 올리지 않았으며 track_functions/DML 계측이 켜진 로컬 SQL 비용이다.

준비 ANALYZE는 원본/공개 통계 순서로1년45.67/202.76ms와81.79/174.66ms, 4년100.28/486.05ms와94.81/457.71ms, 10년204.44/1012.16ms와192.96/1015.72ms였다. 준비 중 cluster WAL도 각 실행 원시자료와 판정표에 별도로 기록했다. 이 비용을 총개선에서 숨기거나 통계 갱신 전 실패 결과를 대체하지 않는다.

이는 통제된 장기 이력 측정의 해당 예산 충족이며 전체 G04 합격이 아니다. freshness의 기준선 호환성 합격 미입증, 최종 공개 통계 변경행·전체 재계산 대조, 혼합 부하와 브라우저 검증은 각각 별도로 남아 있다.

Phase 2 — 이미 게시된 10년 이력의 후속 저장 실패

원래 실패와 rollback 진단. 최종 초기 적재 반복 뒤 같은 10년 계정에 오늘 기록 1건(12세트)을 추가했다. 원본 저장은 완료됐지만 계산 두 번은60158.94/60156.06ms에57014로 중단됐다. 전체 회복191798.39ms 뒤 실패 잡1개와requested2610/applied2609가 남았다. 원본 등급 값·ID·부모 관계의 해시는 계산 전후 같았다. 감사에 잡힌 행은 저장이 남긴 달력 dirty 표의변경이며 계산 단계의 public audit 함수 호출은0이었다. 뒤의 메모·과거 수정·최대기록 삭제·full 대조는 이 실행에서 시작하지 않았다.

원래3/60초 예산을 유지한 rollback 진단의 PG_EXCEPTION_CONTEXTreuse_stats_projection_rows_v1user_exercise_strength_observations 비교 UPDATE를 가리켰다. 최초 공개 통계가 비어 있을 때와 달리, 이미 게시된 통계의 재사용 판단에서 전체 행을 반복 JSON으로 변환하고 계산 이력용 열을 제거하는 비용이 더해진다. 임시 수정은 이 함수 하나의 일반 열을 NULL-safe typed ROW로 비교하고, families 안의 기존 applied_version·materialized_at 제외 의미만 유지한다. 변경되지 않은 값의 계산 이력 정보만 재사용한다.

첫 rollback prototype은 같은 실패한 append에서 계산58430.90ms·게시1104.88ms로 종료했다. 함수·claim/attempt·임시 출력·게시 모두 rollback했으므로 커밋된 후보나 최종 지연 합격 증거가 아니다. 기존 JSON 재사용 함수를 독립 대조로 복사한 NULL/값 변경 검증을 진행 중이다. 첫 대조 준비는 두 입력에 UUID를 각각 생성해 달라진 fixture로 실패했고, 값을 한 번만 정하도록 수정했다. 이어진 검사는791건 동치 뒤 families의 SQL NULL을 기존처럼 오류로 취급하지 않는 prototype 차이를 찾았다. 공개 표의 NOT NULL 제약상 실제 저장 불가 입력이지만, 기존 의미를 유지하도록 해당 경우까지 맞춘 뒤 다시 검사한다. 원래 실패와 각 준비 실패는 성공으로 합산하지 않는다.

마지막 대조(v3)는 실제 비교하는15개 표의663개 변형이 모두 일치했다. 비교에서 제외되는 게시 식별3개 표는 매번 전체 출력 해시 대조에 포함하되, 함수가 비교하지 않는 열의 중복 변형은 반복하지 않았다. NULL/빈 families의 기존 거부·비교 의미도 보존했다. 이 회귀 검사는 표별16개 테스트로 나누어 각 CASE60초 제한을 유지한다.

이 단일 함수 수리는 HQ가 기존 R04 후속 저장/결과 재사용 범위로 확인했다. 실제 정의와 low 위험 마이그레이션 20260915043000_r04_typed_row_reuse.sql(지문17922f2c)에 적용했다. 새 인덱스·테이블·제품 정책·default full·60/6초 예산을 바꾸지 않는다. clean DB 재생과 실제 후보의 후속 저장/무관한 공개 행 쓰기0/full 대조가 끝나기 전 Phase 2 완료로 보고하지 않는다.

Phase 3 실행 조건 — HQ 조율 결과

아래 조건은 계획이며 Phase 2 검증이 끝났다는 뜻이 아니다.

2026-09-11 20:18 KST, HQ는 기존 프로필의 5명×4년 초기 이력, 500세션 batch 1개, 분당 읽기20·일반쓰기2·인입1을 유지하는 독립 1분 투입 창 2회를 확인했다. 각 반복 전에 같은 격리 fixture/후보/통계 준비 상태를 다시 만들며, 앞 반복의 500세션을 다음 초기 이력에 누적하지 않는다. 1분은 요청 투입 기간이다. 진행 중 요청과 backlog는 이후에도 완료/실패와 기존 회복 예산까지 관찰한다.

각 반복·RPC·일반쓰기·batch별 계획/실제 시작·완료 시각, 겹침, 투입/완료/오류/미실행 수와 p50/p95/max/n을 기록한다. 일반쓰기 n=2의 p95는 작은 표본의 관측값이며 드문 지연을 충분히 검증했다고 하지 않는다. batch 내부 500저장을 일반쓰기 표본에 더하거나 정적 RPC 20회·D14 분포와 합치지 않는다. 실행이 밀려 계획한 빈도나 겹침을 달성하지 못하면 그 사실을 실패/제한으로 남긴다. 확인한 정본에는 실제 mixed 쓰기를 20표본으로 늘려야 하는 별도 최소 조건이 없으며, 새 5,000세션 fixture나 쓰기 빈도 상향을 추가하지 않는다.

기존 500저장 근사 인입과 지원되는 실제 인입 경로는 별도 증거로 다룬다. #1478 제외 범위는 복원하지 않는다. 이 절은 실행 전 조건이며 결과를 뜻하지 않는다.

acdc97ff 재사용 수정 검증과 후속 저장 제한 초과

후보 acdc97ff851f67aff931750d8dde96ae0bfaacd0는 clean migration 재생·schema/registry/장부 생성과 SQL 정의 검사를 마쳤다. 실제 DB의 재사용 동치 16개 CASE와 기존 차등 게시·full/incremental 대조를 합한 20개 검사가 모두 통과했다(150.583초). 각 CASE의 60초 제한은 유지했다. npm run check는 3,627pass/0fail/126skip(109.115초)이다. 늘어난 skip 16개는 DB 환경을 지정하지 않은 재사용 검사이며, 앞의 실제 DB 실행에서 별도로 통과했다.

10년 후속 저장 v6/v7 원시자료와 rollback 단계 진단을 초기 적재 성공과 분리한다. 같은 후보에서 각각 새 10년 fixture를 준비한 뒤 오늘 12세트를 추가했다.

실행함수 비용 계측첫 계산(ms)기존 재시도 계산(ms)게시(ms)전체 회복(ms)판정
v660263.575·5701459369.5441128.675151233.410실패 1회 보존·최종 수렴
v760241.177·5701458622.6031080.790150842.097실패 1회 보존·최종 수렴

양쪽 모두 requested/applied2610에 도달했고 사용자 원본 등급 값·ID·관계 해시가 보존됐다. 그러나 첫 계산이 제한을 넘었으므로 전체 실행 상태는 fail이다. v7의 미수집 함수/표 카운터는 null이며 0으로 합산하지 않는다. v7의 원본 저장과 worker 전체 cluster WAL은 별도로 기록했다. 다른 내부 작업이 cluster WAL에 기여할 수 있다. 이 실행들에서는 첫 사례 이후 8개 사례와 full 대조, 1/4년 후속 검사가 미실행이다. 별도 CPU 시계열도 수집하지 않았으므로 앞 후보의 CPU 증거로 대신하지 않는다.

함수 계측을 꺼도 첫 실패가 반복돼 profiler 비용만을 원인으로 단정할 수 없다. 이미 수렴한 v7 fixture에서 다음 저장을 넣고 sparse notice를 추가한 rollback 진단은 계산58.985초에 완료했다. 공개 결과 복사 등 준비0.886초·projector55.787초·영속화 등 나머지2.312초였으며, 해당 진단은 제한 초과 위치를 재현하지 못했다. 함수·원본·claim·결과는 모두 rollback했다. 이를 커밋된 지연 합격 표본이나 특정 SQL 결함의 증거로 사용하지 않는다.

다음 수집(v8)은 같은 후보·원래 예산을 유지하고, 기존 회복 예산 안에서 수렴한 사례의 실패를 누적한 채 후속 정확성 검사를 계속한다. 최종 실패 상태와 비정상 종료 코드는 유지하며, 불수렴이나 원본 변경은 즉시 중단한다. 각 이력은 새 fixture로 독립 실행한다. 이 변경은 성공 기준 완화나 재시도 증설이 아니라, 첫 실패 때문에 가려진 나머지 정확성 증거의 수집이다. Phase 2 완료와 G04 전체 합격은 아직 미입증이다.

v8 후속 저장 27개 사례 수집 완료 — 정확성과 시간 초과 분리

세 이력의 원시 결과·전체 재계산 대조·자료 지문. 후보 acdc97ff를 고정한 수집은12:21:11~12:53:04Z에 끝났다. 각각 새 fixture에서 오늘 append, 같은 mutation 재전송, memo-only, 동일 내용 새 mutation, 현재 load 수정, 복합/실측 최대기록, 과거 load 수정, 날짜 이동, 최대기록 삭제를 순서대로 실행했다.

이력사례 수실패 시도성공한 계산 시간 범위(ms)독립 full 대조 시간(ms)정확성실행 전체
1년905993.411~6245.1117003통과통과
4년9021603.704~34727.72136938통과통과
10년9858396.631~59141.39574778통과실패

위 시간 범위는 서로 다른 사례들의 성공한 계산이며, 이를 같은 모집단의 p95로 표시하지 않는다. 같은 mutation 재전송은 세 이력 모두 새 계산 표본0개이며 0ms 성공 표본으로 만들지 않는다. 10년의 나머지8개 사례는 각각 첫 계산이60초 제한에 실패하고 기존 재시도로 수렴했다. 실패8회를 지우거나 최종 수렴으로 시간 예산 합격을 대신하지 않는다.

각 사례에서 사용자 원본 등급 값·ID·부모 관계·revision/provenance 해시는 worker 전후 같았다. 독립적으로 정한 무관한 public 행의 쓰기0, expected requested/applied generation과 replay receipt를 확인했다. 세 이력의 최종 full maintenance 결과는 모두 논리 차이0이며 원본도 보존됐다. 대조 도구의16개 논리 결과 표와, public 감사19개 표·그중 무관한 일반 결과16개 표의 검사는 서로 다른 범위다. 게시 식별/보존 관리3개 표는 무관한 일반행0 판단에서 제외하되 실제 쓰기를 원시자료에 남겼다. dirty-date 제어행의 정상 표시/정리는 실제 값 변경 여부와 분리했다.

함수 계측은 껐고, source/worker 전체 cluster WAL은 각각 보존했다. 자원 표본은10년 준비 도중12:29:27Z부터 수집했다. 1/4년 및 v6/v7에 대한 소급 증거가 아니며, 이 표본만으로 특정 SQL이나 앞선 실패의 원인을 단정하지 않는다. 이 결과로 후속 정확성 미실행은 해소됐지만10년 계산 예산 초과와 freshness 호환성 합격 미입증은 여전히 남아 있다.

동일 입력의 추정 계산 공유 — 72891abf 후보

독립 입력 대조와 worker rollback 비교. 기존 refresh_user_strength_estimation_projection_from_v1는 각 source 행의 effective load/reps/result/RPE와 고정된 정책으로 변경하지 않은 calculate_strength_observation_v2를 호출한다. 같은 SQL 문 안에서 입력이 같은 source ID들을 묶고, 한 번 계산한 결과를 각 ID에 연결하는 방식만 비교했다. owner/종목/날짜/null/total 필터, 각 source의 나머지 열과 복합 제외 trigger·정책·후속 순서는 유지한다. 작업 사이에 남는 cache나 새 표/인덱스/설정은 추가하지 않는다.

실제31,320행/45입력 조합의 독립 대조는 차이0, 직접 계산4,428.527ms·공유56.984ms였다. NULL/0/실패/반복수/RPE 경계2,268행(756조합)도 차이0이다. 이45개는 한 쿼리 진단의 조합 수이며 제품 전체 호출 수가45개라는 뜻이 아니다.

같은 저장 입력·ID·claim 전 상태를 savepoint로 유지한 worker 비교는 계산58,747.136→54,343.849ms, 게시1,102.542→1,172.578ms였다. 제품 전체에서 해당 추정 함수 호출은36,147→4,881회, curve 조회 함수는127,701→33,903회였다. 함수별 수치는 rollback으로 지워지지 않는 트랜잭션 카운터를 각 trial 전후에 빼서 구했으며 overload를 function OID로 구분했다. 원래 projector를 복원한 full 대조, 두 trial의 public 결과, 원본 보존 모두 통과했고 전체 변경은 rollback했다.

원래 trial도60초 안에 완료됐으므로 특정 timeout SQL 또는 단일 원인을 확정한 것은 아니다. 같은 트랜잭션·캐시 조건의 진단을 실제 커밋된 첫 시도의 지연 합격으로 사용하지 않는다. 위 중복 비용 감소를 근거로 한 호출부만 후보 72891abf385e6d46f4d2a35c749463aeb84b6299에 반영하고 새 fixture에서 예산을 다시 확인한다. low 마이그레이션 20260915053000_r04_shared_strength_inputs.sql은 함수 재발행1개·지문a4527518이며 제품 예산과 default full은 그대로다.

clean migration 재생·schema/registry/DB장부·SQL 검사가 통과했다. 실제 새 DB에서는 중복 입력/NULL RPE/0/실패/맨몸/복합/total 제외의 per-source 독립 함수 대조와 기존 차등 게시/full·incremental 검사를 합한5개가 모두 통과했다(48.633초). 기존663개 행 재사용 변형의16 CASE는 앞acdc97ff에서 통과한 동일 재사용 함수 검사로 구분하고, 새 후보에서 재실행했다고 표시하지 않는다.

일반 check의 첫 실행은3,626pass/1fail/127skip(101.347초)이었다. 실패1개는 SQL 공백을 포함한 문자열에만 의존하던total 제외 단언이다. 실제 DB에서total 제외를 확인한 뒤 같은 조건을 공백과 무관한 패턴으로 검사하도록 바꿨다. 해당 검사 묶음5개와 최종 npm run check 3,627pass/0fail/127skip(106.859초)이 통과했다. 추가된skip1개는 DB 없는 check에서 빠지는 새DB CASE이며 위 실제DB 실행에서 통과했다.

재현 가능한 후속 도구는 앱 scripts/performance/probe/public-history-delta.mjs다. 명시한 disposable local sandbox와 고정 합성 owner/email/초기 세션 수, 중지된cron·정착한 시작 상태를 검사하고, 기존 파일 덮어쓰기를 거부한다. receipt/ID 검사는 메모리에서 유지하되 공개 자료에는 원본 행을 쓰지 않고 hygiene 검사를 통과한 계약 필드·집계·해시만 기록한다. 실패 누적/최종fail·비정상 종료, 불수렴 중단과 독립 full 대조를 유지한다.

이 후보의 고정1/4/10년 초기worker·읽기2회와 각 첫 반복의후속9개 사례 재측정은 시작했으며, 이 절은 그 결과나Phase 2 완료를 미리 주장하지 않는다. 앞선 실패 자료와freshness 호환성 합격 미입증을 그대로 보존한다.

Phase 2 측정 완료 — 72891abf, 2026-09-11 22:41 KST

고정 후보 72891abf385e6d46f4d2a35c749463aeb84b6299, tree 0941fab59784751acc0089b296200b7513add553의 새 fixture 반복은13:18:21~13:41:25Z에 완료됐다. 실행·27개 압축 원시자료 목록, 고정 예산 판정, 호스트 CPU 표본. 모든 실행의 통계 준비 비용은 worker 시간·WAL과 따로 기록했다. 이전 후보의 실패와 b0fa93ec 기준 실행을 보존하며 새 후보의 실행으로 바꾸지 않는다.

이력·반복계산(ms)게시(ms)초기 소진(ms)상세 조회 p95(ms)적재 저장 p95(ms)
1년·14392.454536.5015086.99816.0693.77
4년·116693.5072183.32219078.29817.4950.40
10년·143012.0655586.61048872.54015.4872.63
1년·24353.181647.8775178.86716.2838.82
4년·215213.6181985.69317377.84516.1742.28
10년·242250.3214978.86247462.67015.5244.94

9개 RPC×6회×20표본의54개 p95 판정과 두 반복의10년/1년 조회 증가율은 모두 기존 상한 이내다. 적재 저장 증가율은0.775/1.158배로1.5배 이내다. 첫 반복의 적재 시간이 더 큰 사실을 보존하며 전체 호스트 표본만으로 원인을 단정하지 않는다. 이 적재 저장 분포를 혼합 부하40ms 합격으로 사용하지 않는다.

10년 초기 소진은 두 반복 모두191438ms 이내, 세션당18.732/18.192ms(상한74), 단계별 cluster WAL은96.151/98.187KiB(상한233)다. claim3초/compute60초/publish6초 각각 충족, 실패·미반영0이다. cluster WAL에는 같은 DB의 다른 작업이 기여할 수 있다.

각 첫 반복에서 후속9개, 총27개가 모두 첫 시도에 통과했다. acdc97ff의10년 최초 계산8회57014를 보존한 상태에서, 새 후보의8개 계산은53,654.769~58,127.665ms·재시도0이었다. 같은 mutation 재전송은 새 계산 표본0개이며0ms 표본이 아니다. 원본 값/ID/관계/revision/provenance 보존, 독립 예상 무관 public 쓰기0, requested/applied 수렴을 확인했다. 각 이력의 마지막 독립 full 대조16개 논리 결과는 차이0이며 원본도 보존했다.10년 full 대조70.609초는 별도 유지보수 검증 시간으로 compute60초 지표에 섞지 않는다.

Phase 2의 구현·측정·관련 검사와 원시 증거 수집을 완료했다. 최신 후보의 npm run check는3,627pass/0fail/127skip(106.859초), 실제 관련DB5pass/0fail이며 위 절의 후보별 검사 범위를 따른다. 앞서 통과한 변경 없는 D14 원본 분포·재사용663변형을 새 후보 재실행으로 표시하지 않는다.

전체 G04 합격은 미입증이다. freshness는 트랜잭션 경계 변화로 기준선과 동등 비교 불가, 해당 항목 합격 미입증으로 R05에 인계한다. Phase 3 혼합·동시성, Phase 4 브라우저, Phase 5 최종 인계 및 Precheck/Merge Check/실제 release 병합은 아직 이 완료 범위에 포함하지 않는다. 오너 결정 없이 기준·예산·정책을 바꾸지 않는다.

Phase 3 진행 — 첫 동시 실행과 측정 날짜 정정

첫 동시 실행 원시자료·환경·자원 표본. 실행기 1d4851ad, 제품DB 72891abf. 고정 혼합 프로필의 초기5명×4년5215세션은 매번 새로 준비하고,500세션 근사batch는 live 창에서 한 트랜잭션으로만 넣었다. 일반저장은 같은owner가5초·다른owner가35초에 도착하며, 인입은0초·읽기는3초 간격이다. 긴 대기를 피하도록 도착 시각을 옮기지 않았다.

반복요청 성공/투입같은owner 저장(ms)다른owner 저장(ms)인입 전체(ms)관측
혼합123/2318008.91980.90522959 부근원본5개 표 보존·5717세션/68604세트·최종 수렴
혼합223/2317704.96674.14222659.678동일 정확성 통과·최종 수렴

각 반복에서 읽기 12개·일반 쓰기 1개가 계산과 겹쳤고, 잠금 대기는 최대 1개를 관측했다. 첫 반복은 투입 종료 뒤 9.145초에 모두 수렴했다. 일반 쓰기는 n=2이고 p95는 각각 18.009/17.705초로 40ms 상한을 넘었다. 일부 읽기도 상한을 초과했다. 기존 G04의 근사 인입 중 26.465초 max와 이 분포는 표본수가 달라 새 회귀로 단정하지 않는다. 요청 성공과 원본 보존을 성능 합격으로 바꾸지 않으며, batch 안의 500개 저장을 일반 쓰기 표본에 합치지 않는다.

10명 첫 실행은 읽기 100개·쓰기 20개 중 PR 읽기 5개가 applied generation 261 / as_of 2026-09-06 스냅샷 없음으로 거부됐다. 저장 20개·기존 원본 보존·최종 건수·수렴은 통과했다. 계산 1개는 40001로 무효화됐고, DB 보존 기록은 D11 source changed during computation, absorbed=true다. 현재 open/failed/stale는 0이다. 원시 recovery.status=fail/실패 1회와 convergence=pass를 함께 남긴다.

원인 확인: 실제 compute는 snapshot_anchor_date=current_date, publish도 current_date를 검사한다. PR 창은 anchor±1일의 세 날짜다. 초기 fixture만 과거 9/6으로 맞춘 뒤 새 세대가 현재 9/11 창으로 게시되면 9/6을 계속 요청할 수 없다. 이 경우 제품의 거부가 정상이며 측정기의 요청 날짜가 잘못 맞았다. 측정기 aeec72cd는 고정 이력·seed·빈도·쓰기 입력·도착 시각을 유지하고, PR만 사전에 기록한 실제 DB 현재일로 준비하고 요청한다. 다른 역사 조회는 기존 fixture 끝 날짜다. 실시간 요청 중 rollover·ANALYZE·sleep을 삽입하거나 제품 clock·정책을 바꾸지 않는다.

같은 수정에서 읽기 측정 구간을 기존 G04와 같은 RPC 직렬화·octet_length→서버시계로 맞췄다. 첫 실행기에 추가했던 GUC 결과 복사·해시 비용을 제거하고 응답 바이트는 유지했다. 위 v1 원시값을 정정된 절차의 값으로 바꾸지 않는다. 정정 후 후보/b0fa93ec의 혼합·10명·2기기를 각각 2회씩, 실제 InBody 경로를 별도로 검증 중이다. Phase 3 완료나 새 제품 수리·전체 성능 합격을 뜻하지 않는다.

Phase 3 — 전후 동시 부하와 실제 지원 인입 측정

2026-09-12, 전후 12개 실행·원시자료 79개·대기열·자원·수치 판정, 실제 InBody 2개 실행과 당시 소스, 실행기·관련 DB 검사·대기열 명령 검증. 측정 코드는 aeec72cd0ecececa559f49c7de1e6c14a8d41fe0, 후보 DB는 72891abf385e6d46f4d2a35c749463aeb84b6299, 이전 DB는 b0fa93ec97fab41c6bcbc59bd096f3e1926535fd다. 이 측정 기간에 제품 SQL과 실행 코드를 고정했다. 처음 중단한 진행 파일과 재개 파일을 모두 보존했고 이미 끝난 실행은 반복하지 않았다.

요청·원본·반영 결과와 전후 변화

각 프로필을 두 버전에서 각각 2회 실행했다. 혼합은 1분당 읽기 20·일반 저장 2·500건 근사 인입 1회, 10명은 읽기 100·저장 20, 2기기는 읽기 40·저장 4다. 두 worker 연결은 기존 claim 3초·compute 60초·publish 6초·최대 active 2를 유지한다. 투입 중 별도 ANALYZE나 준비용 지연을 추가하지 않았다.

항목이전 버전 1/2회현재 후보 1/2회
혼합 일반 저장 p95(ms), 회당 n=228616.177 / 29057.74818045.568 / 18551.411
혼합의 다른 사용자 저장(ms), 회당 n=1103.460 / 108.94774.683 / 83.355
혼합 통계 반영각각 게시 57014 3회, 미반영 사용자 1명두 번 모두 실패 시도·미처리·미반영 0
10명 일반 저장 p95(ms), 회당 n=2081.041 / 81.77268.205 / 67.062
10명 투입 종료→worker 확인 종료(ms)903.122 / 519.91768730.909 / 65559.320
10명 최종 통계 반영두 번 모두 전체 반영, 실패 시도 0두 번 모두 전체 반영, 실패 시도 각 2회
2기기 일반 저장 p95(ms), 회당 n=4128.808 / 122.464108.149 / 121.366
2기기 최종 통계 반영두 번 모두 전체 반영, 실패 시도 0두 번 모두 전체 반영, 실패 시도 0

전체 12개 실행에서 요청 오류 0, 기존 원본 5개 표의 행 보존과 최종 세션·세트 개수 일치를 확인했다. 하지만 혼합 저장 40ms는 충족하지 않았고, 10명 부하의 반영 완료 확인은 더 늦어졌다. 현재 후보의 10명 compute p95는 11649.398/10337.701ms, 이전은 1444.949/1461.873ms다. publish p95는 현재 258.399/277.242ms, 이전 832.150/831.076ms다. 부분 단계가 빨라진 것을 전체 개선으로 환산하지 않는다.

afterInputWallMs는 투입 종료 후 worker와 관측 연결이 종료될 때까지이며 polling 비용도 포함한다. 투입 창 안에 이미 반영된 실행의 남은 0.5~0.9초를 개별 저장의 freshness로 해석하지 않는다. 이전 버전 혼합의 이 값은 229917.244/230010.738ms로, 이미 시작한 단계가 회복 루프의 시작 상한 뒤까지 실행된 초과를 보존한다. 상태가 끝내 미반영이면 빠른 소진으로 판정하지 않는다.

현재 후보의 10명 첫 반복 실패 2건은 DB 기록상 계산 중 원본 변경이며, 두 번째는 계산 중 1건·게시 직전 1건이다. 모두 40001이고 후속 작업에 absorbed=true다. 이전 원본으로 만든 결과를 거부하고 최신 세대로 수렴했지만, 원시 status=fail·실패 시도와 convergence=pass를 함께 남긴다. 현재 실패 잡과 복구된 과거 실패를 합치지 않는다. 대기열 기록은 다음 fixture 삭제 전에 기존 observability view에서 수집했다. 처리 시작 시각은 마지막 재시도일 수 있으며 live 최대 queue age를 추정하지 않는다.

읽기 p95 전체는 요약의 readCeilingComparisons에 있다. 혼합 후보에서 일 요약 20.716/21.007ms, 상세 32.980/40.062ms, 수동 기록 2.264/1.061ms가 기존 수치 상한을 넘었다. 해당 읽기 예산의 원래 workload는 history이고, 이 live 창의 RPC별 표본은 2~3개다. 이 조건 차이와 초과를 함께 남기며 history 검증 통과 또는 요청 성공으로 대체하지 않는다. 동일 사용자의 세대 배정에는 트랜잭션 잠금이 있고, 500회 legacy 저장을 한 원자 트랜잭션으로 묶은 근사는 같은 사용자의 저장을 기다리게 할 수 있다. 측정에서 대기 backend 최대 1개를 관측했지만 그 표본만으로 정확한 대기 SQL별 시간을 나누지 않는다.

2기기 준비에는 원래 372개 작업·재생 60개·예상 충돌 26개를 유지했다. live 저장 4개는 두 독립 연결의 동시 생성 두 쌍이다. 같은 기록의 동시 수정·수정/삭제·같은 요청 재전송은 아래 별도 DB 검사에서 확인했다. 실제 물리 기기 두 대나 지원 사용자 수를 측정한 것으로 표현하지 않는다.

실제 InBody 지원 경로

고정 4년 이력의 새 합성 사용자에게 실제 parser·repository·인증 HTTP·Storage·import_inbody_body_metrics를 연결했다. 파일은 17477 bytes, 신체 측정 500행이며 500개 운동 세션이나 20MB 최대 파일 스트레스가 아니다. import RPC 호출 시점에 홈 조회와 일반 운동 저장을 시작했고, 두 반복 모두 HTTP 요청 구간의 겹침을 기록했다. 이를 관측하지 않은 서버 SQL 동시 실행이나 잠금 종류로 확대하지 않는다.

항목1회2회
Node의 실제 parser(ms)14.77815.601
repository 가져오기 전체(ms)203.420118.476
함께 실행한 홈 조회 HTTP(ms)34.71336.041
함께 실행한 일반 저장 HTTP(ms)82.13785.795
같은 파일 재전송(ms)11.07511.271

500개 날짜·체중·근육량·체지방량·체지방률을 독립 예상값과 대조했고, batch/source identity·보관 파일의 바이트 동일성을 확인했다. 재전송은 already_imported/새 행 0·배치 1개이며 기존 ID·값이 유지됐다. 두 번 모두 후속 통계 반영과 자신의 파일·Auth 사용자 정리가 통과했다. 이 프로브의 기존 운동 보존 검사는 session 부모 행이며, 5개 원본 표 증거는 앞의 동시 부하 matrix에 있다. HTTP 전체 시간과 SQL 전용 40ms 예산은 같은 경계가 아니다. 브라우저 parser의 정지 시간·힙 최고점이나 Production/Edge 배포 성공을 이 결과로 주장하지 않는다.

동시성 검사와 재현 명령

statsProjectionWorkerConcurrency·statsRefreshScopeConcurrency·workoutGenerationConcurrency를 기존 case 시간 제한 아래 순서대로 실행해 23 pass / 0 fail / 0 skip, 43.710초였다. 느린 다른 사용자, 임대 교체, 계산 중 새 저장, 원본 세션·세트 삭제, 실패 범위 흡수, 수정 충돌·재전송·계획 전환·원자 실패를 포함한다. 전체 Full CI가 아니다. 앱에 정리한 대기열 CLI는 이미 끝난 대조 fixture에서 원래 job/state/분위수와 정확히 일치했으며 부하를 다시 실행하지 않았다.

명령은 자신의 명시적 disposable BARBELIC_DB_SANDBOX와 실제 DB SHA를 사용한다. 동시 부하 도구는 등록된 fixture 소유자의 이메일이 합성 신원과 다르거나 통계 cron이 활성화돼 있으면 거부한다. 현재 앱의 재현 명령은 다음과 같으며, 측정 당시 원본 source SHA와 후속 CLI 정리를 구분한다.

sh
node scripts/performance/measure/concurrent.mjs --profile mixed-read-write-import --out <새-결과-폴> --database-release <실제-DB-SHA>
node scripts/performance/measure/concurrent.mjs --profile multi-owner-10 --out <새-결과-폴> --database-release <실제-DB-SHA>
node scripts/performance/measure/concurrent.mjs --profile same-owner-two-devices --out <새-결과-폴> --database-release <실제-DB-SHA>
node --import tsx scripts/performance/probe/supported-inbody.mjs --out <새-결과-폴> --database-release <실제-DB-SHA>
node --import tsx --import ./tests/support/registerNodeTestBudget.mjs --test --test-concurrency=1 tests/db/statsProjectionWorkerConcurrency.test.mjs tests/db/statsRefreshScopeConcurrency.test.mjs tests/db/workoutGenerationConcurrency.test.mjs

Phase 3 최종 앱 커밋은 8d311598이다. npm run check3627 pass / 0 fail / 127 skip, 97.702초였고 git diff --check도 통과했다. 측정 당시 aeec72cd 소스와 이후 재현 CLI 정리를 구분한다. Phase 3/5 완료이며 Phase 4·5와 필수 precheck·Merge Check·실제 release 병합은 남아 있다. 전체 G04 합격은 여전히 미입증이다. freshness는 트랜잭션 경계 변화로 기준선과 동등 비교 불가, 해당 항목 합격 미입증을 유지하며 847ms/1101ms와 R05/R06 조건을 변경하지 않는다.

Phase 4 — 기기·화면 통합 측정 완료

2026-09-12, 최종 비교·원시자료20개·체크·실행 소스. 앱 09aaa9a45e9a9848dc4809b5905768028bc2a081, 제품 DB 72891abf에서 G04 2회와 U05 12회를 15:58:18~16:01:49Z에 실행했다. 마지막 변경 두 개는 측정기의 오래된 repository import와 fixture 종목 해석을 고쳤으며 제품 SQL·UI는 바뀌지 않았다. local target 빌드 산출물100개 텍스트 검사·실제 서버 비밀값1개 부재 검사가 통과했다. 키 값은 증거에 포함하지 않는다.

G04 실제120세션과 과거 DOM 비교의 한계

반복cold 홈 준비(ms)cold load(ms)script 전송(bytes)/개수cold/warm DOMwarm 홈 준비(ms)
1877251.2565817 / 38317 / 3171157
2966233.9565817 / 38317 / 3171264

두 번 모두 실제120세션을 검증했다. mobile390×844·CPU4배·tabbar 후3초·fonts.ready 미대기 조건이다. cold 홈1448ms/load456ms/script601434bytes 상한은 충족한다. DOM317은 숫자로294를 넘지만 과거267의 실제 적재 건수가 확인되지 않아 동등 비교와 해당 합격은 미입증이다. 267·294·317을 모두 유지하고 예산을 올리거나 제품 DOM 회귀를 확정하지 않는다.

처음 실행은 build-artifact 필수 CLI 인자 누락, 다음은 현재 harness에 없는 repository export 참조로 중단됐다. 이후 v2는 CLI exit0이었으나 부모의 실제 건수 검사가 seededSessions=0을 발견했다. 이 자료는 invalid-v2-zero-sessions.json.gz로 보존하고120세션 표본에서 제외한다. 기존 측정기는 catalog의 slug로 종목을 찾고 없으면 저장을 건너뛰었다. 최종 측정기는 기존 DB load 도구의 canonical identity 해석을 사용하고 누락을 실패로 처리한다. 명시적 local sandbox/API/DB를 먼저 검사한다.

역사 대상 16b8e996exercise_catalog_item_json_v1도 slug에 빈 문자열을 반환하며, 원래 browser 측정기 이력은 beff760b 이후 위 수정 전까지 바뀌지 않았다. 다만 당시 ignored 원시 JSON을 찾지 못했으므로 과거 실제0건이라고 단정하지 않는다. HQ가 기존 #1284 기록에서 실행·종료0·DOM267을 확인했지만 실제 seededSessions 증거는 없었다. 이전 실행 전체 재현이나 기록 복구를 새 선행 작업으로 만들지 않는다.

U05 같은 조건 비교

이전 beedaacf와 같은1년260세션·mobile390×844/desktop1440×1000·Asia/Seoul·CPU4배·cold/warm 각3회·4초와 fonts.ready 조건이다. 실제260건,12회×10전환=120전환, 페이지 오류0·미방문 화면 요청0을 확인했다. 각 셀은 이전→현재이며 시간은ms다.

기기·cache홈 중앙값 / 최대load 중앙값script 실행 중앙값DOM초기 gzip bytes
mobile cold925→885 / 950→1047259→279.2805.268→843.011317→317552758→552529
mobile warm1257→1250 / 1297→1269124.8→125.61657.449→1628.602317→317552758→552529
desktop cold1023→1068 / 1180→1114243.1→259.1778.034→768.0731757→1757500776→500410
desktop warm1176→1213 / 1326→1316126.4→132.41361.901→1381.5621757→1757500776→500410
기기·cache달력 첫 진입볼륨 첫 진입달력 재진입볼륨 재진입프로필 첫 진입
mobile cold291→289621→57283→78552→621769→654
mobile warm315→259590→56886→90651→586704→789
desktop cold541→569185→190201→194168→174299→303
desktop warm629→537201→176207→215164→172307→311

초기 script 개수는mobile38/desktop23으로 같다. 각 첫 방문의 추가 청크와 재방문 추가gzip0을 원시 분포와 보존했다. 첫 font 요청은cold200·비캐시·약1.29MB이고 warm은disk cache·전송0이다. 외부font 네트워크와 공유 호스트는 통제되지 않았다. ScriptDuration은 실행을 포함하며 V8 parse 단독 시간이 아니다. CSS/font 요청과 실제 DOM을 관측했지만 개별 layout 비용·native·Production CDN·HTTPS service worker·Production Edge 성공은 미측정이다. 이러한 한계와 느려진 전환을 전체 개선으로 바꾸지 않는다.

S07 및 기존 유효 증거의 재사용

실제 Chromium IndexedDB/localStorage의 outbox drain은1/100/1000건3검사 모두 통과했다(8.135초). source 8d311598 이후 최종 후보까지 변경 파일이 browser 측정기 하나뿐임을 확인해 이 결과를 재사용했다. 1000건에서 읽기 배율7.48≤12, 미러 쓰기 배율1.49≤6, 전체 조회11≤40, drain4956ms다. 기존 S07 값7.84/1.85/15회/6077ms와 구분하며 wall 시간은 새 CI 예산이 아니다. 1/100건 읽기6배·미러 전체 쓰기0·전체 조회3회를 함께 보관했다.

U04의 live DOM·identity와 U06의 저장 identity, B02 환경별 빌드 경계, I01 지원 parser/파일 경계는 해당 변경 없는 구현의 기존 증거를 재사용한다. 현재 빌드 검사와 실제 화면·API RPC·Phase3 지원 InBody가 통합 경계를 보완한다. I01의 과거 Node 대용량 진단을 현재 브라우저 최대 파일 처리나 실제 upload 검증으로 부풀리지 않고, #1478에서 제외한 와드업/관리자 검사를 복원하지 않았다. D12의 과거 생략 운영 측정도 재개하지 않았다.

자원 표본은15:58:26Z부터 첫 G04 중간 이후만 수집했다. 원본 설명의 v2 표기는 요약의 metadataCorrections에서 v3로 정정하고 원시파일은 보존했다. 초기 outbox/build 및 앞선 구간을 포함하지 않으며 특정 SQL에 CPU를 귀속하지 않는다. 공개 JSON은 데이터 내용이 없는 측정 카운터 이름만 hygiene 규칙에 맞춰 바꿨고 원본·공개·압축 SHA256을 연결했다.

Phase4 최종 npm run check3627 pass / 0 fail / 127 skip, 99.776초였다. Phase 4/5 완료는 측정·증거 수집의 완료이며 G04 전체 합격·최종 precheck·Merge Check·release 반영은 별도다.

Phase 5 — 최종 판정과 R05 인계

2026-09-12. 원본·공개 결과의 정확성, 성능·회복·브라우저 조건을 분리한 아래 판정으로 인계한다. 전체 G04 수락은 미입증이며 이슈의 성능/freshness 완료 항목을 전부 체크하지 않는다. 통합 전 후보 앱 09aaa9a45e9a9848dc4809b5905768028bc2a081, 제품DB 72891abf385e6d46f4d2a35c749463aeb84b6299, D11 직전 대조 b0fa93ec97fab41c6bcbc59bd096f3e1926535fd다. 최종 release 병합 SHA·precheck 결과는 병합 확인 절에 별도로 추가한다.

수락 대상판정증거·해석
기존 사용자 원본 값·ID·부모·revision/provenance통과한 실행 범위에서 보존D14 독립 변경행·26사례, D11 후속27사례, 동시부하12회, 관련 DB 검사. 실제 사용자 데이터를 fixture로 수정하지 않음
무관한 원본/public 행 쓰기0·full 동치최종 경로의 관련 검사 통과1/4/10년 후속 각각9사례·full 논리16표 차이0. 공개 감사19표 중 게시/관리3표의 정상 쓰기는 별도 보존
1/4/10년 읽기·증가 추세기존 상한 충족9RPC×6실행×20표본,54개p95와10년/1년 증가율. DB cold-cache 또는 Production 예측 아님
최종10년 초기 소진·compute/publish/WAL기존 상한 충족소진48.873/47.463초, compute43.012/42.250초, publish5.587/4.979초. 단계별 WAL96.151/98.187KiB/세션
최종10년 후속 저장첫 계산8개·정확성9개 통과compute53.655~58.128초, 기존60초 유지. 재전송은 새 계산 없음. 앞 후보 최초8회57014는 보존
개별 저장 freshness동등 비교·합격 미입증트랜잭션 경계 변화로 기준선과 동등 비교 불가.847ms/1101ms 유지. 초기 backlog/afterInputWall/마지막 poll을 대체 지표로 쓰지 않음
혼합 일반 저장40ms미충족같은 사용자18.046/18.551초·다른 사용자74.683/83.355ms. 500회 legacy 원자batch 근사와 실제 InBody를 구분. 요청·원본·최종 반영 성공은 예산 합격 아님
여러 사용자 회복수렴 확인, 지연 악화 보존후보10명은 각2회 원본판 변경을 거부·흡수한 뒤 전체 수렴. 투입 종료→확인 종료0.9/0.5→68.7/65.6초. 개별freshness로 해석하지 않음
실패·미처리·대기열 추적실행별 증거 확보당시 job/state·generation·상태·실패SQLSTATE·흡수·lock 관측을 다음fixture 삭제 전에 수집. 최초/현재/복구 실패를 분리. live 최대queue age 미관측을 추정하지 않음
기기 outbox·같은 U05조건관련 검사·분포 확보1000건 비용 상한 충족,12회/120전환 오류0,DOM317/1757 유지. 느려진 전환도 원시값 보존
G04 DOM294숫자 초과·동등 비교 미입증실제120세션317. 과거267의 실제seed 미확인. 예산변경·확정제품회귀·과거0건 주장 없음
비통계/API/지원파일/자원측정·재사용 범위 한정실제500행 InBody parser/Storage/RPC·파일/재전송 동치2회. 일반 읽기/feed/search/manual과 브라우저RPC·font/CSS·빌드 증거. 기존 I01 대용량Node 근거의 실행환경·시점 유지
최대파일browser힙·V8 parse단독·native·Production/Edge/CDN/SW미측정 유지작은 파일·local HTTP 또는 과거 Node 자료로 대체하지 않음. #1478 제외와 D12 과거 운영 생략 유지

구조적 수리와 남는 비용

원본 사실은 변경하지 않았다. 계산 중 public 정규화 관측 쓰기/삭제와 원본 FK 잠금의 교착, 결과 저장 취소의 예외 경계는 앞서 R02 통합 PR#1577로 전달돼 BUG-124에 기록됐다. 이번 최종 후보는 전체 JSON 반복 전달/검증을 줄이고, 계산 결과를 lease에 묶인 비공개 typed 표로 영속화해 게시가 필요한 결과 행을 직접 읽게 한다. 동등성·원본판·권한·임대·원자적 게시/정리 조건을 유지한다. 별도 부분 인덱스로 세트 점수 참조 검색의 긴 정렬/순회를 줄였고 동일 순수 추정 입력은 한 SQL 안에서만 공유한다. 재사용은 SQL NULL과 JSON null을 구분하는 native 비교로 검증했다.

이 변경은 suffix 전체 계산을 없앤다는 약속이 아니다. full 계산·필요한 임시 결과 준비·정당한 과거 영향 suffix·원본판 변경의 기존 재시도 비용은 남는다. 워커 제한/시도 수/동시성·제품 예산을 늘리는 대안, 원본 FK 제거·원본 임의수리·무관한 UI노드 삭제·새 대시보드/관측 플랫폼 추가는 채택하지 않았다. compute 일부가 빨라진 수치나 작은 fixture로 전체 개선율·지원 동시 사용자 수를 외삽하지 않는다.

재현 자료와 운영 경계

각 절의 summary는 원 실행의 SHA·시간·fixture·opsDigest·환경·원시 분포와 원본/공개/압축 지문을 연결한다. 앱의 기존 scripts/performance/measure/{integrated,worker-stages,db,concurrent,concurrent-queue,browser,feature-loading,feature-graph}.mjs, probe/{session-write-delta,public-history-delta,stats-row-reuse-equivalence,supported-inbody}.mjs를 사용한다. 당시 scratch 실행기는 압축 소스로 보존했고, 설치된 CLI와 실제 측정 당시 source가 다르면 분리 기재했다.

실행에는 명시적인 disposable local sandbox와 로컬 API, 고정 합성 신원을 사용하며 기존 결과 덮어쓰기를 거부한다. worker 통계 cron의 원래 활성 상태를 기록해 측정 중만 정지했다. 기존 observability view/queue 결과와 G04 형식을 사용하고 새로운 경보나 운영 플랫폼을 배포하지 않았다. 실패 후보·초기 준비 실패·계측 오버헤드·부분 자원 수집·null을 삭제하거나 성공 표본으로 바꾸지 않았다.

R05는 최종 release SHA/tree, 이 문서와 원시 자료, high 마이그레이션 20260915033000의 populated upgrade 자료를 소비한다. 이 upgrade는10년2609세션/31308세트,23개 표81673원본,원본/ID 보존·중단/재개·공존 검사를 확인한 별도 실행이며 R05 staging 리허설 자체가 아니다. 해당 부분 인덱스는 그 fixture의RPE8 데이터에서는 비어 있었고, RPE10 선택조건 검사는 별도다. 자료에 기록된 이전 to.ref와 이후 후보의 같은 migration 지문/DDL을 구분한다.

HQ에는 혼합40ms 미충족·10명회복지연 증가·freshness/DOM 동등비교 미입증·미측정을 그대로 전달한다. R05의 리허설·R06의 오너대기/Production 종료 조건을 완화하거나 대신 실행하지 않는다. #1543의 목적 release 통합은 제품의 Production 출시 및 이슈 종결과 구분한다.

Phase 5 검증 완료

최종 앱 09aaa9a4, tree 8883325ee1a671c8c2c8e919fb15bae166fb23e2npm run check는3627pass/0fail/127skip(104.912초), 문서 검사4개 약관/354개 경로·빌드54.79초·산출물31파일 검사가 통과했다. 검사와 자체 cron 복원 증거. 측정용 두 자체 DB의 통계 cron5개씩을 기록한 원래 active=true로 복원하고 실제 값을 확인했다. 다른 담당자의 DB/예약/프로세스는 변경하지 않았다. Phase 5/5 측정·판정·재현 자료 정리 완료, 필수 Precheck와 Merge Check·실제 release 병합은 이어 진행하며 아래에 결과를 추가한다.

필수 Precheck — 첫 실행의 검사 호환성 실패

2026-09-12 01:18~01:26 KST, 09aaa9a4·base d63926b1ci:precheck-local은7분30초에 종료했다. static·unit1832/1795pass(45/82skip)·빈 DB 전체 재생·schema 대조·5개 실제DB묶음과 큰 이력 격리/CRUD/수렴 검사가 통과했다. pgTAP는122파일2444단언 중 stats_isolated_publication_v1의7번만 실패했다(실제0/예상2). 전체 precheck는 실패다.

사전 검증 누락: 비공개 결과 저장을 typed 표로 바꾼 뒤 이 기존 검사는 여전히 run.payload의 옛 observation 배열을 읽었다. 따라서 계산 직후 결과를0개로 셌고, 같은 검사의 실제 게시 후 복합 두 멤버 제외 단언은 통과했다. 기존 계산/공개 정확성 단언을 없애지 않고 현재 run의 job·lease·owner에 묶인 typed 관측에서 같은 두 복합 멤버·eligible=false·training_complex·vote=false를 검사하도록 수정한다. 제품 SQL·기록·정책·예산은 변경하지 않는다. 원 실행의 나머지 실패까지 수집해 이1개만임을 확인했고, 관련44단언 검증 뒤 수정된 clean head에서 필수 precheck를 다시 실행한다. Full CI를 수리 반복에 사용하지 않는다.

최종 Precheck·Merge Check와 release 반영

ci:precheck-local 후보 07714a27 / base d63926b1, 452.377초. static·unit3627pass/0fail/127skip·빈 DB 재생·schema·pgTAP 122파일/2444 assert 통과·실제 DB5묶음/큰 이력 격리·CRUD·수렴 통과. 첫 pgTAP1단언 실패와 관련44단언 수리 통과를 별도 보존. 최종 증거

기존 단언의 저장 위치만 수정한 07714a27ca6b94e53e5089dc8cad1e53233f4ee1, tree c1aa97c20310a0f190b194506a6c0775185d9584의 clean head로 일반 Merge Check를 요청했다. 앱 PR #1579가 2026-09-11T16:39:22Z에 17ce78123bb5297dedf9fbc34f10ea8f62fcf86f로 실제 release/v0.18.0에 반영됐다. 작업→release 검사이며 Full CI가 아니다. 전체 G04 수락·staging/Production 성공·이슈 종결은 주장하지 않는다.

일반 Merge Check 실행은 성공했으며, 원격 release를 fetch해 PR head 포함과 병합 tree가 위 검증 tree와 같은지 확인했다. 측정용 대조 DB는 기록한 cron 활성 상태 복원 후 종료했고, 후보 DB는 마지막 precheck의 자동 정리로 종료됐다. 실제 두 컨테이너의 부재를 확인했다. 다른 담당자의 자원은 변경하지 않았다.

업데이트bug-126-20260911.md, bug-127-20260911.md, bug-128-20260912.md에 수리·위험·미검증을 연결했다. 문서 PR #77과 원시 지문을 R05/HQ 인계의 정본으로 사용한다.