PR deploy gate simulation + forward-fix PR template (seeds #new4/#new5)
Goal
- Recover 2 carryover CI-visibility seeds from Sprint 164.
- #new4 — simulate the deploy gate at the PR stage for shift-left visibility: surface which services WOULD deploy / which would SKIP in PR Checks before the main merge.
- #new5 — auto-generate a forward-fix PR body template in the deploy summary that the operator can paste immediately when an aether-gitops push fails.
- Seed #new7 (
_parse_group_responseenvelope extension) carries a security-regression risk of touching Sprint 164 #new3's raw-exposure-blocking fix, so it is separated from this sprint's scope → carried over to Sprint 174.
Decisions
D0. Extract the deploy gate fail-closed decision logic into a pure helper
Extract the deploy gate fail-closed decision logic into a scripts/ci/compute-deploy-gate.sh pure helper → the deploy job (main-only) and the new deploy-simulation job (PR) share the same SSOT. Rationale: duplicating the same gate in two places risks a divergence between the PR simulation prediction and the actual deploy → a single helper guarantees consistency. Follows the existing helper-extraction pattern (Sprint 168 report-build-metrics.sh).
D1. Candidate list (CANDIDATES) computation stays out of the helper
The candidate list computation depends on the GitHub Actions context (detect-changes outputs + build job result), so it stays out of the helper — the caller (ci.yml) computes it and passes it as an argument. The helper handles only the trivy-status gate decision (single responsibility).
D2. Preserve fail-closed
Each candidate's trivy-status/<svc>.txt yields UPDATED only when it is exactly "pass"; everything else (fail/missing/look-alike values) yields SKIPPED. This is the core property of the Sprint 159 regression + Critic R1 P1 security gate — preserved identically after the helper extraction.
D3. Rationale for the PR simulation being feasible
The trivy-scan job also runs on PRs (Sprint 165 Option C, if: !cancelled()) and uploads the trivy-status-<svc> artifact on PRs too → at PR time, all simulation inputs (detect-changes / build result / artifact) exist. The simulation job is dry-run (no clone / yaml edit / push) → it only writes a Step Summary.
D4. The #new5 forward-fix template prints only on the push-failure branch
#new5 prints only on the push-failure branch of the deploy job's "Surface deploy summary" — it generates a forward-fix PR body for the operator to paste (target image tag + kustomization overlays/prod path + failing CI run link) as a <details> collapsible block + markdown code fence. The happy-path behavior is unchanged.
D5. Reuse the detect-changes filter
The new helper/tests are already covered by detect-changes' ci-scripts filter (scripts/ci/** + tests/ci/** globs) → no per-file filter addition needed. Only add a test-execution step to the quality-ci-scripts job.
Implementation (single PR, branch feat/sprint-173-deploy-gate-visibility)
Phase A — helper extraction + unit tests (Architect, commit f7cda47)
feat(ci): compute-deploy-gate.sh 헬퍼 추출 + 단위 테스트 (Sprint 173 #신규4)
scripts/ci/compute-deploy-gate.shnew (58 lines, fail-closed pure helper, header annotation)tests/ci/compute-deploy-gate-test.shnew (pure bash, 7 cases / 19 assertions)
Phase B — ci.yml wiring + simulation job + forward-fix (Architect, commit 3379f4d)
feat(ci): deploy 게이트 헬퍼 연동 + PR 시뮬 job + forward-fix 템플릿 (Sprint 173 #신규4/#신규5)
- Add a test-execution step to the
quality-ci-scriptsjob - Refactor the deploy job's
update_tagsgate loop to a helper call + add a helper sparse-checkout step (the deploy job does not full-checkout the AlgoSu repo, only clones aether-gitops) - New deploy-simulation job (PR-only
if: github.event_name == 'pull_request' && !cancelled(), trivy-status-* download continue-on-error, helper dry-run → STEP_SUMMARY) - Add the #new5 forward-fix block
Phase C — ADR recording (Scribe, this commit)
docs/adr/sprints/sprint-173.md(KR) +docs/adr-en/sprints/sprint-173.md(EN 1:1)docs/adr/README.mdcount 111→112, range 62171→62173
Critic cycle
- R1 (
codex review --base main, codex-cli 0.130.0, session ID019e43cf-5c4e-7153-9dcc-1df410f5d5e9): 0 P0/P1/P2/P3 findings, PASS ✅ — "no functional regression, no merge-blocking bug". Confirmed deploy gate behavior unchanged + fail-closed preserved.
Risk / regression guard
Prediction 1: deploy behavior unchanged
STATUS_DIR definition / CANDIDATES computation / python yaml tag edit / GITHUB_OUTPUT recording are all preserved. The helper is invoked by absolute path ($GITHUB_WORKSPACE/scripts/ci/...), so it works even after cd aether-gitops/.... The helper output may leave a leading space, but downstream normalizes it via xargs anyway → behavior identical.
Prediction 2: simulation job has no production impact
The simulation job is PR-only + dry-run → no production impact. A docs-only PR (0 artifacts) does not turn the job red either, thanks to continue-on-error + a defensive mkdir.
Prediction 3: helper regression guard
quality-ci-scripts runs the 19 assertions on scripts/ci/** or tests/ci/** changes → guards against helper regressions.
Verification
Local
bash tests/ci/compute-deploy-gate-test.sh: 19/19 PASS (macOS, no docker / GNU stat dependency)python3 yaml.safe_load(ci.yml): PASS- shellcheck (helper + tests): CLEAN
- diff secret scan: 0 sensitive patterns
- fail-closed edges: missing→skip, look-alike (passed/PASS)→skip verified via unit tests
CI (expected)
- On PR CI,
quality-ci-scripts(19 assertions) success → the deploy-simulation job writes "Deploy preview" to the PR Step Summary check-adr-en-coverage --strict/check-doc-refsexpected PASS
New UAT (Sprint 173)
- On a real PR, visually confirm the deploy-simulation job's Step Summary shows the WOULD deploy / SKIP list accurately as "🔮 Deploy preview"
Result
- Merge: origin/main
0739913→<TBD-MERGE-SHA>(PR #, squash merge) - Net change: +304 -16 (new helper + tests + ci.yml, 3 files)
New patterns
- Gate-logic SSOT extraction → guaranteed main/PR consistency: unifying the deploy decision rule into a helper makes "what you saw predicted in the PR" structurally identical to "the actual main deploy". The trustworthiness of shift-left visibility comes from sharing the same code.
- Accompany a security-gate extraction with fail-closed unit tests: extraction carries a regression risk → lock down exact-match / missing / look-alike rejection with tests to preserve the security property after extraction.