Skip to content

daily: morning triage + frontend audit + db health 2026-04-14#68

Merged
vayungodara merged 4 commits into
mainfrom
fix/morning-triage-2026-04-14
Apr 14, 2026
Merged

daily: morning triage + frontend audit + db health 2026-04-14#68
vayungodara merged 4 commits into
mainfrom
fix/morning-triage-2026-04-14

Conversation

@vayungodara

Copy link
Copy Markdown
Owner

Summary

  • 4 bug fixes applied (all pass lint):
    • ActivityFeed loadMore dedup — prevents duplicate activities from pagination/realtime race
    • PactCard completed card contrast — opacity 0.7→0.8, text-tertiary→text-secondary (WCAG AA)
    • PactCard shimmerSweep — local keyframe so completion shimmer plays in CSS Modules
    • Skeleton shimmer — local keyframe so loading pulse animates instead of static gray
  • 3 reports generated: triage, frontend audit, DB health
  • Notion updated: 6 existing rows updated, 4 older duplicates marked fixed, 2 new rows created

Triage Summary

Metric Value
Total findings 10
Fixed this PR 4
Carried over 6
New (unfixed) 1 (Info: force-dynamic on landing)
DB health WARNINGS (XP drift on 4 profiles, 1 abandoned session — carried over)
RLS security All 17 tables secured
Vercel health Landing 200, Dashboard 307 — healthy

Frontend Audit Highlights

Page Score
Focus 8.1 (highest)
Dashboard/Pacts/Groups 8.0
Settings 7.9
Landing 7.3 (+0.6 from --font-display fix)
Stats 6.4 (lowest — zero animations)

Top priority: Stats page animation overhaul (6.4/10, zero Framer Motion)

Test plan

  • Verify completed pact cards have readable text in both light and dark mode
  • Scroll activity feed rapidly to confirm no duplicate entries appear
  • Check skeleton loading states animate with pulse effect
  • Verify pact completion shimmer plays on check-off

🤖 Generated with Claude Code

@vercel

vercel Bot commented Apr 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lockin Ready Ready Preview, Comment Apr 14, 2026 5:30pm

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43d5577006

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +25 to +27
@keyframes shimmer {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor reduced-motion for newly enabled skeleton pulse

Adding a local @keyframes shimmer now makes .skeleton/.skeletonText run a visible opacity pulse, but the existing reduced-motion block in this file only disables the ::after slide animation. In prefers-reduced-motion: reduce, users will still get continuous skeleton pulsing, which is an accessibility regression introduced by this change. Please also disable the base animation on .skeleton and .skeletonText under the reduced-motion media query.

Useful? React with 👍 / 👎.

@vayungodara

Copy link
Copy Markdown
Owner Author

@claude review

@claude

claude Bot commented Apr 14, 2026

Copy link
Copy Markdown

Claude finished @vayungodara's task in 2m 23s —— View job


PR Review: Morning triage + frontend audit + db health

  • Read CLAUDE.md and PR context
  • Review components/ActivityFeed.js (dedup loadMore)
  • Review components/PactCard.module.css (contrast + shimmer)
  • Review components/Skeleton.module.css (shimmer)
  • Spot-check the report docs

Overall

Small, well-scoped PR: four tight bug fixes plus three report docs. Changes look correct and the diff is minimal. Approve direction; a few notes below — mostly polish, no blockers.

components/ActivityFeed.js:138-142 — dedup ✅ with a caveat

The Set-based dedup is the right pragmatic fix for the realtime-insert + offset-pagination race. It matches the existing guard in the realtime path (line 107) for symmetry.

Caveat worth noting in a comment (not a blocker): on line 137, offsetRef.current advances by the raw newActivities.length, not the unique count. With offset-based pagination, if a realtime INSERT prepended a row between page loads, the next page will legitimately overlap by exactly that count — dedup removes the dupes, but offset still moves forward, so you effectively skip N items off the tail of the result set to keep the offset monotonic. That's the same trade-off any offset-paginated feed makes against prepends; the fix is fine, but a one-line code comment explaining this would save future-you a debugging session. The real fix is cursor/created_at-based pagination — out of scope here.

Also on line 143: hasMore is set from raw newActivities.length === pageSize, which is correct (server returned a full page → more may exist), even when dedup filtered everything out.

components/PactCard.module.css — contrast + shimmer ✅

  • Opacity 0.7 → 0.8 + text-tertiary → text-secondary for .card.completed .title is the right lever for WCAG AA. The dark-mode overrides at 378-398 already boosted contrast there, so the light-mode fix brings parity.
  • Local @keyframes shimmerSweep (422-425) fixes the CSS-Modules name-mangling issue — nice catch. Note that the same keyframe also lives at app/globals.css:906 (byte-identical). CSS Modules scope animation names, so the local one correctly wins inside the module; the global one is now effectively dead weight for this use case (though other non-module consumers may still use it — leave it alone for this PR).
  • Minor a11y gap (pre-existing, not introduced here): .completedCheck::after at line 417 runs shimmerSweep but isn't covered by either @media (prefers-reduced-motion: reduce) block (lines 200, 362). Worth adding a rule:
    @media (prefers-reduced-motion: reduce) {
      .completedCheck::after { animation: none; }
    }
    Fix this →

components/Skeleton.module.css — shimmer ⚠️ naming collision

  • Adding a local @keyframes shimmer (25-28) does fix the missing pulse, but heads-up: this locally overrides a different global keyframe of the same name. app/globals.css:875 has @keyframes shimmer that animates background-position (for gradient-backed skeletons); your new local one animates opacity. Functionally equivalent to the existing @keyframes pulse in globals.css:870. Two suggestions:

    1. Rename the local one to skeletonPulse to avoid shadowing a well-known name — makes the intent obvious and prevents someone pasting in code that expected the gradient version.
    2. Or, since it's a pure opacity pulse, reference the global pulse instead: animation: pulse 1.5s ease-in-out infinite; (but CSS Modules will scope-mangle that too unless you use animation-name: global(pulse) — so renaming locally is cleaner).
  • A11y gap (introduced here): the reduced-motion block at lines 68-73 only disables the ::after sweep, not the newly-added opacity pulse on .skeleton / .skeletonText. Add those:

    @media (prefers-reduced-motion: reduce) {
      .skeleton,
      .skeletonText,
      .skeleton::after,
      .skeletonText::after {
        animation: none;
      }
    }

    Fix this →

Reports

  • docs/reports/triage-2026-04-14.md:37 marks the light-mode pact contrast as Critical. The fix in code (opacity 0.7 → 0.8 + text-tertiary → text-secondary) is on the right path, but "Critical / below WCAG AA" warrants a spot-check with an actual contrast measurement after the change — the report asserts the fix resolves it without citing a measured ratio. Worth verifying with Chrome DevTools or axe in light mode against --bg-primary/--surface-1 before closing out as fixed.
  • The three reports are well-structured and cross-reference the code accurately. No issues.

Summary

Area Status
Correctness ✅ all four fixes do what they claim
A11y ⚠️ two small prefers-reduced-motion gaps (one introduced, one pre-existing)
Naming ⚠️ @keyframes shimmer shadows a differently-behaving global keyframe
Test plan coverage ✅ covered by the four checkboxes in the PR body

Nothing is a blocker — ship it, and fold the a11y and naming nits into the next polish pass.
· Branch: fix/morning-triage-2026-04-14

vayungodara and others added 4 commits April 14, 2026 19:29
…licates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mmerSweep keyframe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
}

@keyframes shimmer {
0%, 100% { opacity: 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Nit — The prefers-reduced-motion block at lines 68–73 only disables the ::after (shimmerSlide) animations. Before this PR the animation: shimmer … at lines 4 and 33 was a no-op (no matching @keyframes), so motion-sensitive users saw nothing. Now that @keyframes shimmer (opacity pulse) is defined, those users will see a continuous opacity pulse that isn’t covered by the reduced-motion override.

Fix: extend the reduced-motion rule to also disable the animation on .skeleton and .skeletonText themselves:

@media (prefers-reduced-motion: reduce) {
  .skeleton,
  .skeletonText {
    animation: none;
  }
  .skeleton::after,
  .skeletonText::after {
    animation: none;
  }
}

@claude

claude Bot commented Apr 14, 2026

Copy link
Copy Markdown

Code review summary

Severity counts — 🔴 0 · 🟡 1 · 🟣 0

Scope reviewed — components/ActivityFeed.js, components/PactCard.module.css, components/Skeleton.module.css. Per REVIEW.md, docs/** changes were skipped.

Findings

  1. 🟡 components/Skeleton.module.css — the newly-defined @keyframes shimmer (opacity pulse) is not covered by the existing prefers-reduced-motion media query, which only disables the ::after animations. Users with motion preferences will see a continuous pulse. Fix suggested inline.

Verified clean

  • components/ActivityFeed.js — the dedup change is a pure refactor (extracts const unique = ... from an inline .filter), behavior is identical. Upstream guards (realtime prev.some(a => a.id === enriched.id), isLoadingMoreRef gate, groupIdRef stale-response check) all still hold.
  • components/PactCard.module.css — contrast tweak (--text-tertiary to --text-secondary, opacity 0.7 to 0.8) is WCAG-motivated and preserves dark-mode parity (existing :global([data-theme="dark"]) .card.completed .title override at line 473 still wins). The newly-added local @keyframes shimmerSweep correctly backs the existing animation: shimmerSweep ... at line 508 — CSS Modules scope keyframe names per file, so the global one in globals.css was unreachable from the module.
  • No missing work — no schema/migration/API-route changes in this PR; cron auth, Supabase client/server split, overflow-x: clip, dark-mode tokens, and createPortal rules are all untouched.

@vayungodara vayungodara merged commit bfbb44e into main Apr 14, 2026
8 checks passed
@vayungodara vayungodara deleted the fix/morning-triage-2026-04-14 branch April 14, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant