Recommendation Loading Recovery + Platform Toggle Scoping — Deployment Gap Diagnosis and platform Filter
SummaryThe Sprint 254 recommendation feature showed a 'cannot load recommendations' symptom in production. Diagnosis found it was not a code bug but a deployment gap — after PR #479 merged, only the `Trivy Scan — problem` job failed on main CI, so the service-scoped fail-closed gate skipped the GitOps tag update for problem-service, pinning the deployed image to an old version (`ee4d4fe`) that lacked the `/recommendations` route. PR #481 `c889092` resolved the transitive CVEs (brace-expansion, js-yaml) via overrides → unblocked the gate → redeploy restored the route. Then feature improvement PR #482 `e14e8c6` scoped recommendations to the problem-add modal's platform toggle (BOJ/Programmers) so only the selected platform's problems appear (BE `platform` parameter for cross-study DB filter + Tier3 seed filter, new BOJ cold-start seeds, FE hook refetch on tab switch). Critic (Codex gpt-5.5, foreground) resolved a P2 tab-switch race with an epoch pattern (`86b041d`).
Date: 2026-07-22
Goal
Recover the recommendation feature added in Sprint 254 after a report that recommendations could not be loaded in production. Then improve the previously platform-mixed recommendation exposure by scoping it to the problem-add modal's platform toggle (BOJ/Programmers) so only the selected platform's problems are suggested.
Background / Constraints: Reproduced against the actual deployment URL (https://algo-su.com). The source-code path (FE hook → gateway → controller route priority → service Tier3 seed fallback) had no defect under static analysis → hypothesis set the cause as a runtime/deployment gap rather than code.
Decisions
D1. Root cause = deployment gap (not a code bug)
Confirmed with physical evidence from CI logs. After PR #479 (4b60583) merged, only the Trivy Scan — problem job failed on main CI, and the deploy job's service-scoped fail-closed gate skipped the GitOps image-tag update for the Trivy-failed service (log: ⚠ algosu-problem SKIPPED (Trivy status: fail — service-scoped security gate)). As a result, the deployed problem-service stayed pinned to the old ee4d4fe (Sprint 251) → the /recommendations route was absent → the new FE called a nonexistent route and failed. The frontend deployed normally, producing a new/old mismatch.
- The
main-4b60583problem image built and pushed to GHCR successfully (only the tag update was skipped) — the image itself exists.
D2. Recovery = unblock the gate by resolving transitive CVEs (Option A)
The Trivy failure cause was two newly-published transitive-dependency HIGH CVEs in problem-service (feature-unrelated drift):
brace-expansion→ CVE-2026-13149 (DoS)js-yaml→ CVE-2026-59869 (DoS)
Instead of a temporary .trivyignore entry (Option B, fast but defers the DoS), we adopted pinning patched versions via services/problem/package.json overrides (Option A, real security fix + unblock at once) — service-stability-first. Same pattern as the existing multer·tmp·ajv overrides:
brace-expansion@>=3.0.0 <=5.0.6→5.0.7,brace-expansion@<=1.1.15→1.1.16js-yaml@>=4.0.0 <=4.2.0→4.3.0,js-yaml@<=3.14.2→3.15.0
PR #481 c889092 merged → CI green → Trivy problem passed → GitOps tag updated → problem-service redeployed → recommendation route restored.
D3. Scope recommendations to the platform toggle (feature improvement)
The problem-add modal has a platform toggle, but recommendations ignored it and mixed all platforms. Scope recommendations to the toggle so only the selected platform is suggested:
- BE: Add a
platformparameter toRecommendQueryDto→ controller → delegate torecommendForStudy. Apply a conditionalsourcePlatformfilter in the DBwhereof the cross-study candidate query (findRecommendationCandidates), and filter the Tier3 seed fallback by platform too. When unspecified, expose all (backward compatible). - Cold start: Add a BOJ representative-problem seed set (
recommendation-seeds.ts). Do not assert precise solved.ac tiers — uselevel=null, difficulty macro-category only. - FE: The
use-problem-recommendationhook takes aplatformoption and refetches on tab switch (resetting exposure history).SearchStepinjects the current tab's platform.
PR #482 e14e8c6 merged.
D4. Critic gate = foreground blocking execution (avoiding ACP reap)
The background PTY-wrapper approach was reaped twice in a row in this ACP environment (SIGKILL without a verdict, no .done marker created). Rather than a third identical retry, switched to foreground blocking execution (macOS script PTY emulation, base c889092, -c model="gpt-5.5" pin) → completed without a reap. Verdict: 1 P2 (a race where, if a tab switch occurs while a previous platform query is in-flight, the loadingRef guard drops the refetch so the stale-platform response overwrites the screen). Resolved with an epoch-ref-based stale-discard pattern + a regression test (86b041d).
Completed Items
- PR #481
c889092— problem-service Trivy HIGH CVE override resolution (completed first by a parallel Oracle session). Unblocked the deployment gap. - PR #482
e14e8c6— recommendation platform-toggle scoping- BE(
services/problem):RecommendQueryDto.platform+ controller delegation +recommendForStudyplatform filter +findRecommendationCandidatesconditionalsourcePlatformwhere + new BOJ seeds inrecommendation-seeds.ts - FE:
use-problem-recommendation.ts(platform option + refetch on tab switch + epoch stale discard),SearchStep.tsxcurrent-tab platform injection
- BE(
Verification (Oracle direct re-check — distrust self-reports): problem BE tsc (feature clean)·ESLint 0·jest 252 pass. FE tsc 0·ESLint 0·jest 98 pass, recommendation hook 14/14 (including the new race regression test).
Critic (Codex gpt-5.5, base c889092, foreground): 1 P2 → resolved with the epoch pattern (86b041d). Re-check closed on green local gates.
Incidents
- Deployment-gap misdiagnosis risk: "the code is fine but recommendations don't show" was easy to misread as a code defect from static analysis alone. Reproducing against the live deployment URL + tracing CI-log physical evidence (per-job results, GitOps tags) pinned down the problem-service old-version freeze.
- Critic ACP reap twice in a row: the background PTY wrapper lost the verdict to SIGKILL at session boundaries repeatedly (isomorphic to Sprint 254). Solved with foreground blocking execution.
- Parallel Oracle session first (recovery part): just before starting Option A, a parallel session had already completed and merged the same overrides / PR #481 → switched from rebuild to CI/redeploy verification.