Remove zstd OCI export — concluding the Sprint 165~170 zstd cycle (seed #170-1)
Goal
- Recover Sprint 170 carryover seed #170-1: follow-up decision on the measurement finding that zstd savings are ~0% on warm cache.
- Compare two candidates — (a) introduce
force-compression=true(guarantees zstd savings, build-time trade-off) vs (b) remove the zstd OCI export (clean up the unconsumed + zero-saving redundant step). - Final step of "security gate (165) → visibility (166) → measurement (167) → full adoption (168) → observation (169) → measurement automation (170) → cycle conclusion (171)".
Decisions
D0. Adopted approach — option (b) remove zstd OCI export
Adopt option (b) without a force-compression A/B measurement, because this sprint's codebase grep verification + Sprint 170's empirical data already make the decision conclusive:
- Zero consumer (verified this sprint): The
type=oci,compression=zstd,dest=...-zstd.tarartifact is produced by 3 build jobs and read only by thereport-build-metrics.shmeasurement helper.upload-artifactuploads only the docker tarball (image-<svc>.tar), Trivy scans only--input <docker tarball>, and registry push uses onlytype=image→ the zstd tarball is consumed nowhere. - ~0% saving on warm cache (Sprint 170 measurement): All 8 services show docker tarball ≈ oci+zstd tarball (exactly a 2048-byte container-format overhead difference). Without
force-compression=true, buildx does not recompress cached/base layers, so both exporters embed identical blobs → saving -0.0%. - (a) force-compression is irrational: Spending extra build time to compress an artifact with no consumer yields zero value regardless of compression ratio — only a build-time regression.
→ The A/B measurement is unnecessary as a decision input. Remove the zstd OCI export to conclude the Sprint 165~170 zstd cycle as a redundant-step cleanup.
D1. Rationale for skipping the force-compression A/B measurement
Seed #170-1's original plan was a cold-cache force-compression A/B, but the "zero consumer" discovery fixes the decision independently of any measurement result. An artifact with no consumer has zero value even at maximal compression, so force-compression's build-time cost is pure loss. We converge on (b) logically, with no measurement CI cost.
D2. Helper 2-arg simplification (dead-code removal)
After removing the zstd export, the zstd branch in report-build-metrics.sh and the Sprint 170 ZSTD-METRIC stdout marker become uncalled dead code. Per project convention ("delete if certainly unused, avoid backwards-compat hacks"), remove the 3rd argument + zstd branch + marker block entirely → simplify to a <label> <docker_tarball> 2-arg helper. If zstd measurement is ever needed again, it is restorable from git history.
D3. Remaining outputs = return to the Sprint 165 Option C baseline
After removal, the 3 build jobs' outputs: reduce to type=image (main push) + type=docker (Trivy tarball) — the baseline at the time Sprint 165 Option C was introduced. The Trivy scan job's --input /tmp/image-<svc>.tar path is unchanged → zero security-gate regression.
D4. Unit test case re-ordering
After removing Case 2 (zstd saving %)/Case 7 (ZSTD-METRIC marker), Case 3 (no-zstd branch) is promoted to the canonical docker tarball path (neg assertions: confirm absence of oci+zstd / compression saving lines). Remaining cases 4/5/6 → 3/4/5. 7 cases → 5 cases, 22 → 16 assertions.
Implementation (single PR, 39 consecutive sprints of branch discipline)
Branch: feat/sprint-171-zstd-export-removal → single PR squash merge.
Phase A — code removal (Architect, commit 28dd957)
.github/workflows/ci.yml: Remove thetype=oci,compression=zstd,dest=/tmp/image-*-zstd.tarline from 3 build jobs (build-services/build-frontend/build-blog) + remove the 3rd argument (zstd tarball) from the 3report-build-metrics.shcalls + update Sprint 168 zstd comments to reflect the Sprint 171 decision. python3 yaml.safe_load PASS.scripts/ci/report-build-metrics.sh: Remove the zstd branch block + ZSTD-METRIC stdout marker block +ZSTD_TARBALLargument + usage/header comments → 2-arg helper.bash -nsyntax PASS.tests/ci/report-build-metrics-test.sh: Remove Case 2/7, promote Case 3 (add neg assertions), renumber 4/5/6→3/4/5, update header case list.
Phase B — ADR recording (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 (lines 18/52/54)
Critic cycle
- R1 (codex exec --base bd60329, codex-cli 0.130.0): 0 P0/P1/P2/P3 findings, PASS ✅ — Trivy
--inputdocker tarball path unchanged (969/979) / docker tarballs still produced & uploaded (onlytype=ociremoved) / deploy push path + gate unchanged / 0 live references toZSTD_TARBALL/ZSTD-METRIC/compression=zstd/image-*-zstd/ helper consistently 2-arg + tests renumbered 1-5. Single-pass PASS, no codex hang.
Risk / regression guard
Prediction 1: Trivy security gate unchanged
Trivy does not use the zstd tarball (--input docker tarball), so removal does not affect scanning. The 8-matrix Trivy scan in the PR Checks tab stays SUCCESS as before.
Prediction 2: deploy unchanged
The deploy job depends on type=image push (main only). Removing the zstd OCI export is unrelated to the push path → zero deploy regression.
Prediction 3: helper regression guard
The quality-ci-scripts job runs unit tests on scripts/ci/**/tests/ci/** changes → the 2-arg helper's 5 cases / 16 assertions guard against regressions.
Verification
Local
bash -n scripts/ci/report-build-metrics.sh: syntax PASS- Unit tests (GNU stat shim): 16 assertions PASS (5 cases)
- python3 yaml.safe_load(ci.yml): PASS
- zstd remnant grep: 0 in code (comments only, intentional)
CI
- PR #297 CI: quality-ci-scripts (unit tests) confirmed success → 8 build jobs + 8-matrix Trivy scan expected green
- check-adr-en-coverage --strict: 120/120 (100.0%) PASS
- check-doc-refs: 305 files 0 broken refs PASS
New UAT (Sprint 171)
- Visually confirm the 8-matrix Trivy scan in the PR Checks tab stays SUCCESS after the zstd export removal
Result
- Merge: origin/main
bd60329→<TBD-MERGE-SHA>(PR #297, squash merge) - Net change: -84 +32 (zstd export + dead-code removal dominant)
- Conclusion of the Sprint 165~170 zstd cycle: security tarball (165) → visibility (166) → measurement (167) → zstd adoption (168) → observation (169) → measurement automation (170) → redundant-step removal (171).
New patterns
- Discovering an unconsumed artifact = removal beats compression optimization: After measurement automation (170) exposed ~0% savings, a follow-up grep confirmed "zero consumer" → the answer is removing the artifact, not improving its compression ratio (force-compression). The pattern: first verify whether the optimization target is actually consumed.
- A measurement finding simplifies the decision = A/B can be skipped: The prior sprint's measurement data + this sprint's static verification (grep) make an A/B measurement unnecessary. "If you have the data, skip the extra measurement" — a measurement sprint's output reduces the next sprint's cost.
- A cycle-conclusion ADR = the full stop for a multi-stage seed: The 165~171 7-sprint zstd cycle is concluded in a single ADR. The decision graph of each stage is traceable in one place.