Carry-Over Automation Seeds Cleanup — Trivy/Dependabot/Envelope (Critic Self-Contradiction Detection)

Date
ImpactCritical

Key Decisions

Split into 4 PRs

Phase A/B/C/D each one-PR-one-responsibility — minimize regression risk. No single-PR compression

Close Phase A + defer redesign to Sprint 165

After Critic R1 P1 essential defect detection, immediately close. Avoid compressing essential redesign (build job load: true + multi-arch) into a single sprint. Apply priority (service stability > development speed)

Apply Critic R1 P2 fix immediately (Phase B)

Add equal coverage for blog Dockerfile — resolve the self-contradiction (blog is also CI-built + Trivy-scanned but not covered by dependabot) immediately

Envelope simplification (Phase C)

group has no score regex extraction pattern → always return status="failed" (simplified single envelope, consistency justified)

New PII/secret mock raw token leakage test

Introduce test_group_response_fallback_no_raw_exposure — explicitly verify all string values in envelope never contain raw tokens

Goal

  • Clean up the top 3 carry-over automation seeds (#new1/#new2/#new3) accumulated in Sprint 157~163
  • Seed #new1 — Enable Trivy scan at the PR stage (attempt to land Sprint 160 lesson #6)
  • Seed #new2 — Add 5 docker entries to dependabot.yml (block the Sprint 159 missing base image refresh causal chain)
  • Seed #new3 — Apply envelope to _parse_group_response (recover Sprint 159 single-analysis envelope on the group side)
  • 5 user-facing UAT guides (visual validation of Sprint 161~163 new behaviors)

Decisions

  • Split into 4 PRs: Phase A/B/C/D each one-PR-one-responsibility — minimize regression risk. No single-PR compression
  • Close Phase A + defer redesign to Sprint 165: After Critic R1 P1 essential defect detection, immediately close. Avoid compressing essential redesign (build job load: true + multi-arch) into a single sprint. Apply priority (service stability > development speed)
  • Apply Critic R1 P2 fix immediately (Phase B): Add equal coverage for blog Dockerfile — resolve the self-contradiction (blog is also CI-built + Trivy-scanned but not covered by dependabot) immediately
  • Envelope simplification (Phase C): group has no score regex extraction pattern → always return status="failed" (simplified single envelope, consistency justified)
  • New PII/secret mock raw token leakage test: Introduce test_group_response_fallback_no_raw_exposure — explicitly verify all string values in envelope never contain raw tokens

Implementation (4 PRs, 32 sprints consecutive branch discipline)

PRPhaseBranchResult
#280A — Enable PR Trivychore/sprint-164-pr-trivy-enableClosed (Critic R1 P1 essential defect → Sprint 165 redesign)
#281B — dependabot docker x6chore/sprint-164-dependabot-docker✅ Squash merge b13e6c5
#282C — group envelopefix/sprint-164-ai-analysis-group-envelope✅ Squash merge 12eb347
#TBDD — Sprint 164 ADRdocs/sprint-164-adrThis PR (architect + scribe)

Phase A — PR-stage Trivy scan activation attempt (closed)

  • Change: .github/workflows/ci.yml:781 if: github.ref == 'refs/heads/main' && !cancelled()if: "!cancelled()"
  • Goal: Trivy SARIF upload on both PR + main → 1st-stage PR security regression detection (Sprint 160 lesson #6)
  • Critic R1 P1 detected (codex review --commit 1e2e3c2):

    Avoid scanning registry tags that PR builds never push (ci.yml:784). On pull_request, build jobs still use push: ${{ github.ref == 'refs/heads/main' }}, so they do not publish ghcr.io/...:main-${{ github.sha }}. With this job now running for PRs, any changed service that reaches Trivy will try to pull a tag that was never pushed and fail before producing a useful security result.

  • Essential defect: PR build doesn't push to GHCR → Trivy tries to pull missing tag → fail. This PR produces noisy CI red, not a security gate = sprint goal self-contradiction
  • Decision: Close PR + defer to Sprint 165 redesign (need 3-option comparison: build job load: true + Trivy local image scan, or PR-specific tag push, or buildx artifact + fs scan)
  • Lesson: A seemingly-simple 1-line if change can require essential redesign when interacting with image registry policy

Phase B — dependabot.yml docker x6 additions

  • Change: .github/dependabot.yml docker entries 2 → 8
    • Existing: /services/gateway, /services/ai-analysis
    • New: /services/identity, /services/submission, /services/problem, /services/github-worker, /frontend, /blog
  • Common config: weekly Monday Asia/Seoul, labels ["dependencies", "docker"], commit prefix chore(docker), semver-major ignore
  • Critic R1 P2 detected (codex review --commit cdec0a2, session 019e3f46-4dad-73c0-911f-09066d212f60):

    Include the blog Dockerfile in Docker updates. CI builds and Trivy-scans a blog image from /blog/Dockerfile, but this new Docker coverage still omits /blog. If the blog image's nginx base tag goes stale or vulnerable, the same Trivy failures this change is meant to prevent can still recur for blog.

  • Immediate fix (commit 0f81fb1): Add /blog docker entry — resolve self-contradicting omission against this PR's causal-chain blocking goal
  • Critic R2 PASS ✅ — "No breaking or actionable issues were identified in the change"
  • Merge: squash sha b13e6c5

Phase C — _parse_group_response envelope application

  • Change: services/ai-analysis/src/claude_client.py:476-490 (envelope pattern)
    • Before: fallback = raw_text.strip() + backtick strip + comparison: fallback[:50000] (50KB raw exposure)
    • After: comparison: "AI 그룹 분석 결과 파싱에 일시적 오류가 발생했습니다. 잠시 후 다시 시도해주세요." (zero raw body exposure)
    • logger.warning extra: only raw_length recorded (no raw body)
    • group has no score regex extraction pattern → always status="failed" (simplified single envelope)
  • Tests (services/ai-analysis/tests/test_claude_client.py):
    • 4 existing tests converted to envelope verification: test_parse_group_response_invalid_json + test_parse_group_response_empty_string + test_group_response_fallback_backtick_no_closing + test_group_response_fallback_backtick_with_closing
    • 1 new: test_group_response_fallback_no_raw_exposure — verify with PII/secret mock raw (hunter2 / 123-45-6789 / sk-abc123def456 / user_id=42) that no raw tokens leak into envelope string values
  • Critic R1 PASS ✅ (codex review --commit, session 019e3f4a-92d5-7503-8dd3-e92f5ae18c78): "I did not find a discrete regression introduced by this commit"
  • Verification: pytest 79 PASS, claude_client.py coverage 99% maintained

Phase D — Sprint 164 ADR (this PR)

  • docs/adr/sprints/sprint-164.md (KR) + docs/adr-en/sprints/sprint-164.md (EN, this file, 1:1 mapping)
  • docs/adr/README.md update — count 103 → 104, range 62163 → 62164

Verification

ItemResult
Phase B YAML syntax✅ docker entries 8 (2→8)
Phase B CI29 checks SUCCESS + SKIPPED
Phase B Critic R1 P2 → R2PASS ✅
Phase C pytest79 PASS (5 group included)
Phase C claude_client.py coverage99% maintained
Phase C Critic R1PASS ✅
check-adr-en-coverage --strict113/113 (100.0%) PASS (post Phase D)
check-doc-refs0 broken refs (post Phase D)
Branch discipline✅ 32 sprints consecutive, 0 direct main commits, 0 --no-verify

Branch Discipline ✅ 32 Sprints Consecutive

  • All 4 PRs use new branches + Squash merge (Phase A closed + branch deleted)
  • 0 direct main commits, 0 --no-verify

New Patterns

  1. Critic R1 self-contradiction detection 2× per single sprint (Sprint 155/159/160 pattern reinforced) — Phase A essential defect (image tag missing) + Phase B blog equal coverage omission. Codex cross-validation's sprint consistency-guard effect confirmed 2× in this sprint
  2. PR close + Sprint 165 redesign deferral pattern — Even seemingly-simple 1-line change requires immediate close + separate sprint split when essential redesign is required. Avoid single-sprint compression (continues Sprint 161~163 3-sprint split policy)
  3. Cross-service envelope pattern recovery — Apply Sprint 159 single-analysis envelope to group side. Score regex extraction difference → simplification (group: always status="failed"). Difference justification required when same pattern applied to different functions
  4. PII/secret mock raw token leakage explicit verification — Strengthen envelope pattern's core promise (zero raw body exposure) via unit test. Regression-blocking gate (supplements Sprint 159 envelope's partial verification limitation)
  5. stash + branch switching multi-PR parallel handling — When Phase B Critic R1 P2 fix occurred, stash Phase C work → switch to Phase B → push fix → stash pop Phase C. Safe handling in multi-PR within single session
  6. codex CLI direct call backgrounding — Run codex review --commit <sha> in background and proceed with next Phase in parallel. Hide Critic cycle processing time