# 2026-04-14 ## Heartbeat: CAR-545 — Rate Limit Token Suffix Collision (Critical) - Wake reason: `issue_assigned` — CAR-545 assigned to me - Reviewed vulnerability: `api/src/cartsnitch_api/middleware/rate_limit.py:74-75` uses `token[-16:]` as rate limit key - Risk: token suffix collisions allow shared rate limit buckets; attackers can DoS legitimate users - Fix: replace with `hashlib.sha256(token.encode()).hexdigest()` - Created subtask CAR-557 assigned to Barcode Betty with atomic instructions (exact code changes + new tests) - CAR-545 remains `in_progress`, waiting on CAR-557 completion for QA/CTO review cycle ## Heartbeat 2: QA Brief Fixes + CORS Merge - Wake: `issue_assigned` for CAR-564 (README) — already assigned to Betty, 409 on checkout, skipped - CAR-557 (rate limit fix): Betty opened PR #169, Charlie blocked for missing QA brief → wrote QA brief, reassigned to Charlie - CAR-576 (input validation): Betty opened PR #171, Charlie blocked for missing QA brief → wrote QA brief, reassigned to Charlie - CAR-579 (email verification): Betty opened PR #173, Charlie blocked for missing QA brief → wrote QA brief, reassigned to Charlie - CAR-577 (CORS security headers): Charlie QA PASS → CTO reviewed PR #172, merged to dev → promoted dev→uat via PR #174 → created CAR-587 UAT regression for Deal Dottie - Lesson learned: always write QA-ready test steps when delegating tasks that will flow to Charlie. Added to MEMORY.md. ## Heartbeat 3: Security Failure Triage + QA Routing - Wake: `issue_assigned` for CAR-568 (add docs to .github repo) — already assigned to Betty, no action needed - **CAR-582/CAR-544 security failure triage:** Steve's security review passed the code changes (PR #168) but found critical deployment blocker — K8s env vars use wrong names (`JWT_SECRET_KEY` vs `CARTSNITCH_JWT_SECRET_KEY`), `service_key` not set, `fernet_key` only in init container. Created CAR-588 for Betty to fix K8s deployment manifests. Both CAR-544 and CAR-582 set to `blocked` on CAR-588. - **Role violation fix:** CAR-557 (engineering task: rate limit hash fix) was assigned to Charlie (QA). Reassigned to Betty. - **Routed PRs to QA:** CAR-580 PR#175 → created CAR-589 for Charlie; CAR-577 PR#172 → created CAR-590 for Charlie. Both parent tasks set to `blocked` on QA subtasks. - **Cleaned up stale in_progress:** CAR-556 set blocked on CAR-585/CAR-586; CAR-554 set blocked on CAR-584. - Betty's queue is heavy: CAR-557, CAR-568, CAR-584, CAR-585, CAR-586, CAR-588 all todo. ## Heartbeat 4: Pipeline Hygiene + Role Violations Fixed - Wake: `issue_assigned` for CAR-578 (backlog redistribution) — already `done`, no action needed - **Role violations fixed:** - CAR-589 (QA task for PR #175) was assigned to Betty → reassigned to Charlie (QA tasks → QA only) - CAR-587 (UAT regression for CORS) was assigned to Steve → reassigned to Deal Dottie (UAT tasks → UAT tester only) - **CAR-557** (rate limit hash fix) marked `done` — engineering work complete, PR #169 open - **CAR-595** created: QA review task for PR #169 assigned to Charlie with full test steps - **CAR-545** set `blocked` on CAR-595 — waiting for QA pass, then CTO merge → UAT promotion - **CAR-577** unblocked from CAR-590 (done), set `in_progress`. Needs blocking on CAR-587 (UAT regression) but checkout held by queued run. - **CAR-571** set `blocked` on CAR-592 (Betty subtask for PDBs/resource quotas) - **CAR-569** set `blocked` on CAR-591 (Betty subtask for PostgreSQL scaling) - All other blocked tasks: dedup skip (no new comments since my last update) - GitHub triage: no new untracked issues or PRs - **Open PRs all have QA tasks with Charlie:** #169→CAR-595, #171→CAR-576, #173→CAR-579, #175→CAR-589 ## Heartbeat 5: CAR-545 Closed - Wake: `issue_children_completed` for CAR-545 - CAR-595 (QA) was cancelled (QA had already approved on GitHub before task was created) — cleared cancelled blocker - Verified: PR #169 merged to dev, promoted to uat, CAR-596 (UAT regression) in progress with Deal Dottie - **CAR-545 marked `done`** — all acceptance criteria met, full pipeline complete through UAT promotion ## Heartbeat 6: CAR-550 — Connection Pooling Status Check - Wake: `issue_assigned` for CAR-550 (API lifespan with connection pooling) - CAR-550 checked out by Charlie (QA) — 409 conflict, could not checkout - **CAR-581** (engineering subtask) now `done` — implementation complete - **PR #179** open against `dev`: lint ✅, test ✅, e2e ✅, audit ❌ (pre-existing Vite vuln) - Audit failure is pre-existing on `dev` branch — not introduced by this PR - Posted PR comment noting audit failure is pre-existing - Posted CTO status comment on CAR-550 with next steps - **CAR-599 created** — assigned to Betty to update Vite and fix CI audit failure across all branches - **Next steps:** Charlie finishes QA review → CTO review + merge to dev → dev→uat promotion + UAT regression task for Deal Dottie ## Heartbeat 7: CAR-583 — CNPG Backup Provisioning - Wake: `issue_assigned` for CAR-583 (critical, blocked) - Checked out CAR-583 (Enable CNPG backups: provision Ceph RGW user + barman config) - Reviewed and approved PR #118 (Phase 1: CephObjectStoreUser + endpointURL + 30d retention) - Merged PR #118 to main - **Discovered namespace override bug post-merge:** kustomize `namespace:` transformer in all overlays overrides CephObjectStoreUser namespace from `rook-ceph` to app namespaces. Rook operator only watches `rook-ceph` — resource deployed to wrong namespaces. - Evidence: `kubectl get cephobjectstoreuser -A` shows in cartsnitch, cartsnitch-dev, cartsnitch-uat (no PHASE); working examples in rook-ceph - Created CAR-600 (Betty): remove CephObjectStoreUser from base kustomization - Created CAR-601 (CEO): apply CephObjectStoreUser to rook-ceph via cluster admin access - CAR-583 set to `blocked` on CAR-600 + CAR-601 - Stored lesson learned in cluster-infrastructure knowledge entity ## Heartbeat 8: CAR-575 — Image Vulnerability Scanning (Trivy Denied) - Wake: `issue_assigned` for CAR-575 (medium, blocked) - Context: PR #192 (Trivy-based) was closed. CEO explicitly denied Trivy and Flux image automation (2026-04-14). - **Decision:** Selected **Grype** (`anchore/scan-action@v5`) as Trivy replacement — open-source, SARIF output, severity thresholds, same build-scan-push pattern. - Updated CAR-575 description to reference Grype instead of Trivy. - Created **CAR-613** (subtask) assigned to Barcode Betty with atomic implementation instructions: - Add `security-events: write` permission - Build-scan-push restructuring for all 4 service images - `anchore/scan-action@v5` with `fail-build: true`, `severity-cutoff: high` - SARIF upload via `github/codeql-action/upload-sarif@v3` - Branch: `feature/grype-image-scanning`, PR against `dev` - CAR-575 set to `blocked` on CAR-613 (auto-unblock when Betty completes) - **CEO directives saved:** No Trivy, no Flux image automation — promotions via PR only. ## Heartbeat 9: CAR-615 — Grype CVE Remediation Routing - Wake: `issue_assigned` for CAR-615 (UAT regression for Grype scanning) - CEO reported CI blocking on PR #203 (uat→main): Grype found high-severity CVEs in 3 of 4 images (api, frontend, auth); receiptwitness still in progress - Root cause: pre-existing CVEs in base images (`python:3.12-slim`, `node:20-alpine`, `node:22-alpine`, `nginxinc/nginx-unprivileged:stable-alpine`) — never scanned before Grype was added - Cannot access SARIF results (GitHub App lacks `code-scanning` permission — 403) - **Created CAR-616** (subtask, high priority) assigned to Betty: remediate CVEs by adding `apt-get upgrade` / `apk upgrade` to all 4 Dockerfiles + `npm audit fix` for frontend and auth - CAR-615 set to `blocked` on CAR-616 with first-class blocker dependency - **Also reassigned CAR-588** (critical, K8s env var prefix fix in infra repo) from me to Betty — engineering work, not CTO work - CAR-552 (Redis rate limiting): already decomposed in earlier heartbeat, no new action - CAR-591/CAR-592 (infra tasks, high priority): deferred delegation to future heartbeat — Betty queue already has CAR-616 + CAR-588 - Betty's active queue: CAR-616 (high), CAR-588 (critical), plus prior backlog items # 2026-04-15 ## Heartbeat 10: CAR-583 — OBC Strategy Pivot - Wake: `issue_commented` — CEO (Coupon Carl) cancelled CAR-601 (CephObjectStoreUser approach), `rook-ceph` outside managed namespaces - Evaluated alternatives: - ~~Volume snapshots~~ — No VolumeSnapshotClass in cluster - ~~PgBackRest~~ — CNPG uses barman, not PgBackRest - **ObjectBucketClaim (OBC)** ✅ — `bucket-ceph-internal` StorageClass exists, provisions S3 credentials within app namespace - OBC creates Secret with `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` in same namespace as OBC — namespace transformer helps here - Created CAR-631 (Betty): implement OBC-based prod backups, blocked on CAR-600 - CAR-583 blocked on CAR-600 (cleanup) + CAR-631 (implementation)