diff --git a/.convoys/add-rate-limiting.md b/.convoys/add-rate-limiting.md index 24ccb66..85e4ee5 100644 --- a/.convoys/add-rate-limiting.md +++ b/.convoys/add-rate-limiting.md @@ -14,8 +14,9 @@ skip: - role-a11y-auditor - role-ux-reviewer - role-ia-architect -status: in-progress +status: shipped created: 2026-05-24 +shipped: 2026-05-24 parent: ship-readiness addresses: P0 #6 (PARTIAL → RESOLVED) — the LAST open P0 depends_on: @@ -674,3 +675,361 @@ slice_dependencies: One brief, no `/multitask` fan-out — the conductor dispatches a single implementer. + +## As-shipped + +Shipped 2026-05-24 as squash commit `708ef45` (PR #20, architect-commit +`60b842e`, implementer-commit `51a3a97`). **This is the milestone +convoy — it closes the LAST open P0 (P0 #6) and flips +`.convoys/ship-readiness.md`'s § Status summary from "7 of 8 RESOLVED; +1 remains" to "8 of 8 RESOLVED. Launch-readiness P0 checklist is +empty."** Brief 1 shipped as planned — single lib refactor + six +route-gate additions + one admin UI atomic fix + one rule extension, +no scope expansions beyond the architect-ratified Decision 1, and the +empirical CI metrics + the cross-validation finding + the +"D3 tuning-evidence" rationale captured here so the next architect / +reviewer has the audit trail. + +### Decisions ratified at gate 1 + +All six decisions landed verbatim. Only D1 required operator gate-1 +sign-off (significant scope expansion to admin-only enforcement on the +import surface plus an atomic admin UI touch); D2-D6 are +architect-self-ratifiable per the precedent established by +`cors-tighten` Decisions D2-D5 and +`fix-vercel-deployment-protection-in-ci` Decisions A/B/D. + +- **Decision 1 — Option A (operator-ratified).** Gate all three + `pages/api/cards/import-*.js` routes in this convoy with + `getUserFromRequest` + `if (user.role !== 'admin') return 403` + + `checkImportRateLimit(req, user.userId)`. **And** atomically update + `pages/admin/card-import.js` to send + `'Authorization': \`Bearer ${localStorage.getItem('auth_token')}\`` + on its import fetch — without this, the API gating would have + immediately broken every "Import Cards" click in the admin UI. The + architect's pre-brief investigation flagged this as the critical + hidden coupling: gating the import APIs without the matching client + fetch fix would have closed P0 #6 but introduced a visible UX + regression on the only live admin tooling that depends on it. Lorcana + was gated defensively despite having zero current frontend callers + (`pages/admin/card-import.js`'s `` permanently. Surfaced 2026-05-24 in `add-rate-limiting` Decision 1: the architect ran `rg 'import-lorcana' pages/ components/` and found zero frontend callers — `pages/admin/card-import.js`'s `