Skip to content

docs(qa): BaseballHelm Fairway visual audit pack (coach + player)#788

Merged
njrini99-code merged 3 commits into
mainfrom
cursor/baseball-qa-artifact-pack-6886
Jul 4, 2026
Merged

docs(qa): BaseballHelm Fairway visual audit pack (coach + player)#788
njrini99-code merged 3 commits into
mainfrom
cursor/baseball-qa-artifact-pack-6886

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Summary

Adds a labeled visual QA artifact pack from the 2026-07-04 BaseballHelm Fairway click-through audit (coach + player demo accounts).

Contents

docs/qa/baseball-fairway-visual-audit-2026-07-04/

Role Desktop Mobile Index
Coach (Nick Rini) 72 PNGs 7 PNGs coach/INDEX.md
Player (Marcus Rodriguez) 22 PNGs 7 PNGs player/INDEX.md

Each route entry includes:

  • Labeled screenshot ({##}-{role}-{route-slug}.png)
  • Page file path (src/app/baseball/.../page.tsx)
  • Nav registry hub + capability (coach routes)
  • Database table dependencies (curated + scanned from page/actions)
  • Actions / read-model paths where known
  • Audit notes, redirects, console errors (ERRORS.md)

Regenerate

E2E_ROLE=coach E2E_EMAIL=... E2E_PASSWORD=... OUT_DIR=/tmp/baseball-qa-full node scripts/tmp-baseball-route-audit.mjs
E2E_ROLE=player E2E_EMAIL=... E2E_PASSWORD=... OUT_DIR=/tmp/baseball-qa-full node scripts/tmp-baseball-route-audit.mjs
node scripts/build-baseball-qa-pack.mjs

Other changes

  • .gitignore: allow docs/qa/**/*.png (global *.png ignore otherwise blocks screenshots)
  • scripts/build-baseball-qa-pack.mjs: pack builder from audit output

Test plan

  • 108 screenshots copied with consistent naming
  • coach/INDEX.md and player/INDEX.md link to all desktop/mobile shots
  • manifest.json per role for programmatic lookup
Open in Web Open in Cursor 

Coach and player screenshot packs with per-route manifests linking
page files, database tables, actions/read-models, and audit notes.
Includes build script to regenerate from Playwright audit output.
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown

Too many files changed for review. (117 files found, 50 file limit)

Bypass the limit by tagging @greptile-apps to review.

@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
helmv3 Ignored Ignored Preview Jul 4, 2026 10:25pm

Request Review

@supabase

supabase Bot commented Jul 4, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project qmnssrrolpinvwjjnufo because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added a coach-only “College Interest” recruiting destination and updated dashboard/sidebar navigation to include a Recruiting hub.
  • Bug Fixes
    • Improved message participant naming using available display names.
    • Reduced analytics refresh issues and made analytics loading more resilient.
    • Refined route/ hub visibility behavior for recruiting-focused destinations.
  • Documentation
    • Added/updated a visual QA pack (screenshots, manifests, index/error reports, and rebuild instructions).

Walkthrough

Adds a baseball QA audit pack generator and generated coach/player audit docs, updates recruiting navigation for college-interest, and changes college-interest, analytics, messages, demo-coverage, and stats-smoke handling to use updated fields and routes.

Changes

Baseball QA Visual Audit Pack

Layer / File(s) Summary
Pack generation script
scripts/build-baseball-qa-pack.mjs, .gitignore, scripts/__tests__/baseball-stale-route-links.test.mjs
Builds the QA pack from audit JSON, nav registry metadata, screenshots, and route hints; tracks QA PNGs under docs/qa/**/; and exempts a few internal route files from stale-link scanning.
Coach audit artifacts
docs/qa/baseball-fairway-visual-audit-2026-07-04/coach/*
Adds the coach index, errors report, and manifest for desktop/mobile audit entries with route outcomes, notes, and screenshot metadata.
Player audit artifacts
docs/qa/baseball-fairway-visual-audit-2026-07-04/player/*
Adds the player index, errors report, and manifest for desktop/mobile audit entries with route outcomes, notes, and screenshot metadata.
QA registry and pack README
docs/qa/baseball-fairway-visual-audit-2026-07-04/NAV_ISSUES.md, docs/qa/baseball-fairway-visual-audit-2026-07-04/README.md
Adds the QA issues registry and the pack README describing the pack layout, known issues, and regeneration commands.

Baseball navigation and data flow updates

Layer / File(s) Summary
Recruiting navigation
src/lib/baseball/nav-registry.ts, src/app/baseball/(dashboard)/_components/hub-definitions.ts, src/app/baseball/(dashboard)/_components/resolve-active-hub.ts, src/app/baseball/(dashboard)/BaseballFairwayShell.tsx, src/components/layout/sidebar.tsx, src/app/baseball/actions/__tests__/route-shell-contract.test.ts, src/lib/baseball/__tests__/nav-manifest.test.ts, src/lib/baseball/__tests__/resolve-active-hub.test.ts
Registers college-interest, updates recruiting tab ordering and visibility, removes the player recruiting interest tab, adjusts coach hub gating and sidebar construction, and extends the nav/route-shell tests.
College-interest data shape
src/app/baseball/(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx
Switches the college-interest client to the new coach organization payload shape and maps recent activity fields from full_name plus nested organization data.
Messages participant display
src/lib/types/messages.ts, src/hooks/use-messages.ts, src/components/messages/ConversationList.tsx
Adds display_name to shared message types, computes it from conversation participant arrays, returns it in participant details, and prefers it in conversation labels.
Analytics hook
src/hooks/use-analytics.ts
Keeps the Supabase client stable across renders, narrows the engagement-events query, treats query errors as empty-state failures, and removes the client from the effect dependency list.
Demo coverage and smoke test
scripts/seed-rini-baseball-demo.ts, scripts/verify-baseball-demo-coverage.ts, e2e/baseball-stats-smoke.spec.ts
Changes the Rini seed ownership field, adds profile-based coverage selection and reporting, and makes the stats smoke test click a manifest-matched completed game before asserting box-score content.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

  • njrini99-code/helmv3#382 — The updated baseball QA pack and seeded stats smoke test align with deterministic smoke coverage for seeded baseball stats surfaces.

Possibly related PRs

Suggested labels: ci


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 2 warnings)

Check name Status Explanation Resolution
No Service-Role In Client Bundles ❌ Error scripts/seed-rini-baseball-demo.ts:137-139 and scripts/verify-baseball-demo-coverage.ts:167-169 read SUPABASE_SERVICE_ROLE_KEY and pass it to createClient(). Move service-role usage into src/lib/supabase/admin* or src/app/api//admin/, or swap these scripts to a server-only wrapper/env so the key is never present in changed client-facing code.
No Destructive Writes ❌ Error scripts/seed-rini-baseball-demo.ts deletes baseball_team_coach_staff/baseball_teams at 148-152, then upserts those same tables at 171-190, with no transaction comment justifying the rebuild. Either avoid the DELETEs or wrap the wipe-and-reseed in a documented transaction/SQL function with an explicit comment explaining the intentional rebuild.
Title check ⚠️ Warning The title is related to the change, but it uses the unlisted scope qa instead of one of the required scopes. Change the title to Conventional Commits with an allowed scope, such as docs(baseball): ... or another listed scope.
Conventional Commits ⚠️ Warning HEAD subject is 'Fix Baseball grouped shell and Rini seed coverage', which does not match the required conventional-commit regex. Change the PR title and squashed commit subject to a lowercase conventional commit, e.g. 'fix(baseball): grouped shell and Rini seed coverage'.
✅ Passed checks (8 passed)
Check name Status Explanation
Description check ✅ Passed The description matches the PR contents, describing the visual QA pack, builder script, and screenshot/gitignore updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Rls Coverage On New Tables ✅ Passed No changed migration files appear in the PR diff, so the CREATE TABLE/RLS rule is not applicable.
Auth Check In Server Actions ✅ Passed PASS: The only changed file under src/app//actions//*.ts is a Vitest test; it has no exported async function or Supabase calls. src/app/baseball/actions/tests/route-shell-contract.test.ts:2...
Sport-Prefixed Table Names ✅ Passed All changed Supabase queries use baseball_ prefixed tables/views; no bare coaches/players/teams/rounds/events queries found.
No Edits To Historical Migrations ✅ Passed No supabase/migrations/* files were changed in HEAD; the PR only touches docs, scripts, tests, and app code.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/baseball-qa-artifact-pack-6886
  • 🛠️ helm safety pass
  • 🛠️ dashboard ux pass
  • 🛠️ rls test pass

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.1)

ast-grep could not parse rule config: /ast-grep-rules/../git/.coderabbit/ast-grep/no-explicit-any.yml

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

e2e/baseball-stats-smoke.spec.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

scripts/seed-rini-baseball-demo.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

scripts/verify-baseball-demo-coverage.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 7 others

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the ci CI, Vercel, test, build, deploy label Jul 4, 2026
* Usage: node scripts/build-baseball-qa-pack.mjs
*/
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, existsSync } from 'fs';
import { join, basename } from 'path';
*/
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, existsSync } from 'fs';
import { join, basename } from 'path';
import { globSync } from 'glob';
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 4, 2026
@linear-code linear-code Bot marked this pull request as ready for review July 4, 2026 21:58
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app/baseball/(dashboard)/_components/hub-definitions.ts (1)

442-445: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Move the player redirect before the dashboard shell renders

PLAYER_RECRUITING_TABS no longer owns /baseball/dashboard/college-interest (src/app/baseball/(dashboard)/_components/hub-definitions.ts:441-445 vs. src/app/baseball/(dashboard)/_components/resolve-active-hub.ts:94-119), and CollegeInterestClient.tsx:191-260 only sends non-coach players away in useEffect. That leaves a deep-link window where the dashboard shell can mount with no active player hub highlighted. Push the player redirect to the page/layout boundary or make this route bypass the shell for player visitors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/baseball/`(dashboard)/_components/hub-definitions.ts around lines 442
- 445, The player redirect for the college-interest flow is happening too late,
allowing the dashboard shell to render before the user is sent away. Move the
non-coach player redirect out of CollegeInterestClient’s useEffect and into the
page/layout boundary so it runs before the shell mounts, or make the
/baseball/dashboard/college-interest route bypass the dashboard shell entirely
for player visitors. Update the routing logic around CollegeInterestClient,
resolve-active-hub, and the dashboard shell entry point so deep links never show
an unhighlighted hub.
src/app/baseball/(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx (1)

41-63: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Extract EngagementEvent to @/lib/types src/app/baseball/(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx:41-63 duplicates the same shape in src/hooks/use-analytics.ts:27-44; share one type so the query result stays in sync across both files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/app/baseball/`(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx
around lines 41 - 63, The EngagementEvent shape is duplicated in
CollegeInterestClient and use-analytics, so it should be shared from a single
source of truth. Move the EngagementEvent type into `@/lib/types`, then import and
use it in CollegeInterestClient and the analytics hook so both query result
typings stay aligned. Update any local type references in the affected
components/hooks to use the shared type instead of redefining it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/hooks/use-analytics.ts`:
- Around line 225-226: Confirm that the `useAnalytics` effect continues to
depend only on `user` and that the `supabase` client is truly stable by
construction from the `useRef`-based setup used in this hook. If the client is
not guaranteed stable, move its initialization so the ref is created once and
reused across renders; otherwise keep the current `[user]` dependency array with
the eslint-disable in place.
- Line 117: The handled failure in use-analytics.ts is currently falling back to
the empty state without recording eventsError anywhere. Update the useAnalytics
flow around the eventsError || !events check to send the query failure through
src/lib/error-logging.ts logError, or capture it with Sentry captureException,
before returning the empty analytics state. Keep the fallback behavior, but
ensure the error is logged with enough context to distinguish a real
Postgres/RLS failure from a genuine no-data result.
- Line 3: The analytics hook is still creating a browser Supabase client during
render, which causes a new instance on every re-render and can leave extra auth
state behind. Update use-analytics to avoid calling createClient() inside useRef
initialization or any render-time path; instead create the client lazily once
inside the hook using a stable initialization pattern and keep the existing
instance across renders. Use the createClient function from
src/lib/supabase/client.ts and the useAnalytics hook as the main locations to
adjust.

In `@src/hooks/use-messages.ts`:
- Around line 282-285: The participant name lookup in use-messages is relying on
parallel participant_ids and participant_names arrays whose order is not
guaranteed, so fix the conversation data shape to be deterministic. Update the
baseline migration query that builds the conversation payload so participant_ids
and participant_names come from the same ordered source (or better, a single
ordered participant record array), and avoid dropping entries when a users row
is missing. Then adjust the lookup logic in use-messages to read the name from
that deterministic structure using otherUserId rather than assuming array
positions always align.

In `@src/lib/baseball/nav-registry.ts`:
- Line 125: Add a regression test in resolve-active-hub.test.ts that directly
exercises resolveActiveHub for the new college-interest nav entry: call
resolveActiveHub with pathname '/baseball/dashboard/college-interest' and role
'coach', and assert it resolves to hub 'recruiting' with the 'college-interest'
tab id present. Use the existing resolveActiveHub test setup/helpers so the new
assertion covers the nav-registry entry introduced in nav-registry.ts.

---

Outside diff comments:
In `@src/app/baseball/`(dashboard)/_components/hub-definitions.ts:
- Around line 442-445: The player redirect for the college-interest flow is
happening too late, allowing the dashboard shell to render before the user is
sent away. Move the non-coach player redirect out of CollegeInterestClient’s
useEffect and into the page/layout boundary so it runs before the shell mounts,
or make the /baseball/dashboard/college-interest route bypass the dashboard
shell entirely for player visitors. Update the routing logic around
CollegeInterestClient, resolve-active-hub, and the dashboard shell entry point
so deep links never show an unhighlighted hub.

In
`@src/app/baseball/`(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx:
- Around line 41-63: The EngagementEvent shape is duplicated in
CollegeInterestClient and use-analytics, so it should be shared from a single
source of truth. Move the EngagementEvent type into `@/lib/types`, then import and
use it in CollegeInterestClient and the analytics hook so both query result
typings stay aligned. Update any local type references in the affected
components/hooks to use the shared type instead of redefining it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a3a669c8-8557-4dee-b337-d68948bd66d7

📥 Commits

Reviewing files that changed from the base of the PR and between af23283 and acec5a0.

📒 Files selected for processing (12)
  • docs/qa/baseball-fairway-visual-audit-2026-07-04/NAV_ISSUES.md
  • docs/qa/baseball-fairway-visual-audit-2026-07-04/README.md
  • scripts/__tests__/baseball-stale-route-links.test.mjs
  • scripts/build-baseball-qa-pack.mjs
  • src/app/baseball/(dashboard)/_components/hub-definitions.ts
  • src/app/baseball/(dashboard)/dashboard/college-interest/CollegeInterestClient.tsx
  • src/components/messages/ConversationList.tsx
  • src/hooks/use-analytics.ts
  • src/hooks/use-messages.ts
  • src/lib/baseball/__tests__/resolve-active-hub.test.ts
  • src/lib/baseball/nav-registry.ts
  • src/lib/types/messages.ts

'use client';

import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

rg -n "createClient|createBrowserClient|useRef\\(createClient\\(|useState\\(\\(\\) => createClient\\(" src/lib/supabase src/hooks/use-analytics.ts

Repository: njrini99-code/helmv3

Length of output: 765


🌐 Web query:

Supabase GoTrueClient _startAutoRefresh autoRefreshToken default createBrowserClient per-instance setInterval visibilitychange listener

💡 Result:

In the Supabase SDK, the GoTrueClient handles token refreshing via an internal _startAutoRefreshToken process, which manages session longevity [1][2]. Key implementation details regarding your query include: Auto-Refresh Mechanism The client uses a timer to schedule token refreshes [1][3]. When a session is saved or recovered, the client calculates the time remaining until expiration and calls _startAutoRefreshToken to schedule a refresh task [1]. The _startAutoRefreshToken method uses setTimeout to trigger _callRefreshToken shortly before the token expires [1][3]. If the refresh fails due to network issues, the client implements an exponential backoff strategy for retries [1]. Visibility Change Listener The GoTrueClient includes a _handleVisibilityChange method that listens for the browser's visibilitychange event [4]. When a tab or window returns to the foreground (document.visibilityState === 'visible'), the client triggers a session recovery and refresh process (_recoverAndRefresh) to ensure the session is still valid [5][4]. This is particularly important for recovering from tab suspension [5]. Calling the public startAutoRefresh or stopAutoRefresh methods manually will remove this managed visibility change callback, shifting the responsibility for managing visibility to the developer [2][6]. CreateBrowserClient Integration The createBrowserClient function from the @supabase/ssr package is designed to simplify client initialization in browser environments [7][8]. It automatically configures autoRefreshToken to true by default when running in a browser [7][9]. Historically, earlier versions of createBrowserClient would override user-provided autoRefreshToken settings, but recent updates (e.g., @supabase/ssr@0.10.1 and later) have been patched to respect developer-provided configuration options using nullish coalescing [10][9]. Per-Instance Behavior GoTrueClient manages its own internal state and timers on a per-instance basis [1][11]. Each SupabaseClient (and its nested auth client) maintains its own refresh timer, storage key references, and visibility listeners [11][4]. This ensures that multiple client instances do not interfere with each other's refresh cycles, though developers should be mindful of creating multiple singleton-style browser clients, which the @supabase/ssr library manages via a cached singleton pattern [7].

Citations:


Avoid useRef(createClient()) here; it evaluates on every render

src/hooks/use-analytics.ts:60-61 still calls createClient() during render, so each re-render builds and discards a browser Supabase client. src/lib/supabase/client.ts:8-17 wraps createBrowserClient(), which creates per-instance auth refresh state; that pattern can leave extra timers/listeners behind.

🔧 Proposed fix
-  const supabaseRef = useRef(createClient());
-  const supabase = supabaseRef.current;
+  const [supabase] = useState(() => createClient());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/use-analytics.ts` at line 3, The analytics hook is still creating a
browser Supabase client during render, which causes a new instance on every
re-render and can leave extra auth state behind. Update use-analytics to avoid
calling createClient() inside useRef initialization or any render-time path;
instead create the client lazily once inside the hook using a stable
initialization pattern and keep the existing instance across renders. Use the
createClient function from src/lib/supabase/client.ts and the useAnalytics hook
as the main locations to adjust.

.order('created_at', { ascending: false });

if (!events) {
if (eventsError || !events) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

eventsError is swallowed silently — no logging before falling back to the empty state.

Per docs/operations/observability-convention.md, client-side handled errors should still reach src/lib/error-logging.ts logError (or Sentry captureException) so a persistent query failure is visible somewhere other than "user sees zero analytics." Right now a real Postgres/RLS error is indistinguishable from "no rows yet."

🔧 Proposed fix
       if (eventsError || !events) {
+        if (eventsError) {
+          logError(eventsError, { context: 'useAnalytics.fetchAnalytics' });
+        }
         setData({
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (eventsError || !events) {
if (eventsError || !events) {
if (eventsError) {
logError(eventsError, { context: 'useAnalytics.fetchAnalytics' });
}
setData({
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/use-analytics.ts` at line 117, The handled failure in
use-analytics.ts is currently falling back to the empty state without recording
eventsError anywhere. Update the useAnalytics flow around the eventsError ||
!events check to send the query failure through src/lib/error-logging.ts
logError, or capture it with Sentry captureException, before returning the empty
analytics state. Keep the fallback behavior, but ensure the error is logged with
enough context to distinguish a real Postgres/RLS failure from a genuine no-data
result.

Comment on lines +225 to +226
// eslint-disable-next-line react-hooks/exhaustive-deps -- `supabase` is stable across renders (useRef above).
}, [user]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Dependency-array fix is correct, contingent on the useRef client being genuinely stable.

Narrowing to [user] with the eslint-disable is the right call given supabase doesn't change identity across renders — the ref's .current binding is indeed stable, so the effect won't loop. This is a real fix for the effect previously depending on a non-memoized supabase. See the comment on lines 60-61 for the underlying construction pattern that still needs cleanup, but the dependency-array reasoning itself is sound.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/use-analytics.ts` around lines 225 - 226, Confirm that the
`useAnalytics` effect continues to depend only on `user` and that the `supabase`
client is truly stable by construction from the `useRef`-based setup used in
this hook. If the client is not guaranteed stable, move its initialization so
the ref is created once and reused across renders; otherwise keep the current
`[user]` dependency array with the eslint-disable in place.

Comment thread src/hooks/use-messages.ts
Comment on lines 282 to +285
const otherUserId = conv.participant_ids?.find((id: string) => id !== user.id);
const otherUserIndex = otherUserId ? conv.participant_ids?.indexOf(otherUserId) ?? -1 : -1;
const otherUserDisplayName =
otherUserIndex >= 0 ? conv.participant_names?.[otherUserIndex] ?? null : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the RPC definition and check how participant_ids / participant_names are aggregated
rg -n "get_baseball_conversations_with_details" -g '*.sql' -A 40

Repository: njrini99-code/helmv3

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== locate RPC definition across repo ==\n'
rg -n "get_baseball_conversations_with_details" .

printf '\n== locate relevant hook lines ==\n'
sed -n '250,330p' src/hooks/use-messages.ts

Repository: njrini99-code/helmv3

Length of output: 6497


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== baseline function body ==\n'
sed -n '2311,2355p' supabase/migrations/20260527000000_prod_public_baseline.sql

printf '\n== archive function body ==\n'
sed -n '360,430p' supabase/migrations_archive/pre_20260527/042_sport_specific_messaging_tables.sql

printf '\n== fixed/lint migration body ==\n'
sed -n '1,80p' supabase/migrations_archive/pre_20260527/20260518124505_fix_live_db_lint_errors.sql

Repository: njrini99-code/helmv3

Length of output: 8065


Make the participant-name lookup deterministic
src/hooks/use-messages.ts:282-285 indexes participant_names using the position of otherUserId, but supabase/migrations/20260527000000_prod_public_baseline.sql:2311-2333 builds participant_ids and participant_names from separate ARRAY(SELECT ...) subqueries with no shared ORDER BY. That can attach the wrong name to the wrong participant; the JOIN users in the names subquery can also drop a participant entirely if the user row is missing. Build both arrays from the same ordered source, or return a single ordered participant record array instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/use-messages.ts` around lines 282 - 285, The participant name
lookup in use-messages is relying on parallel participant_ids and
participant_names arrays whose order is not guaranteed, so fix the conversation
data shape to be deterministic. Update the baseline migration query that builds
the conversation payload so participant_ids and participant_names come from the
same ordered source (or better, a single ordered participant record array), and
avoid dropping entries when a users row is missing. Then adjust the lookup logic
in use-messages to read the name from that deterministic structure using
otherUserId rather than assuming array positions always align.

| 'analytics'
| 'announcements'
| 'pipeline'
| 'college-interest'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

New college-interest entry looks correct — add a resolveActiveHub regression test.

The entry itself (id, href, role: 'coach', hub: 'recruiting', no capability gate) is consistent with the objective ("Coaches own the actual data surface"). No security/logic issue here.

Given resolve-active-hub.test.ts only exercises /baseball/dashboard/college-interest indirectly (and now via a swapped pathname — see that file's review), add an explicit coach-role assertion that resolveActiveHub({ pathname: '/baseball/dashboard/college-interest', role: 'coach', ... }) resolves to hub 'recruiting' with tab id 'college-interest' present. This is the one nav id this PR actually introduces, and it currently has zero direct hub-resolution coverage.

Also applies to: 563-575

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/baseball/nav-registry.ts` at line 125, Add a regression test in
resolve-active-hub.test.ts that directly exercises resolveActiveHub for the new
college-interest nav entry: call resolveActiveHub with pathname
'/baseball/dashboard/college-interest' and role 'coach', and assert it resolves
to hub 'recruiting' with the 'college-interest' tab id present. Use the existing
resolveActiveHub test setup/helpers so the new assertion covers the nav-registry
entry introduced in nav-registry.ts.

@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/layout/sidebar.tsx`:
- Around line 216-221: The comment on the branch that returns playerTeamNav is
stale and contradicts the current Recruiting nav entry added via
PLAYER_RECRUITING_TABS and COACH_HUB_DEFS.recruiting.icon. Update or remove the
outdated “ARCHIVED: recruiting nav disabled” comment so it accurately reflects
that recruiting is still part of the team nav, and keep the wording aligned with
the playerTeamNav construction in sidebar.tsx.
- Around line 120-125: The sidebar fallback for the recruiting hub is hardcoding
the label instead of using the mode-specific noun. Update the fallback in
sidebar.tsx where COACH_RECRUITING_HUB is defined, and any other hardcoded
Recruiting label in this flow, to use the same label source already used later
via getBaseballTerminology(ctx).exposureNoun. Keep the hub logic tied to
COACH_RECRUITING_HUB/COACH_RECRUITING_TABS, but make the displayed name resolve
from the terminology helper so it matches the program type before navContext
finishes loading.

In `@src/lib/baseball/__tests__/resolve-active-hub.test.ts`:
- Around line 93-103: Add a negative regression test in resolveActiveHub for the
academics hub using a non-eligible program type such as high_school with
can_view_academics: true, and assert it does not activate academics (hub is
null/undefined or another hub is chosen). Use the existing resolveActiveHub
helper and the academics hub/tab expectations in resolve-active-hub.test.ts to
mirror the positive case while verifying the fallback behavior for ineligible
programs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 93820902-7320-49d3-953e-428ed96b23ac

📥 Commits

Reviewing files that changed from the base of the PR and between acec5a0 and eb7eef2.

📒 Files selected for processing (11)
  • docs/qa/baseball-fairway-visual-audit-2026-07-04/NAV_ISSUES.md
  • e2e/baseball-stats-smoke.spec.ts
  • scripts/seed-rini-baseball-demo.ts
  • scripts/verify-baseball-demo-coverage.ts
  • src/app/baseball/(dashboard)/BaseballFairwayShell.tsx
  • src/app/baseball/(dashboard)/_components/hub-definitions.ts
  • src/app/baseball/(dashboard)/_components/resolve-active-hub.ts
  • src/app/baseball/actions/__tests__/route-shell-contract.test.ts
  • src/components/layout/sidebar.tsx
  • src/lib/baseball/__tests__/nav-manifest.test.ts
  • src/lib/baseball/__tests__/resolve-active-hub.test.ts

Comment on lines +120 to +125
const COACH_RECRUITING_HUB: SidebarHubItem = {
name: 'Recruiting',
href: COACH_RECRUITING_TABS[0]!.href,
icon: COACH_HUB_DEFS.recruiting.icon,
hubPrefixes: hubPrefixesFrom(COACH_RECRUITING_TABS),
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "exposureNoun" src/lib/baseball/nav-registry.ts -A 3 -B 3

Repository: njrini99-code/helmv3

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the sidebar file around the referenced lines and search for the nav label helpers.
sed -n '100,180p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '200,240p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '280,340p' src/components/layout/sidebar.tsx
printf '\n---\n'
rg -n "getBaseballTerminology|exposureNoun|Recruiting" src -A 2 -B 2

Repository: njrini99-code/helmv3

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect sidebar file around the referenced lines and search for the nav label helpers.
sed -n '100,180p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '200,240p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '280,340p' src/components/layout/sidebar.tsx
printf '\n---\n'
rg -n "getBaseballTerminology|exposureNoun|Recruiting" src -A 2 -B 2

Repository: njrini99-code/helmv3

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '100,180p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '200,240p' src/components/layout/sidebar.tsx
printf '\n---\n'
sed -n '280,340p' src/components/layout/sidebar.tsx
printf '\n---\n'
rg -n "getBaseballTerminology|exposureNoun|Recruiting" src -A 2 -B 2

Repository: njrini99-code/helmv3

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "function getBaseballTerminology|getBaseballTerminology\(" src memory -A 6 -B 3

Repository: njrini99-code/helmv3

Length of output: 6695


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'sidebar.tsx excerpt:\n'
sed -n '110,240p' src/components/layout/sidebar.tsx
printf '\n---\nnav-related matches:\n'
rg -n "getBaseballTerminology|exposureNoun|Recruiting" src memory -A 2 -B 2

Repository: njrini99-code/helmv3

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the terminology definitions and the tests that exercise them.
sed -n '1,220p' src/lib/baseball/__tests__/program-type-nav-variants.test.ts
printf '\n---\n'
sed -n '1,260p' src/lib/baseball/nav-registry.ts | sed -n '900,1160p'

Repository: njrini99-code/helmv3

Length of output: 11009


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the specific terminology mappings and the assertions about exposureNoun.
rg -n "exposureNoun|terminology" src/lib/baseball/nav-registry.ts -A 6 -B 6
printf '\n---\n'
sed -n '130,170p' src/lib/baseball/__tests__/program-type-nav-variants.test.ts

Repository: njrini99-code/helmv3

Length of output: 2595


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the actual exposureNoun definitions/usages without dumping the whole file.
rg -n "exposureNoun" src/lib/baseball src/app/baseball -A 3 -B 3

Repository: njrini99-code/helmv3

Length of output: 4998


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the variant definitions around any exposure-related terminology fields.
rg -n "exposure" src/lib/baseball/nav-registry.ts -A 5 -B 5

Repository: njrini99-code/helmv3

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the terminology object fields that include exposureNoun.
rg -n "exposureNoun\s*:" src/lib/baseball/nav-registry.ts -A 3 -B 3
printf '\n---\n'
rg -n "exposureNoun" src/lib/baseball/__tests__/program-type-nav-variants.test.ts -A 3 -B 3

Repository: njrini99-code/helmv3

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the program variant objects that define terminology, if any.
rg -n "exposureNoun|eventNoun|programNoun|rosterNoun" src/lib/baseball/nav-registry.ts -A 4 -B 4

Repository: njrini99-code/helmv3

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the variant table entries that set terminology.
rg -n "terminology:" src/lib/baseball/nav-registry.ts -A 10 -B 4

Repository: njrini99-code/helmv3

Length of output: 158


Use the mode-specific recruiting noun in the sidebar fallback.

src/components/layout/sidebar.tsx:121 and :217 hardcode Recruiting, but :296 and :328 already pull the label from getBaseballTerminology(ctx).exposureNoun. That noun varies by program type (College Interest, Exposure, Transfer Exposure), so the fallback can flash the wrong label until navContext resolves. Make the fallback share the same label source instead of hardcoding it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/layout/sidebar.tsx` around lines 120 - 125, The sidebar
fallback for the recruiting hub is hardcoding the label instead of using the
mode-specific noun. Update the fallback in sidebar.tsx where
COACH_RECRUITING_HUB is defined, and any other hardcoded Recruiting label in
this flow, to use the same label source already used later via
getBaseballTerminology(ctx).exposureNoun. Keep the hub logic tied to
COACH_RECRUITING_HUB/COACH_RECRUITING_TABS, but make the displayed name resolve
from the terminology helper so it matches the program type before navContext
finishes loading.

Comment on lines +216 to +221
{
name: 'Recruiting',
href: PLAYER_RECRUITING_TABS[0]!.href,
icon: COACH_HUB_DEFS.recruiting.icon,
hubPrefixes: hubPrefixesFrom(PLAYER_RECRUITING_TABS),
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale "ARCHIVED: recruiting nav disabled" comment now contradicts the code it annotates.

Lines 216-221 add a live "Recruiting" entry to playerTeamNav, but the branch that returns playerTeamNav (shown further down in this file) still carries the comment // ARCHIVED: All players now see team nav only — recruiting nav disabled. That comment is now factually wrong and will mislead the next person touching this branch into thinking recruiting nav is dead code.

📝 Suggested comment fix
     } else if (user?.role === 'player') {
-      // ARCHIVED: All players now see team nav only — recruiting nav disabled
+      // Player fallback nav (pre-navContext). Mirrors buildCondensedBaseballNavigation's
+      // player branch, including the Recruiting entry.
       return playerTeamNav;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/layout/sidebar.tsx` around lines 216 - 221, The comment on the
branch that returns playerTeamNav is stale and contradicts the current
Recruiting nav entry added via PLAYER_RECRUITING_TABS and
COACH_HUB_DEFS.recruiting.icon. Update or remove the outdated “ARCHIVED:
recruiting nav disabled” comment so it accurately reflects that recruiting is
still part of the team nav, and keep the wording aligned with the playerTeamNav
construction in sidebar.tsx.

Comment on lines +93 to +103

it('activates academics for college coaches with the academics capability', () => {
const hub = resolveActiveHub({
pathname: '/baseball/dashboard/academics',
role: 'coach',
programType: 'college',
capabilities: { can_view_academics: true },
});
expect(hub?.id).toBe('academics');
expect(hub?.tabs.map((t) => t.id)).toEqual(['academics']);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add a negative test for academics + ineligible program type.

This test proves academics activates for programType: 'college' + can_view_academics, but there's no companion test asserting it stays hidden for a non-eligible program type (e.g. high_school) even when can_view_academics: true is set. Given the removed code path (Line 239-246 in BaseballFairwayShell.tsx, Line 78-91 in resolve-active-hub.ts) used to hard-block this at the hub level, and enforcement now lives purely in tab config, this is exactly the regression this suite should guard against.

✅ Suggested additional test
   it('activates academics for college coaches with the academics capability', () => {
     const hub = resolveActiveHub({
       pathname: '/baseball/dashboard/academics',
       role: 'coach',
       programType: 'college',
       capabilities: { can_view_academics: true },
     });
     expect(hub?.id).toBe('academics');
     expect(hub?.tabs.map((t) => t.id)).toEqual(['academics']);
   });
+
+  it('hides academics for ineligible program types even with the capability set', () => {
+    const hub = resolveActiveHub({
+      pathname: '/baseball/dashboard/academics',
+      role: 'coach',
+      programType: 'high_school',
+      capabilities: { can_view_academics: true },
+    });
+    expect(hub?.id).not.toBe('academics');
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('activates academics for college coaches with the academics capability', () => {
const hub = resolveActiveHub({
pathname: '/baseball/dashboard/academics',
role: 'coach',
programType: 'college',
capabilities: { can_view_academics: true },
});
expect(hub?.id).toBe('academics');
expect(hub?.tabs.map((t) => t.id)).toEqual(['academics']);
});
it('activates academics for college coaches with the academics capability', () => {
const hub = resolveActiveHub({
pathname: '/baseball/dashboard/academics',
role: 'coach',
programType: 'college',
capabilities: { can_view_academics: true },
});
expect(hub?.id).toBe('academics');
expect(hub?.tabs.map((t) => t.id)).toEqual(['academics']);
});
it('hides academics for ineligible program types even with the capability set', () => {
const hub = resolveActiveHub({
pathname: '/baseball/dashboard/academics',
role: 'coach',
programType: 'high_school',
capabilities: { can_view_academics: true },
});
expect(hub?.id).not.toBe('academics');
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/baseball/__tests__/resolve-active-hub.test.ts` around lines 93 - 103,
Add a negative regression test in resolveActiveHub for the academics hub using a
non-eligible program type such as high_school with can_view_academics: true, and
assert it does not activate academics (hub is null/undefined or another hub is
chosen). Use the existing resolveActiveHub helper and the academics hub/tab
expectations in resolve-active-hub.test.ts to mirror the positive case while
verifying the fallback behavior for ineligible programs.

@njrini99-code njrini99-code merged commit e63de60 into main Jul 4, 2026
41 checks passed
@njrini99-code njrini99-code deleted the cursor/baseball-qa-artifact-pack-6886 branch July 4, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI, Vercel, test, build, deploy

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants