Skip to content

Add printable judge schedules - #655

Merged
zacjones93 merged 4 commits into
mainfrom
agent/judge-schedule-printing
Aug 7, 2026
Merged

Add printable judge schedules#655
zacjones93 merged 4 commits into
mainfrom
agent/judge-schedule-printing

Conversation

@zacjones93

@zacjones93 zacjones93 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a print center with master heat/lane grids and individualized judge packets
  • include judge, team or athlete, full roster, division, venue, timing, and workout details
  • support bulk printing all judge packets or selecting one replacement sheet
  • add compact WODsmith Compete branding to master sheets and judge packets
  • document the organizer entry points and print workflow

Why

Organizers were manually assembling judge assignments and team rosters in spreadsheets before an event. This gives floor staff printable schedules that work without requiring every judge to sign in.

Validation

  • pnpm test -- test/components/judges-schedule-content.test.tsx
  • pnpm type-check
  • repository pre-push pnpm lint
  • repository pre-push pnpm type-check
  • lat check
  • browser-rendered letter PDFs for the master grid and bulk judge packets; verified one judge per page and WODsmith branding on each sheet

Summary by cubic

Adds a print center with a master heat/lane grid and individual judge packets (run sheets + briefs) so organizers can print event‑day schedules that work offline. Access is restricted to organizers and competition‑team members.

  • New Features
    • Master grid: prints every heat and lane with judge, team/athlete, full roster (active teammates + named pending teammates), division, time, venue; shows floating floor judges.
    • Judge packets: print all judges or one selected; per‑judge run sheets with time, heat, lane/floor, athlete/team, roster; deduped briefs per event+division+description and preserves blank division overrides; one judge per page; compact WODsmith Compete branding.
    • Invitation judges: keep unique assignee IDs and names from invitations; generate separate packets for pending volunteers.
    • UI: toggle between Master grid and Judge packets; “Print sheets for” selector (All or one judge); print button now says “Print current view”.
    • Data/auth: server returns workout description, scheme, timeCapSeconds, and division‑specific scaling descriptions; lanes include registration with teamName and full athleteNames; getJudgesScheduleDataFn requires MANAGE_COMPETITIONS or competition‑team membership.
    • Docs & tests: organizer docs updated with entry points and workflow; tests cover grid, packets, branding, roster resolution and fallbacks, selection reset when a judge disappears, invitation‑backed packets, and brief de‑dupe/blank overrides.

Written for commit d8c82cd. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added printable master judge schedules with heat, lane, athlete, team, and workout details.
    • Added personalized judge packets with selectable judges, workout briefs, assignments, floor information, branding, and pagination.
    • Included invitation-based judge assignments and expanded athlete roster details.
    • Added responsive layouts and helpful empty states.
    • Restricted schedule access to authorized competition organizers and team members.
  • Documentation

    • Updated organizer guidance for creating, printing, and using judge schedules.
    • Documented available print modes and schedule access points.
  • Bug Fixes

    • Replaced the unavailable heat-sheet export placeholder with working schedule instructions.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The judge schedule flow now enforces organizer and competition-team access. It loads workout metadata, invitation-backed judges, and athlete rosters. The interface renders master schedules and selectable judge packets with responsive and printable layouts.

Changes

Judge schedule printouts

Layer / File(s) Summary
Authorize and enrich schedule data
apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts, apps/wodsmith-start/src/routes/compete/$slug/judges-schedule.tsx
The schedule loader now authorizes organizers and competition-team members. The response includes workout metadata, invitation-backed judges, registration details, and deduplicated athlete rosters.
Normalize and group schedule assignments
apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx
The component normalizes lanes, formats workout details, groups heats by day, and creates sorted judge packets.
Render master schedules
apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx, apps/wodsmith-start/src/routes/compete/$slug/judges-schedule.tsx
The component renders responsive master tables and printable layouts with heat, lane, judge, competitor, division, and workout details. The print action now says “Print current view.”
Render judge packets and supporting guidance
apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx, apps/wodsmith-start/test/components/judges-schedule-content.test.tsx, apps/docs/docs/how-to/organizers/*.md, lat.md/organizer-dashboard.md
The component renders selectable judge packets and printable workout briefs. Tests and documentation cover rosters, invitation-backed judges, brief fallback behavior, and print modes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CompetitionOrganizer
  participant JudgesScheduleRoute
  participant judgeSchedulingFns
  participant JudgesScheduleContent
  participant BrowserPrint
  CompetitionOrganizer->>JudgesScheduleRoute: open judges schedule
  JudgesScheduleRoute->>judgeSchedulingFns: request authorized schedule
  judgeSchedulingFns-->>JudgesScheduleRoute: return enriched schedule data
  JudgesScheduleRoute->>JudgesScheduleContent: render schedule
  CompetitionOrganizer->>JudgesScheduleContent: select master or judge view
  JudgesScheduleContent->>BrowserPrint: render current view for printing
Loading

Possibly related PRs

Suggested reviewers: theianjones

Poem

A rabbit sorts the lanes just right,
Judge packets stack in tidy flight.
Workout briefs and rosters appear,
Master grids make heat times clear.
“Print current view!” I cheer.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding printable judge schedules.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/judge-schedule-printing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@zacjones93
zacjones93 marked this pull request as ready for review August 7, 2026 04:51

@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: 87715c3b50

ℹ️ 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 thread apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts
Comment thread apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx (1)

211-214: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Hoist getMaxLanes(event) out of the heat loop.

getMaxLanes scans every heat of the event. Calling it per heat makes packet building O(heats²) per event. The value does not change inside the loop.

♻️ Proposed refactor
   for (const event of events) {
+    const maxLanes = getMaxLanes(event)
     for (const heat of event.heats) {
-      const maxLanes = getMaxLanes(event)
       const lanes = getLaneData(heat, maxLanes)
🤖 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
`@apps/wodsmith-start/src/routes/compete/`$slug/-components/judges-schedule-content.tsx
around lines 211 - 214, Hoist the getMaxLanes(event) call in the event iteration
so each event computes maxLanes once before entering its heat loop. Reuse that
value when calling getLaneData for every heat, preserving the existing
packet-building behavior.
apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts (1)

1610-1626: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

The registration owner is always added to the roster, not only as a fallback.

The comment at Line 1559 states that individual registrations fall back to the registration owner. The code adds registration.userId to rosterUserIds for every registration, including team registrations. If the owner is a coach or a non-competing manager, the owner name appears in printed team rosters. Consider using the owner only when teamUserIds is empty, or update the comment to match the behavior.

♻️ Proposed change
-        const rosterUserIds = [
-          ...new Set([registration.userId, ...teamUserIds]),
-        ]
+        const rosterUserIds =
+          teamUserIds.length > 0
+            ? [...new Set(teamUserIds)]
+            : [registration.userId]
🤖 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 `@apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts` around lines 1610
- 1626, Update the roster construction in the registration mapping to include
registration.userId only when teamUserIds is empty, while retaining all team
athlete IDs for team registrations. Keep the existing deduplication, name
mapping, and sorting behavior unchanged, and ensure individual registrations
still fall back to the registration owner.
🤖 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
`@apps/wodsmith-start/src/routes/compete/`$slug/-components/judges-schedule-content.tsx:
- Around line 166-172: Update getCompetitorLabel to use a falsy fallback for
teamName so empty strings fall through to the first athlete name. Also update
the teamName checks in MasterLaneCell and PrintMasterEvent to treat empty
strings as absent, preserving roster display for valid team names.
- Around line 265-268: Update the judge packet filtering around
visibleJudgePackets to resolve selectedJudgeId against the currently available
judge packets, falling back to all packets when no packet matches the selected
membershipId. Pass this resolved selection value to the judge select control so
it always corresponds to an available option and never renders blank after
events reload.

---

Nitpick comments:
In
`@apps/wodsmith-start/src/routes/compete/`$slug/-components/judges-schedule-content.tsx:
- Around line 211-214: Hoist the getMaxLanes(event) call in the event iteration
so each event computes maxLanes once before entering its heat loop. Reuse that
value when calling getLaneData for every heat, preserving the existing
packet-building behavior.

In `@apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts`:
- Around line 1610-1626: Update the roster construction in the registration
mapping to include registration.userId only when teamUserIds is empty, while
retaining all team athlete IDs for team registrations. Keep the existing
deduplication, name mapping, and sorting behavior unchanged, and ensure
individual registrations still fall back to the registration owner.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: cfeda5b6-adef-45c5-888c-0ea88e34ea32

📥 Commits

Reviewing files that changed from the base of the PR and between 245b325 and 87715c3.

📒 Files selected for processing (7)
  • apps/docs/docs/how-to/organizers/event-day.md
  • apps/docs/docs/how-to/organizers/schedule-heats.md
  • apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx
  • apps/wodsmith-start/src/routes/compete/$slug/judges-schedule.tsx
  • apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx
  • lat.md/organizer-dashboard.md

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts
Comment thread apps/wodsmith-start/test/components/judges-schedule-content.test.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts`:
- Around line 1688-1705: Update the rosterUserIds construction near
confirmedAthleteNames so registration.userId is used only when
registration.athleteTeamId is null; when a team ID exists, preserve an empty
roster if it has no active memberships. Keep the existing teamUserIds handling
and downstream athlete-name processing unchanged.
- Around line 1411-1424: The forbidden branch guarded by canManageCompetition
and isCompetitionTeamMember must return an HTTP 403 response instead of throwing
a generic Error. Replace the throw in the judge-schedule access check with the
project’s established 403 error mechanism or a direct 403 response, preserving
the existing permission message.

In `@apps/wodsmith-start/test/components/judges-schedule-content.test.tsx`:
- Around line 52-66: Add exactly one nearby unique # `@lat`: reference to each of
the five tests in
apps/wodsmith-start/test/components/judges-schedule-content.test.tsx: lines
52-66 for the athlete-name fallback specification, 68-101 for selection reset,
103-147 for invitation-backed packet, 149-169 for blank division brief, and
171-213 for delimiter-safe brief grouping. Ensure every reference targets a
different test-specification leaf.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 8ac92c1f-62c8-4bd6-9180-c8bf21176828

📥 Commits

Reviewing files that changed from the base of the PR and between 87715c3 and d8c82cd.

📒 Files selected for processing (5)
  • apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx
  • apps/wodsmith-start/src/routes/compete/$slug/judges-schedule.tsx
  • apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx
  • lat.md/organizer-dashboard.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/wodsmith-start/src/routes/compete/$slug/judges-schedule.tsx
  • apps/wodsmith-start/src/routes/compete/$slug/-components/judges-schedule-content.tsx
  • lat.md/organizer-dashboard.md

Comment on lines +1411 to +1424
const canManageCompetition = await hasTeamPermission(
competition.organizingTeamId,
TEAM_PERMISSIONS.MANAGE_COMPETITIONS,
)
const isCompetitionTeamMember = competition.competitionTeamId
? await isTeamMember(competition.competitionTeamId)
: false

if (!canManageCompetition && !isCompetitionTeamMember) {
throw new Error(
"FORBIDDEN: You don't have permission to view judge schedules",
)
}

Copy link
Copy Markdown
Contributor

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

ast-grep outline apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts --items all

rg -n -C 3 \
  'FORBIDDEN|status:\s*403|throw new Response|throw new Error' \
  apps/wodsmith-start/src/server-fns

Repository: wodsmith/thewodapp

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the server function and nearby imports/exports.
sed -n '1,40p' apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts
sed -n '1360,1475p' apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts

# Locate TanStack Start server function error/status handling and similar 403 patterns.
rg -n -C 4 \
  'throw new (HttpFailError|AssertionError|Error)\(' \
  'HttpFailError' \
  'status:' \
  'Response\.status' \
  'FORBIDDEN|Forbidden|403' \
  apps/wodsmith-start/src apps/wodsmith-start/package.json pnpm-lock.yaml 2>/dev/null | head -n 500

Repository: wodsmith/thewodapp

Length of output: 39636


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Package manager files:"
fd -a -i '^(package.json|pnpm-lock.yaml|package-lock.json|bun.lockb|yarn.lock)$' . | sed 's#^\./##' | head -n 50

echo
echo "TanStack versions:"
rg -n '"`@tanstack/react-start`"|tanstack|`@tanstack/react-server`' apps/wodsmith-start/package.json pnpm-lock.yaml package.json 2>/dev/null | head -n 120 || true

echo
echo "HTTP handling symbols:"
rg -n --hidden --glob '!**/node_modules/**' \
  'HttpFailError|Response\.status|response\.status|status:|Response\.json|throw new Response|catch \([^)]*\) =>|\.handler' \
  apps/wodsmith-start/src app packages 2>/dev/null | head -n 400 || true

Repository: wodsmith/thewodapp

Length of output: 50374


🌐 Web query:

TanStack Start server functions throw HttpFailError status 403 createServerFn

💡 Result:

In TanStack Start, server functions (createServerFn) can sometimes default to an HTTP 500 status when an error is thrown, even if you intend to send a different status code like 403 [1][2]. This behavior often occurs because unhandled errors or specific error patterns cause the server runtime to override or ignore status codes set via setResponseStatus [3][2]. Key factors contributing to this behavior include: 1. Status Code Override: Historically, calling setResponseStatus(403) followed by throw new Error(...) would often result in a 500 response because the thrown error triggers the runtime to default to a 500 status [1][3][2]. Recent updates (such as those in pull request #6785) aim to preserve the status code when an error is thrown after setResponseStatus is called, provided the environment and router versions are up to date [3][2]. 2. Handling Errors as Responses: If you want to return a specific HTTP status code (like 403) from a server function, the recommended approach is to ensure the response is handled correctly by the framework. Using throw notFound() is supported for 404s [4][5], but for custom statuses like 403, you may need to ensure your error handling strategy aligns with the current version's expectations for status propagation [1][3]. 3. Development Environment Issues: Some users report that unexpected 500 errors occur during SSR or due to misconfigured error handling in development mode [6][7]. Ensuring you are using the latest version of @tanstack/start and @tanstack/router is critical, as several issues regarding error serialization and status code preservation have been actively addressed in recent releases [3][2]. To mitigate this, ensure that: - You are on the most recent version of TanStack Start and Router to benefit from fixes regarding status code preservation [3][2]. - You are using setResponseStatus(403) within the context of the server function or middleware before throwing your error [2][8]. - If you continue to see 500 errors, consider whether the error being thrown is an unhandled exception that the framework is forced to catch and wrap as a 500 [1][6]. For centralized error handling, TanStack Start does not currently have a fully automated global error handler equivalent to some other frameworks; developers often implement manual try-catch blocks or middleware to handle specific domain errors and translate them into appropriate HTTP responses [9][5].

Citations:


🌐 Web query:

"TanStack Start" "createServerFn" "HttpFailError" "403"

💡 Result:

In TanStack Start, the HttpFailError (or similar generic HTTP error) often surfaces when a server function encounters an unhandled exception, resulting in a default 500 status code being returned to the client [1][2][3]. If you are specifically encountering a 403 Forbidden error, it is typically the result of authorization logic failing within your server function or its middleware [4][5]. TanStack Start server functions are same-origin RPC endpoints, and improper configuration or failed authentication/authorization checks will prevent execution [6][7]. Key points regarding 403 errors and error handling in TanStack Start: 1. Authorization Failures: If you use middleware to protect your server functions (e.g., checking session tokens or roles), you may be explicitly throwing a 403 status. If your implementation uses something like throw redirect({ statusCode: 403 }), note that this may result in unexpected behavior where the client receives a 200 OK with a JSON body indicating the redirect/status, rather than an actual HTTP 403 response [4]. 2. Error Handling Limitations: A common pain point in TanStack Start is that throwing standard Errors within a createServerFn handler generally defaults the HTTP response to 500, even if you attempt to call setResponseStatus(403) beforehand [3]. Because TanStack Start serializes errors, standard thrown errors are often captured as generic "500 Internal Server Error" responses by the framework [8][3]. 3. Recommended Patterns: - Use dedicated error types or helper functions if your library version supports them [9]. - For authorization, implement middleware that validates the request context (e.g., user session, roles) before the handler executes [7][5]. - If you need to return specific HTTP status codes (like 403) to the client, you may need to avoid throwing standard errors and instead return a Response object with the desired status if the framework's current architecture allows, or rely on custom middleware that sets the status appropriately before the request completes [9][3]. If you are debugging a specific HttpFailError, check the server-side logs for the actual stack trace, as the client-side error object is often sanitized and only contains minimal information [9][10].

Citations:


Return an HTTP 403 from forbidden schedule access.

throw new Error(...) is not tied to a response status for this server function, and this path currently does not show an explicit 403 mapping. Use an error mechanism that preserves a 403 response, or throw a 403 response directly.

🤖 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 `@apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts` around lines 1411
- 1424, The forbidden branch guarded by canManageCompetition and
isCompetitionTeamMember must return an HTTP 403 response instead of throwing a
generic Error. Replace the throw in the judge-schedule access check with the
project’s established 403 error mechanism or a direct 403 response, preserving
the existing permission message.

Source: Coding guidelines

Comment on lines +1688 to +1705
...new Set(
teamUserIds.length > 0 ? teamUserIds : [registration.userId],
),
]
const confirmedAthleteNames = rosterUserIds
.map((userId) => {
const athlete = athleteUserMap.get(userId)
return [athlete?.firstName, athlete?.lastName]
.filter(Boolean)
.join(" ")
})
.filter(Boolean)
const athleteNames = [
...new Set([
...confirmedAthleteNames,
...parsePendingTeammateNames(registration.pendingTeammates),
]),
].sort((a, b) => a.localeCompare(b))

Copy link
Copy Markdown
Contributor

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

Do not use the registration owner as a team-roster fallback.

When registration.athleteTeamId exists but has no active memberships, Line 1689 adds registration.userId to the roster. A team registration owner can be an organizer or payer rather than an athlete. Use the owner fallback only when athleteTeamId is null.

Proposed fix
-        const rosterUserIds = [
-          ...new Set(
-            teamUserIds.length > 0 ? teamUserIds : [registration.userId],
-          ),
-        ]
+        const rosterUserIds = [
+          ...new Set(
+            registration.athleteTeamId ? teamUserIds : [registration.userId],
+          ),
+        ]
📝 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
...new Set(
teamUserIds.length > 0 ? teamUserIds : [registration.userId],
),
]
const confirmedAthleteNames = rosterUserIds
.map((userId) => {
const athlete = athleteUserMap.get(userId)
return [athlete?.firstName, athlete?.lastName]
.filter(Boolean)
.join(" ")
})
.filter(Boolean)
const athleteNames = [
...new Set([
...confirmedAthleteNames,
...parsePendingTeammateNames(registration.pendingTeammates),
]),
].sort((a, b) => a.localeCompare(b))
...new Set(
registration.athleteTeamId ? teamUserIds : [registration.userId],
),
]
const confirmedAthleteNames = rosterUserIds
.map((userId) => {
const athlete = athleteUserMap.get(userId)
return [athlete?.firstName, athlete?.lastName]
.filter(Boolean)
.join(" ")
})
.filter(Boolean)
const athleteNames = [
...new Set([
...confirmedAthleteNames,
...parsePendingTeammateNames(registration.pendingTeammates),
]),
].sort((a, b) => a.localeCompare(b))
🤖 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 `@apps/wodsmith-start/src/server-fns/judge-scheduling-fns.ts` around lines 1688
- 1705, Update the rosterUserIds construction near confirmedAthleteNames so
registration.userId is used only when registration.athleteTeamId is null; when a
team ID exists, preserve an empty roster if it has no active memberships. Keep
the existing teamUserIds handling and downstream athlete-name processing
unchanged.

Comment on lines +52 to +66
it("falls back to an athlete name when a team name is empty", () => {
const events = scheduleEvents()
const lane = events[0]?.heats[0]?.laneAssignments[0]
if (lane?.registration) lane.registration.teamName = ""

render(
<JudgesScheduleContent
competitionName="Mountain Throwdown"
events={events}
timezone="America/Denver"
/>,
)

expect(screen.getAllByText("Avery Athlete").length).toBeGreaterThan(0)
})

Copy link
Copy Markdown
Contributor

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

Add a unique @lat: reference to each new test.

Each new test needs exactly one nearby # @lat: comment. Each reference must point to a different test-specification leaf.

  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L52-L66: Add the athlete-name fallback specification reference.
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L68-L101: Add the selection-reset specification reference.
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L103-L147: Add the invitation-backed packet specification reference.
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L149-L169: Add the blank division-brief specification reference.
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L171-L213: Add the delimiter-safe brief grouping specification reference.
📍 Affects 1 file
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L52-L66 (this comment)
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L68-L101
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L103-L147
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L149-L169
  • apps/wodsmith-start/test/components/judges-schedule-content.test.tsx#L171-L213
🤖 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 `@apps/wodsmith-start/test/components/judges-schedule-content.test.tsx` around
lines 52 - 66, Add exactly one nearby unique # `@lat`: reference to each of the
five tests in
apps/wodsmith-start/test/components/judges-schedule-content.test.tsx: lines
52-66 for the athlete-name fallback specification, 68-101 for selection reset,
103-147 for invitation-backed packet, 149-169 for blank division brief, and
171-213 for delimiter-safe brief grouping. Ensure every reference targets a
different test-specification leaf.

Source: Coding guidelines

@zacjones93
zacjones93 merged commit 8362e3d into main Aug 7, 2026
16 checks passed
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