GitHub Full CI 실행과 시간 측정
2026-09-15 개정(오너 지시, #1661·#1659) — 승격 검사 3단계 — ① 작업 PR→release는 큐 Merge Check만(PR 전 precheck 폐기) ② release→staging은 GitHub Full CI precheck 레인(
static-checks+migration-smoke) ③ staging→main은 QA2 레인(qa2-product-contracts)만. QA1은 완전히 퇴역(어느 워크플로도 실행하지 않음). 아래 2026-09-10 배너와 본문의 precheck·full CI·재사용 서술은 그 개정 전 기록이다. 정본 = 릴리스 프로세스.
2026-09-11 사용자 결정: Full CI 실패 하나를 고칠 때마다 전체를 반복 실행하지 않는다. 모든 실패를 수집하고 로컬에서 해당 검사 묶음을 수리·검증한 뒤 필요한 원격 검증을 실행한다. 승격 PR head 갱신에 따른 자동 실행도 포함하며, 실패 수리·재실행 절차를 따른다. 이 절차 추가는 자동 차단 기능의 구현이 아니다.
2026-09-10 승인 정책 (#1491, v0.17.8 대상): 작업 세션은
ci:precheck-local, 작업→release 큐는 Merge Check만 수행한다. 최종 release→staging 후보에서 full CI를 실행하고, staging→main은 동일 tree의 유효한 full 성공 기록과 현재 staging 배포·smoke 증거를 확인해 재사용한다. 명시적merge:request --dry-run은 진단용 full 실행을 유지한다. 앱 main6afe58ec에 설치됐으며 정상 큐의 실제 실행 시간과 운영 배포 성공은 아직 확인 전이다. 상세 상태는 적용 기록에서 구분한다. 아래 과거 전환 기록보다 이 절차가 우선한다.
저장소 분리 적용 범위 (#1463): 이 문서의 실행 코드·DB·앱 release 절차는
dekerd/Barbelic에 적용한다. 문서·관리자·랜딩은 각각의 독립 저장소 절차를 따른다. 과거 docs/admin 결합·앱 main 문서 직행 설명은 분리 전 이력이며 저장소 경계와 독립 운영·실제 전환 상태가 그 부분을 대체한다.
2026-09-09 개정 (이슈 #1456·#1457·#1458, 오너 결정) — 명령·워크플로 이름이 바뀌었다. 작업 PR 통합 요청
npm run merge:request(구 landing:request), PR 전 사전 검증npm run ci:precheck-local(최신 release 합치기 → verify → 서버 변경 시 DB 단계, 브라우저 없음), 전체 검증npm run ci:full-local(릴리스 큐 runner 안에서만; 세션은--only <단계>재현만). 워크플로 표시 이름:3-Release Merge Request(release-merge-request.yml) ·GitHub Full CI(policy-contract.yml) ·1-Production Deploy/2-Staging Deploy(production-deploy.yml·staging-deploy.yml, 단계 정의는 deploy-steps.yml) ·Production smoke (manual)·Social login daily check·Daily data backup.landing:lock·db:preflight스크립트는 폐기됐다(GitHub concurrency 가 잠금, DB 검사는 사전 검증과 큐가 한다). 아래 본문의 옛 이름은 그 개정 전 기록이다.
순수 문서 예외: 최신 main 기준의 문서만 담은 PR은 main에 직접 병합할 수 있으며, 오너 요청 시 로컬·GitHub CI를 생략한다. 적용 범위와 [skip ci]·필수 검사 처리는 릴리스 프로세스의 문서 예외를 따른다. 제품 변경과 두 승격 PR은 아래 기준을 유지한다.
실행 시점의 정본은 릴리스 프로세스다. 작업은 precheck, 일반 작업→release 큐는 Merge Check, release→staging 최종 후보는 hosted full CI, staging→main은 동일 tree의 유효한 full 기록과 현재 staging 배포·smoke 증거 확인이 기준이다. staging/main 병합 push는 환경별 배포·smoke를 수행하며 full을 중복 실행하지 않는다.
release별 큐는 최신 후보 확인부터 병합까지 순차 처리한다. 일반 요청은 full 실행·full 기록 조회/발급을 하지 않는다. 명시적 --dry-run만 진단용 full을 실행하고 병합하지 않는다. 추가 사전검증 장부나 승인 게이트·전역 락을 만들지 않는다. 실제 full 경로는 정적·단위 2샤드·DB·브라우저·viewport를 병렬 실행하고 verify가 결과를 확인한다. 재사용 경로의 verify는 scope·재사용 근거·의도된 full 잡 skip을 확인한다.
flowchart LR
scope[변경 범위 판정] --> verify[verify: full 성공 또는 유효한 재사용 확인]
static[정적 검사 · unused · build] --> verify
unit[단위 테스트 2샤드] --> verify
scope --> full{full 필요}
full --> db[빈 DB replay · snapshot · pgTAP · CRUD]
full --> browser[브라우저 4샤드 · 각자 독립 DB]
full --> viewport[뷰포트 · 독립 DB]verify는 full 경로에서 scope·정적·단위·DB·브라우저·viewport·완료 증거의 필수 결과가 모두 성공해야 통과한다. 재사용 경로에서는 scope 성공·유효한 tree와 원 full 링크·예상한 full 잡 skip을 요구한다. 각 matrix의 fail-fast: false와 수동 실행의 별도 manual-* 이름을 유지한다. 수동 실행은 PR의 필수 판정을 대신하지 않는다.
변경 범위
- PR 자체 변경은 merge-base부터 PR head까지 구한다. base branch에만 추가된 변경을 PR 변경으로 오인하지 않는다.
- 실제 테스트하는 merge commit과 base의 차이도 함께 확인해 통합 변경을 포함한다. merge commit이 base와 head를 모두 포함하지 않으면 분류가 실패한다.
- 파일 이동은 삭제와 추가로 분류하고 경로는 NUL로 구분해 삭제·한글·공백·개행이 들어간 경로도 보존한다.
- 알려진
.github/pull_request_template.md,PULL_REQUEST_TEMPLATE/*.md,ISSUE_TEMPLATE/*.{md,yml,yaml}만 문서로 분류한다..github의 다른 경로, DB, E2E, dependency, Playwright, CI 실행 설정은 full이다. full-ci라벨과 수동full_ci=true는 full을 강제한다. 관계없는 라벨은 실행 중인 검사를 취소하지 않는다.- release→staging은 변경 경로와 무관하게 full을 실행한다. staging→main만 유효한 동일 tree 기록과 현재 staging 배포·smoke 증거로 재사용한다. 일반 작업 PR·main/staging push에서는 hosted full을 중복 실행하지 않는다.
대기와 로컬 검증
release PR은 npm run merge:request -- --pr <N>으로 요청하고 그 Actions 실행을 확인한다. 같은 release의 요청은 최신 base 조회부터 병합 확인까지 대기열에서 직렬 처리하며, 파일 landing:lock·heartbeat·ci:wait의 hosted CI 발화를 사용하지 않는다. --dry-run도 슬롯 안에서 full CI를 실행하고 병합만 하지 않는다. 큐는 마지막 head/base·tree 확인과 예상 base 조건부 push로 검증 도중의 변경을 거부한다.
아래 ci:wait 설명은 기존 main 등 hosted 검사 경로에 한정된다.
npm run ci:wait -- --pr <번호>는 완료를 기본 30초마다 조회하고, 상세 진행 상태와 --landing-heartbeat 생존 신호는 5분마다 보낸다. 기존 CI_WAIT_TICK_SECONDS는 조회 간격만 조절한다. 런 미생성 시 수동 발화와 추가 유예, 총 35분 상한은 별도 유지한다.
라벨 이벤트 등으로 workflow 전체가 skipped인 실행은 검증 후보에서 제외한다. 최신 skipped 실행이 진행 중인 실제 검사를 성공으로 덮을 수 없다. 필요한 검사에 성공하고 불필요한 job만 skip한 정상 verify-only 실행은 전체 결론이 success이므로 유효하다.
npm run ci:local은 같은 검사 목록을 로컬에서 순서대로 실행한다. --verify-only 실행은 DB·브라우저 검증 통과로 해석하지 않는다. CI의 각 browser shard는 파일 단위로 분산하고 workers: 1 및 각 사례의 serial 설정을 유지한다.
동일 커밋의 2/4분할 비교
GitHub Full CI 수동 실행의 full_ci=true, browser_shards=2 또는 4로 비교한다. PR 실행은 항상 4샤드다. 같은 head, 도구 버전, 테스트 집합으로 비교하고 결과에는 다음을 함께 적는다.
- 최초 생성부터 종료까지의 시간, 시작 대기, job/step 실행 시간.
- browser shard별 테스트 수와 최대 시간, 모든 job의 누적 runner 시간.
- 실패·flaky 여부, run attempt 번호. 재실행 전후를 한 번의 실행 시간으로 섞지 않는다.
- 캐시 hit/miss 및 CPU/runner 변동. 한 번의 비교는 관측값이며 보장 시간이나 장기 중앙값이 아니다.
4샤드는 브라우저 대기 시간을 줄이는 대신 독립 DB 준비를 두 번 더 수행한다. 이미 캐시된 npm 패키지·Chromium과 작은 앱 빌드를 추가 최적화하기 전에 위 측정으로 비용과 시간을 함께 비교한다. 빈 DB reset은 migration replay/snapshot 계약이므로 속도를 이유로 삭제하지 않는다.