zstd OCI export 제거 — Sprint 165~170 zstd 사이클 종결 (시드 #170-1)
요약Sprint 170 이월 시드 #170-1 회수: warm cache 에서 zstd 절감 ~0% 라는 측정 발견의 후속 결정.
목표
- Sprint 170 이월 시드 #170-1 회수: warm cache 에서 zstd 절감 ~0% 라는 측정 발견의 후속 결정.
- 두 후보 비교 — (a)
force-compression=true도입(zstd 절감 보장, 빌드 시간 trade-off) vs (b) zstd OCI export 제거(미소비+무절감 잉여 step 정리). - "보안 게이트(165) → 가시성(166) → 실측(167) → 전면 채택(168) → 관측 정착(169) → 측정 자동화(170) → 사이클 종결(171)" 의 마지막 단계.
결정
D0. 채택 방식 — 옵션 (b) zstd OCI export 제거
force-compression A/B 측정 없이 옵션 (b) 를 채택. 근거는 본 sprint 의 코드베이스 grep 검증 + Sprint 170 실측 데이터로 이미 결정적이기 때문:
- 소비처 zero (본 sprint 검증):
type=oci,compression=zstd,dest=...-zstd.tar산출물은 3 build job 에서 생성되어report-build-metrics.sh측정 헬퍼만 읽음.upload-artifact는 docker tarball(image-<svc>.tar) 만 업로드하고, Trivy 는--input <docker tarball>만 스캔하며, 레지스트리 푸시는type=image만 사용 → zstd tarball 은 어디서도 소비되지 않음. - warm cache ~0% 절감 (Sprint 170 실측): 8 서비스 모두 docker tarball ≈ oci+zstd tarball (정확히 2048 bytes 컨테이너 포맷 오버헤드 차이). buildx 는
force-compression=true부재 시 캐시/베이스 layer 를 재압축하지 않으므로 두 exporter 가 동일 blob 을 임베드 → saving -0.0%. - (a) force-compression 은 비합리: 소비처가 없는 산출물을 추가 빌드 시간 들여 압축하면 압축률이 아무리 좋아도 가치 zero + 빌드 시간 회귀만 발생.
→ A/B 측정은 결정 입력으로서 불필요. zstd OCI export 를 제거하여 Sprint 165~170 zstd 사이클을 잉여 step 정리로 종결.
D1. force-compression A/B 측정 생략 근거
시드 #170-1 의 원래 계획은 cold-cache 에서 force-compression A/B 실측이었으나, "소비처 zero" 발견이 측정 결과와 무관하게 결정을 확정. 소비자가 없는 산출물은 최대 압축을 적용해도 가치가 0 이므로, force-compression 의 빌드 시간 비용만 순손실. 측정 CI 비용 없이 논리적으로 (b) 로 수렴.
D2. 헬퍼 2-arg 단순화 (dead code 제거)
zstd export 제거 후 report-build-metrics.sh 의 zstd 분기와 Sprint 170 ZSTD-METRIC stdout 마커는 호출되지 않는 dead code 가 됨. 프로젝트 규약("확실히 미사용이면 완전 삭제, backwards-compat hack 회피")에 따라 3번째 인자 + zstd 분기 + 마커 블록을 전면 제거 → <label> <docker_tarball> 2-arg 헬퍼로 단순화. 향후 zstd 측정이 필요하면 git history 에서 복원 가능.
D3. 잔존 출력 = Sprint 165 옵션 C baseline 복귀
제거 후 3 build job 의 outputs: 는 type=image(main 푸시) + type=docker(Trivy tarball) 2줄로 환원 — Sprint 165 옵션 C 도입 시점의 baseline. Trivy scan job 의 --input /tmp/image-<svc>.tar 경로는 무변경 → 보안 게이트 회귀 zero.
D4. 단위 테스트 케이스 재정렬
Case 2(zstd saving %)/Case 7(ZSTD-METRIC 마커) 제거 후, Case 3(zstd 미전달 분기) 이 docker tarball 정규 경로로 승격(neg assertion: oci+zstd/compression saving 라인 부재 확인). 나머지 케이스 4/5/6 → 3/4/5 재번호. 7 케이스 → 5 케이스, 22 → 16 assertion.
구현 (단일 PR, 39 스프린트 연속 브랜치 규율 준수)
브랜치: feat/sprint-171-zstd-export-removal → 단일 PR Squash merge.
Phase A — 코드 제거 (Architect, commit 28dd957)
.github/workflows/ci.yml: 3 build job(build-services/build-frontend/build-blog) 의type=oci,compression=zstd,dest=/tmp/image-*-zstd.tar줄 제거 +report-build-metrics.sh호출 3건의 3번째 인자(zstd tarball) 제거 + Sprint 168 zstd 주석을 Sprint 171 결정 반영으로 갱신. python3 yaml.safe_load PASS.scripts/ci/report-build-metrics.sh: zstd 분기 블록 + ZSTD-METRIC stdout 마커 블록 +ZSTD_TARBALL인자 + usage/헤더 주석 제거 → 2-arg 헬퍼.bash -nsyntax PASS.tests/ci/report-build-metrics-test.sh: Case 2/7 제거, Case 3 승격(neg assertion 추가), 4/5/6→3/4/5 재번호, 헤더 케이스 목록 갱신.
Phase B — ADR 기록 (Scribe, commit 6026e22)
docs/adr/sprints/sprint-171.md(KR) +docs/adr-en/sprints/sprint-171.md(EN 1:1)docs/adr/README.mdcount 110→111, range 62170→62171 (라인 18/52/54)
Critic 사이클
- R1 (codex exec --base bd60329, codex-cli 0.130.0): P0/P1/P2/P3 0건 PASS ✅ — Trivy
--inputdocker tarball 경로 무변경(969/979) / docker tarball 생성·업로드 유지(type=oci만 제거) / deploy push 경로+gate 무변경 /ZSTD_TARBALL·ZSTD-METRIC·compression=zstd·image-*-zstdlive 참조 0건 / 헬퍼 2-arg 일관 + 테스트 1-5 재정렬 정합. codex hang 없음 단일 회전 PASS.
위험/회귀 차단
예측 1: Trivy 보안 게이트 무변경
zstd tarball 은 Trivy 가 사용하지 않으므로(--input docker tarball) 제거가 스캔에 영향 없음. PR Checks 탭의 8 matrix Trivy scan 이 종전과 동일 SUCCESS.
예측 2: 배포 무변경
deploy job 은 type=image push(main only) 에 의존. zstd OCI export 제거는 push 경로와 무관 → 배포 회귀 zero.
예측 3: 헬퍼 회귀 차단
quality-ci-scripts job 이 scripts/ci/**/tests/ci/** 변경 시 단위 테스트 실행 → 2-arg 헬퍼의 5 케이스 16 assertion 으로 회귀 차단.
검증
로컬
bash -n scripts/ci/report-build-metrics.sh: syntax PASS- 단위 테스트(GNU stat shim): 16 assertion PASS (5 케이스)
- python3 yaml.safe_load(ci.yml): PASS
- zstd 잔재 grep: 코드 0건 (주석만 잔존, 의도적)
CI
- PR #297 CI: quality-ci-scripts(단위 테스트) success 확인 → 8 build job + 8 matrix Trivy scan green 예상
- check-adr-en-coverage --strict: 120/120 (100.0%) PASS
- check-doc-refs: 305 files 0 broken refs PASS
UAT 신규 (Sprint 171)
- PR Checks 탭 8 matrix Trivy scan 이 zstd export 제거 후에도 동일 SUCCESS 인지 시각 확인
결과
- 머지: origin/main
bd60329→<TBD-MERGE-SHA>(PR #297, squash merge) - 순변경: -84 +32 (zstd export + dead code 제거 우세)
- Sprint 165~170 zstd 사이클 종결: 보안 tarball(165) → 가시성(166) → 실측(167) → zstd 채택(168) → 관측(169) → 측정 자동화(170) → 잉여 step 제거(171).
신규 패턴
- 미소비 산출물 발견 = 압축 최적화보다 제거 우선: 측정 자동화(170)가 절감 ~0% 를 노출한 후, 후속 grep 이 "소비처 zero" 를 확인 → 압축률 개선(force-compression)이 아니라 산출물 제거가 정답. 최적화 대상이 실제로 소비되는지 먼저 검증하는 패턴.
- 측정 발견이 결정을 단순화 = A/B 생략 가능: prior sprint 의 측정 데이터 + 본 sprint 의 정적 검증(grep) 조합이 A/B 측정을 불필요하게 만듦. "데이터 있으면 추가 측정 생략" — 측정 sprint 의 산출이 후속 sprint 의 비용을 절감.
- 사이클 종결 ADR = 다단계 시드의 마침표: 165~171 7-sprint zstd 사이클을 단일 ADR 로 종결 명문화. 각 단계의 결정 그래프를 한 곳에서 추적 가능.