Skip to content

feat: add division cutoff rank with leaderboard line#384

Open
zacjones93 wants to merge 3 commits intomainfrom
zac/competition-division-cutoff
Open

feat: add division cutoff rank with leaderboard line#384
zacjones93 wants to merge 3 commits intomainfrom
zac/competition-division-cutoff

Conversation

@zacjones93
Copy link
Copy Markdown
Contributor

@zacjones93 zacjones93 commented Apr 11, 2026

Summary

  • Adds a configurable cutoff rank that renders a bold orange line on the leaderboard after the Nth-ranked athlete (e.g., "top 10 advance to finals")
  • Uses the same competition-default + per-division override pattern as capacity (maxSpots)
  • Two new DB columns: competitionsTable.defaultCutoffRank and competitionDivisionsTable.cutoffRank

Changes

Schema:

  • defaultCutoffRank: int() on competitionsTable — competition-wide default
  • cutoffRank: int() on competitionDivisionsTable — per-division override (null = use default)

Server functions:

  • Extended updateCompetitionDefaultCapacityFn to accept defaultCutoffRank
  • New updateDivisionCutoffFn for per-division cutoff overrides
  • Extended getCompetitionDivisionsWithCountsFn and getPublicCompetitionDivisionsFn to return cutoff data

Organizer UI:

  • New "Default cutoff rank" input in CapacitySettingsForm
  • Per-division cutoff rank input in OrganizerDivisionItem collapsible section

Leaderboard:

  • 3px orange line in CompetitionLeaderboardTable and OnlineCompetitionLeaderboardTable
  • Both desktop table and mobile list views
  • Only shown on overall view (hidden in single-event view)
  • Handles ties correctly — line appears after all athletes with rank <= cutoff

Test plan

  • pnpm db:push to apply schema changes
  • Set competition default cutoff on organizer divisions page, verify save
  • Set per-division override, verify it takes precedence
  • View leaderboard — orange line at correct rank position
  • Test: ties at boundary, cutoff > total entries, null cutoff, single event view
  • Test mobile view
  • Test online competition leaderboard

🤖 Generated with Claude Code


Summary by cubic

Adds a configurable leaderboard cutoff rank that draws a bold orange line after the Nth-ranked athlete. Uses a competition default with per-division overrides, shows only on overall view, and handles ties.

  • New Features

    • Schema: competitionsTable.defaultCutoffRank, competitionDivisionsTable.cutoffRank.
    • Server: extended updateCompetitionDefaultCapacityFn to accept defaultCutoffRank; added updateDivisionCutoffFn; cutoff returned by getCompetitionDivisionsWithCountsFn and getPublicCompetitionDivisionsFn.
    • Organizer UI: default cutoff input in CapacitySettingsForm; per-division cutoff input in OrganizerDivisionItem (wired via OrganizerDivisionManager).
    • Leaderboard: 3px orange cutoff line in CompetitionLeaderboardTable and OnlineCompetitionLeaderboardTable (desktop + mobile). Only on overall view; line appears after all athletes at the cutoff to account for ties.
  • Migration

    • Run pnpm db:push to add new columns.
    • Optionally set a competition default or per-division cutoff; leave blank to disable the line.

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

Summary by CodeRabbit

  • New Features
    • Leaderboard cutoff rank configuration added: organizers can now set a default cutoff rank at the competition level and customize the cutoff for individual divisions
    • Leaderboards display a bold orange separator line at the cutoff rank boundary (visible in overall rankings only, not in event-specific views)

zacjones93 and others added 3 commits April 10, 2026 22:25
Add configurable cutoff rank that renders a bold orange line on the
leaderboard after the Nth-ranked athlete. Uses the same two-level
fallback as capacity: competition-wide default with per-division override.

- Schema: defaultCutoffRank on competitionsTable, cutoffRank on competitionDivisionsTable
- Organizer UI: cutoff input in CapacitySettingsForm and per-division items
- Leaderboard: orange line in both in-person and online tables (desktop + mobile)
- Only shown on overall view, hidden in single-event view
- Handles ties correctly (line after all tied athletes at cutoff)

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>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Walkthrough

This PR introduces a leaderboard cutoff rank feature allowing organizers to set a default cutoff rank per competition and override it per division. Visual orange separators mark the cutoff boundary on leaderboards. Changes span database schema, UI components for configuration, leaderboard rendering logic, and server-side persistence.

Changes

Cohort / File(s) Summary
Database Schema
apps/wodsmith-start/src/db/schemas/commerce.ts, apps/wodsmith-start/src/db/schemas/competitions.ts
Added nullable cutoffRank column to competitionDivisionsTable and defaultCutoffRank to competitionsTable to store division-level and competition-wide cutoff configuration.
Leaderboard Components
apps/wodsmith-start/src/components/competition-leaderboard-table.tsx, apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx
Added cutoffRank prop to both components; implemented conditional orange separator rendering at the cutoff boundary by detecting when current entry's overallRank crosses the threshold. Refactored row mapping to use indices for next-item lookahead in online variant.
Division Management UI
apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx, apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx
Extended OrganizerDivisionItem with numeric input for cutoff rank (validating >= 1 or null); added state syncing and save callback. Updated OrganizerDivisionManager to track cutoffRank per division, implement optimistic updates, call updateDivisionCutoffFn for persistence, and display toast notifications.
Settings & Configuration
apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx, apps/wodsmith-start/src/routes/compete/organizer/$competitionId/divisions.tsx, apps/wodsmith-start/src/routes/compete/organizer/$competitionId/settings.tsx
Extended CapacitySettingsForm with "Default cutoff rank" input field and validation; added defaultCutoffRank to the divisions route loader and threaded it through both CapacitySettingsForm and OrganizerDivisionManager.
Leaderboard Data Flow
apps/wodsmith-start/src/components/leaderboard-page-content.tsx
Derives cutoffRank from selected division and passes it to both leaderboard table variants for rendering cutoff separator.
Server Functions
apps/wodsmith-start/src/server-fns/competition-detail-fns.ts, apps/wodsmith-start/src/server-fns/competition-fns.ts, apps/wodsmith-start/src/server-fns/competition-divisions-fns.ts
Updated competition detail/list queries to include defaultCutoffRank; added new updateDivisionCutoffFn server function with validation, authentication, and logic to upsert division cutoff rank; extended division DTOs to include cutoffRank using precedence division.cutoffRank ?? competition.defaultCutoffRank ?? null.
Tests & Documentation
apps/wodsmith-start/test/components/leaderboard-page-content.test.tsx, lat.md/domain.md, lat.md/organizer-dashboard.md
Updated mock division fixtures to include cutoffRank: null; documented two-level cutoff configuration hierarchy (competition default overridable per division) and orange separator visualization on leaderboards.

Sequence Diagram

sequenceDiagram
    actor Organizer
    participant UI as OrganizerDivisionItem
    participant Manager as OrganizerDivisionManager
    participant Server as updateDivisionCutoffFn
    participant DB as Database
    
    Organizer->>UI: Enter cutoff rank value
    UI->>Manager: onCutoffRankSave(rank)
    Manager->>Manager: Optimistic UI update
    Manager->>Server: updateDivisionCutoffFn(divisionId, rank)
    Server->>Server: Validate & authenticate
    Server->>DB: Upsert cutoffRank
    DB-->>Server: Confirm
    Server-->>Manager: Success
    Manager->>Manager: Show success toast
    
    Note over Organizer,DB: Division cutoff now configured
    
    actor Athlete
    participant LeaderboardPage as LeaderboardPageContent
    participant Table as CompetitionLeaderboardTable
    participant Renderer as UI Render
    
    Athlete->>LeaderboardPage: View leaderboard
    LeaderboardPage->>LeaderboardPage: Derive cutoffRank from division
    LeaderboardPage->>Table: Pass cutoffRank prop
    Table->>Renderer: Render rows + orange separator at boundary
    Renderer-->>Athlete: Display leaderboard with cutoff line
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hops gleefully
A cutoff line in orange so bright,
Marks where the rankings reach their height,
Per division, per competition's might,
Leaderboards configured just right! ✨🏆

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add division cutoff rank with leaderboard line' directly describes the main feature being added—a configurable cutoff rank mechanism that displays a visual line on leaderboards. This aligns with the core changes across schema, server functions, organizer UI, and leaderboard rendering components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 zac/competition-division-cutoff

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 and usage tips.

@github-actions
Copy link
Copy Markdown

🚀 Preview Deployed

URL: https://wodsmith-app-pr-384.zacjones93.workers.dev

Detail Value
Commit 05308f7
Stage pr-384
Deployed 2026-04-11T04:32:57.669Z

This comment is automatically updated on each push to this PR.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

4 issues found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/wodsmith-start/src/components/competition-leaderboard-table.tsx">

<violation number="1" location="apps/wodsmith-start/src/components/competition-leaderboard-table.tsx:835">
P2: Cutoff line placement is incorrect when the leaderboard is sorted by anything other than overall-rank ascending.</violation>
</file>

<file name="apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx">

<violation number="1" location="apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx:105">
P2: `hasChanges` does not reject cutoff ranks below 1, so invalid values enable Save and only fail later on submit.</violation>
</file>

<file name="apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx">

<violation number="1" location="apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx:292">
P2: Rollback uses `??` with a nullable original value, so failed saves do not revert when the previous cutoff was `null`.</violation>
</file>

<file name="apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx">

<violation number="1" location="apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx:1264">
P2: Desktop cutoff line logic is also incorrect unless sorting is overall-rank ascending.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

const showCutoff =
cutoffRank != null &&
!selectedEventId &&
entry.overallRank <= cutoffRank &&
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 11, 2026

Choose a reason for hiding this comment

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

P2: Cutoff line placement is incorrect when the leaderboard is sorted by anything other than overall-rank ascending.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/src/components/competition-leaderboard-table.tsx, line 835:

<comment>Cutoff line placement is incorrect when the leaderboard is sorted by anything other than overall-rank ascending.</comment>

<file context>
@@ -825,14 +827,26 @@ export function CompetitionLeaderboardTable({
+              const showCutoff =
+                cutoffRank != null &&
+                !selectedEventId &&
+                entry.overallRank <= cutoffRank &&
+                (!nextEntry || nextEntry.overallRank > cutoffRank)
+              return (
</file context>
Fix with Cubic

const parsedTotal = maxTotal.trim() === "" ? null : Number(maxTotal)
if (parsedTotal !== null && (!Number.isFinite(parsedTotal) || !Number.isInteger(parsedTotal))) return false
const parsedCutoff = cutoffRank.trim() === "" ? null : parseInt(cutoffRank, 10)
if (parsedCutoff !== null && Number.isNaN(parsedCutoff)) return false
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 11, 2026

Choose a reason for hiding this comment

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

P2: hasChanges does not reject cutoff ranks below 1, so invalid values enable Save and only fail later on submit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx, line 105:

<comment>`hasChanges` does not reject cutoff ranks below 1, so invalid values enable Save and only fail later on submit.</comment>

<file context>
@@ -85,9 +101,12 @@ export function CapacitySettingsForm({ competition }: Props) {
     const parsedTotal = maxTotal.trim() === "" ? null : Number(maxTotal)
     if (parsedTotal !== null && (!Number.isFinite(parsedTotal) || !Number.isInteger(parsedTotal))) return false
+    const parsedCutoff = cutoffRank.trim() === "" ? null : parseInt(cutoffRank, 10)
+    if (parsedCutoff !== null && Number.isNaN(parsedCutoff)) return false
     return (
       parsed !== competition.defaultMaxSpotsPerDivision ||
</file context>
Suggested change
if (parsedCutoff !== null && Number.isNaN(parsedCutoff)) return false
if (parsedCutoff !== null && (Number.isNaN(parsedCutoff) || parsedCutoff < 1)) return false
Fix with Cubic

setDivisions((prev) =>
prev.map((d) =>
d.id === divisionId
? { ...d, cutoffRank: original?.cutoffRank ?? newCutoffRank }
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 11, 2026

Choose a reason for hiding this comment

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

P2: Rollback uses ?? with a nullable original value, so failed saves do not revert when the previous cutoff was null.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx, line 292:

<comment>Rollback uses `??` with a nullable original value, so failed saves do not revert when the previous cutoff was `null`.</comment>

<file context>
@@ -255,6 +259,43 @@ export function OrganizerDivisionManager({
+      setDivisions((prev) =>
+        prev.map((d) =>
+          d.id === divisionId
+            ? { ...d, cutoffRank: original?.cutoffRank ?? newCutoffRank }
+            : d,
+        ),
</file context>
Suggested change
? { ...d, cutoffRank: original?.cutoffRank ?? newCutoffRank }
? { ...d, cutoffRank: original ? original.cutoffRank : newCutoffRank }
Fix with Cubic

cutoffRank != null &&
!selectedEventId &&
entry.overallRank <= cutoffRank &&
(!nextRow || nextRow.original.overallRank > cutoffRank)
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 11, 2026

Choose a reason for hiding this comment

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

P2: Desktop cutoff line logic is also incorrect unless sorting is overall-rank ascending.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx, line 1264:

<comment>Desktop cutoff line logic is also incorrect unless sorting is overall-rank ascending.</comment>

<file context>
@@ -1239,43 +1253,61 @@ export function OnlineCompetitionLeaderboardTable({
+                  cutoffRank != null &&
+                  !selectedEventId &&
+                  entry.overallRank <= cutoffRank &&
+                  (!nextRow || nextRow.original.overallRank > cutoffRank)
+                return (
+                  <Fragment key={row.id}>
</file context>
Suggested change
(!nextRow || nextRow.original.overallRank > cutoffRank)
(!nextRow || nextRow.original.overallRank > cutoffRank) &&
currentSortId === "overallRank" &&
!currentSortDesc
Fix with Cubic

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
apps/wodsmith-start/src/server-fns/competition-divisions-fns.ts (1)

1878-1898: ⚠️ Potential issue | 🟠 Major

Preserve cutoffRank when migrating division config to a new scaling group.

This migration now carries feeCents, description, and maxSpots, but it never copies oldConfig.cutoffRank. Any per-division cutoff override will be lost after switching the competition to another scaling group or series template. Please migrate cutoffRank alongside the rest of the division config.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/server-fns/competition-divisions-fns.ts` around lines
1878 - 1898, The insert that migrates a division config (inside the transaction
using tx.query.competitionDivisionsTable.findFirst to get oldConfig and
tx.insert(competitionDivisionsTable).values to create newConfig) currently
copies feeCents, description, and maxSpots but omits cutoffRank; modify the
values passed to tx.insert(...) to also include cutoffRank: oldConfig.cutoffRank
so any per-division cutoff override is preserved when moving to the new
divisionId/scaling group.
🧹 Nitpick comments (1)
apps/wodsmith-start/test/components/leaderboard-page-content.test.tsx (1)

82-95: Add cutoff-specific assertions (and @lat links) in this test suite.

This fixture update is necessary, but the new cutoff behavior (fallback/override/tie boundary placement) still isn’t asserted here. Please add at least one focused test that proves cutoffRank is propagated/rendered correctly.

As per coding guidelines, **/test/**/*.{ts,tsx,js} requires // @lat: [[section-id]] comments next to relevant tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/test/components/leaderboard-page-content.test.tsx` around
lines 82 - 95, Add a focused test in the leaderboard-page-content.test.tsx suite
that renders LeaderboardPageContent (or the existing test case that uses the
updated fixture entries "div-1"/"div-2") with entries having cutoffRank set
(including a tie/boundary and a null case), then assert the rendered output
shows the expected cutoffRank values for each entry (e.g., by querying the DOM
for the cutoff number or a data-testid/label associated with that entry id) to
prove propagation/override/fallback behavior; also add the required test marker
comment // `@lat`: [[section-id]] immediately next to the new or updated test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/wodsmith-start/src/components/competition-leaderboard-table.tsx`:
- Around line 902-929: The cutoff marker logic using table.getRowModel().rows
and showCutoff (checking cutoffRank, selectedEventId, entry.overallRank, and
nextRow.original.overallRank) can display incorrectly after user resorting;
update the render condition so the cutoff only appears when the table is
currently sorted by overallRank in ascending order (or recompute cutoff
positions from a dedicated rank-sorted row model). Concretely, detect the active
sort state via the table instance (e.g., table.getState().sorting) and only
evaluate the existing showCutoff condition when the first sort column is
"overallRank" and direction is "asc"; alternatively build a separate rows array
sorted by overallRank and use that to compute the cutoff instead of
table.getRowModel().rows, ensuring the orange divider is stable when sorting
changes.

In `@apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx`:
- Around line 345-359: The blur handler for the number input truncates decimals
by using parseInt, causing mismatches between the displayed value and saved
value; replace parseInt(localCutoffRank, 10) with Number(localCutoffRank) and
validate using Number.isInteger so decimals are rejected (or reset) rather than
silently truncated; update the logic in the onBlur block that computes newVal
and the subsequent validation checks around localCutoffRank, cutoffRank,
onCutoffRankSave, and setLocalCutoffRank to use Number(...) +
Number.isInteger(...) and the same newVal < 1 and NaN checks before calling
onCutoffRankSave.

In `@apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx`:
- Around line 262-296: The rollback uses a stale/null-hostile value from
initialDivisions; modify handleCutoffRankSave to read and store the pre-edit
cutoff from the live divisions state (use the current divisions lookup before
calling setDivisions) into a local variable (e.g., previousCutoff) and use that
exact value in the catch rollback instead of original?.cutoffRank ??
newCutoffRank; ensure updateDivisionCutoffFn is still awaited and that after a
successful save you also update whatever source-of-truth (if any) you use for
initialDivisions so future errors can rollback correctly.

In `@apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx`:
- Around line 1256-1307: Summary: The cutoff separator is computed from the
current visual row order, so when the table is sorted by other columns the top-N
overall athletes are non-contiguous and the separator is wrong. Fix: change the
showCutoff logic to only render when the table is sorted by overallRank
ascending or compute cutoff from a rank-sorted slice. Specifically, in the
component use table.getState().sorting (or table.getState().sorting[0]) to
detect a single active sort whose id matches the overall-rank column id (the
column that provides entry.overallRank) and direction === "asc", and only then
allow the existing showCutoff code to run; alternatively, derive
rowsSortedByRank =
[...table.getRowModel().rows].sort((a,b)=>a.original.overallRank -
b.original.overallRank) and compute whether entry is the last within the top
cutoffRank using that sorted array instead of the visual rows. Apply this change
where showCutoff is computed (referencing showCutoff, cutoffRank,
entry.overallRank, table.getRowModel(), and table.getState().sorting).

In `@apps/wodsmith-start/src/db/schemas/commerce.ts`:
- Around line 161-162: The cutoffRank field on competition_divisions currently
uses int() and allows 0/negative values; change its schema to enforce the same
rank-domain constraints as the competition default (e.g., replace cutoffRank:
int() with cutoffRank: int().min(1).nullable() or the project’s equivalent
validation chain used by competition.defaultCutoffRank) so only positive ordinal
ranks or null are permitted; update any related tests or callers that assume
0/negative values.

In `@apps/wodsmith-start/src/db/schemas/competitions.ts`:
- Around line 132-133: The defaultCutoffRank field currently uses int(), which
allows 0/negative values; change the schema for defaultCutoffRank on the
competitions schema to only accept null or positive integers (>0) (e.g., use a
validator like int().min(1) / positiveInt() or equivalent) and add a DB-level
CHECK constraint (DEFAULT_CUTOFF_RANK IS NULL OR DEFAULT_CUTOFF_RANK > 0) so
both the application validator and persistence layer enforce the same domain;
update any related input/DTO validators (e.g., create/update competition inputs)
to mirror this rule.

In
`@apps/wodsmith-start/src/routes/compete/organizer/`$competitionId/-components/capacity-settings-form.tsx:
- Around line 70-79: Replace parseInt-based parsing of cutoffRank with numeric
validation using Number() and Number.isFinite/Number.isInteger checks: treat an
empty cutoffRank string as null, otherwise call Number(cutoffRank) and ensure
Number.isFinite(parsed) && Number.isInteger(parsed) && parsed >= 1; if
validation fails show the same toast and abort. Mirror this same
parsing/validation for any hasChanges comparison so the change detection
compares the canonical parsedCutoff (or null) rather than the truncated parseInt
result; follow the same pattern already used for maxTotal (Number +
Number.isFinite + Number.isInteger).

In `@lat.md/domain.md`:
- Line 48: The doc text incorrectly states that division config is stored in the
competition `settings` JSON; update the sentence in lat.md/domain.md to reflect
that division-specific registration fee, capacity (max spots), and leaderboard
cutoff rank are stored on the competition_divisions data model/ table (e.g.,
`competition_divisions`) rather than in the competition `settings` JSON, while
keeping that athletes register into a specific division and noting that these
fields override the competition defaults.

In `@lat.md/organizer-dashboard.md`:
- Around line 29-33: Replace the raw code references in this section with wiki
links so the knowledge graph picks them up: convert
"competitionsTable.defaultCutoffRank" and "competitionDivisionsTable.cutoffRank"
to wiki links (e.g. [[competitionsTable.defaultCutoffRank]] /
[[competitionDivisionsTable.cutoffRank]]), change
"getPublicCompetitionDivisionsFn" to [[getPublicCompetitionDivisionsFn]] and the
component names "CompetitionLeaderboardTable" and
"OnlineCompetitionLeaderboardTable" to [[CompetitionLeaderboardTable]] and
[[OnlineCompetitionLeaderboardTable]] (use aliasing if you want different
display text); keep the surrounding explanatory text intact and ensure the
overall/single-event view wording remains unchanged.

---

Outside diff comments:
In `@apps/wodsmith-start/src/server-fns/competition-divisions-fns.ts`:
- Around line 1878-1898: The insert that migrates a division config (inside the
transaction using tx.query.competitionDivisionsTable.findFirst to get oldConfig
and tx.insert(competitionDivisionsTable).values to create newConfig) currently
copies feeCents, description, and maxSpots but omits cutoffRank; modify the
values passed to tx.insert(...) to also include cutoffRank: oldConfig.cutoffRank
so any per-division cutoff override is preserved when moving to the new
divisionId/scaling group.

---

Nitpick comments:
In `@apps/wodsmith-start/test/components/leaderboard-page-content.test.tsx`:
- Around line 82-95: Add a focused test in the leaderboard-page-content.test.tsx
suite that renders LeaderboardPageContent (or the existing test case that uses
the updated fixture entries "div-1"/"div-2") with entries having cutoffRank set
(including a tie/boundary and a null case), then assert the rendered output
shows the expected cutoffRank values for each entry (e.g., by querying the DOM
for the cutoff number or a data-testid/label associated with that entry id) to
prove propagation/override/fallback behavior; also add the required test marker
comment // `@lat`: [[section-id]] immediately next to the new or updated test.
🪄 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: CHILL

Plan: Pro

Run ID: be573c83-5867-4b54-b541-4d835e15960c

📥 Commits

Reviewing files that changed from the base of the PR and between 142c844 and 0634494.

📒 Files selected for processing (16)
  • apps/wodsmith-start/src/components/competition-leaderboard-table.tsx
  • apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx
  • apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx
  • apps/wodsmith-start/src/components/leaderboard-page-content.tsx
  • apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx
  • apps/wodsmith-start/src/db/schemas/commerce.ts
  • apps/wodsmith-start/src/db/schemas/competitions.ts
  • apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx
  • apps/wodsmith-start/src/routes/compete/organizer/$competitionId/divisions.tsx
  • apps/wodsmith-start/src/routes/compete/organizer/$competitionId/settings.tsx
  • apps/wodsmith-start/src/server-fns/competition-detail-fns.ts
  • apps/wodsmith-start/src/server-fns/competition-divisions-fns.ts
  • apps/wodsmith-start/src/server-fns/competition-fns.ts
  • apps/wodsmith-start/test/components/leaderboard-page-content.test.tsx
  • lat.md/domain.md
  • lat.md/organizer-dashboard.md

Comment on lines +902 to +929
table.getRowModel().rows.map((row, rowIdx) => {
const entry = row.original
const rows = table.getRowModel().rows
const nextRow = rows[rowIdx + 1]
const showCutoff =
cutoffRank != null &&
!selectedEventId &&
entry.overallRank <= cutoffRank &&
(!nextRow || nextRow.original.overallRank > cutoffRank)
return (
<Fragment key={row.id}>
<TableRow className="table-row">
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} className="table-cell">
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
{showCutoff && (
<tr>
<td colSpan={columns.length} className="p-0">
<div className="h-[3px] bg-orange-500" />
</td>
</tr>
)}
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.

⚠️ Potential issue | 🟠 Major

Hide or recompute the cutoff when the table is re-sorted.

This boundary check runs against the current sorted row model, so as soon as the user sorts overall view by athlete/event or flips rank descending, the orange line can land in the middle of the table or disappear entirely. The cutoff marker should only render in ascending overallRank order, or be computed from a separately rank-sorted view.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/components/competition-leaderboard-table.tsx` around
lines 902 - 929, The cutoff marker logic using table.getRowModel().rows and
showCutoff (checking cutoffRank, selectedEventId, entry.overallRank, and
nextRow.original.overallRank) can display incorrectly after user resorting;
update the render condition so the cutoff only appears when the table is
currently sorted by overallRank in ascending order (or recompute cutoff
positions from a dedicated rank-sorted row model). Concretely, detect the active
sort state via the table instance (e.g., table.getState().sorting) and only
evaluate the existing showCutoff condition when the first sort column is
"overallRank" and direction is "asc"; alternatively build a separate rows array
sorted by overallRank and use that to compute the cutoff instead of
table.getRowModel().rows, ensuring the orange divider is stable when sorting
changes.

Comment on lines +345 to +359
onBlur={() => {
const newVal =
localCutoffRank.trim() === ""
? null
: parseInt(localCutoffRank, 10)
if (newVal !== cutoffRank) {
if (
newVal !== null &&
(Number.isNaN(newVal) || newVal < 1)
) {
setLocalCutoffRank(cutoffRank?.toString() ?? "")
return
}
onCutoffRankSave(newVal)
}
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node - <<'NODE'
for (const raw of ["1.5", "2.9", "1e2"]) {
  console.log({
    raw,
    parsedInt: parseInt(raw, 10),
    numeric: Number(raw),
    isInteger: Number.isInteger(Number(raw)),
  })
}
NODE

Repository: wodsmith/thewodapp

Length of output: 243


🏁 Script executed:

cat -n apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx | sed -n '330,370p'

Repository: wodsmith/thewodapp

Length of output: 1949


🏁 Script executed:

rg -B 20 "localCutoffRank.trim" apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx

Repository: wodsmith/thewodapp

Length of output: 890


🏁 Script executed:

rg "cutoffRank" apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx -A 2 -B 2

Repository: wodsmith/thewodapp

Length of output: 1533


This blur handler silently truncates decimal input from the number field.

The <Input type="number"> field allows users to type decimal values (e.g., 1.5), but the blur handler uses parseInt(), which truncates to an integer. If a user types 1.5 and the current cutoffRank is 1, the parsed value equals the current value, so nothing is saved—but the UI still shows 1.5, making it appear the input was ignored. When cutoffRank differs, the truncated value gets saved silently. Use Number() and validate with Number.isInteger() instead:

const newVal =
  localCutoffRank.trim() === ""
    ? null
    : Number(localCutoffRank)
if (newVal !== cutoffRank) {
  if (
    newVal !== null &&
    (Number.isNaN(newVal) || !Number.isInteger(newVal) || newVal < 1)
  ) {
    setLocalCutoffRank(cutoffRank?.toString() ?? "")
    return
  }
  onCutoffRankSave(newVal)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/components/divisions/organizer-division-item.tsx`
around lines 345 - 359, The blur handler for the number input truncates decimals
by using parseInt, causing mismatches between the displayed value and saved
value; replace parseInt(localCutoffRank, 10) with Number(localCutoffRank) and
validate using Number.isInteger so decimals are rejected (or reset) rather than
silently truncated; update the logic in the onBlur block that computes newVal
and the subsequent validation checks around localCutoffRank, cutoffRank,
onCutoffRankSave, and setLocalCutoffRank to use Number(...) +
Number.isInteger(...) and the same newVal < 1 and NaN checks before calling
onCutoffRankSave.

Comment on lines +262 to +296
const handleCutoffRankSave = async (
divisionId: string,
newCutoffRank: number | null,
) => {
const original = initialDivisions.find((d) => d.id === divisionId)
if (original && original.cutoffRank === newCutoffRank) return

setDivisions((prev) =>
prev.map((d) =>
d.id === divisionId ? { ...d, cutoffRank: newCutoffRank } : d,
),
)

try {
await updateDivisionCutoffFn({
data: {
teamId,
competitionId,
divisionId,
cutoffRank: newCutoffRank,
},
})
toast.success("Division cutoff updated")
} catch (error) {
toast.error(
error instanceof Error ? error.message : "Failed to update cutoff",
)
setDivisions((prev) =>
prev.map((d) =>
d.id === divisionId
? { ...d, cutoffRank: original?.cutoffRank ?? newCutoffRank }
: d,
),
)
}
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.

⚠️ Potential issue | 🟠 Major

Rollback uses a stale/null-hostile source value.

This handler captures original from initialDivisions, then reverts with original?.cutoffRank ?? newCutoffRank. If the prior value was null, the catch path keeps the optimistic value instead of rolling back, and after one successful save initialDivisions is also stale for subsequent failures. Capture the pre-edit value from current state before mutating and restore that exact value on error.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/components/divisions/organizer-division-manager.tsx`
around lines 262 - 296, The rollback uses a stale/null-hostile value from
initialDivisions; modify handleCutoffRankSave to read and store the pre-edit
cutoff from the live divisions state (use the current divisions lookup before
calling setDivisions) into a local variable (e.g., previousCutoff) and use that
exact value in the catch rollback instead of original?.cutoffRank ??
newCutoffRank; ensure updateDivisionCutoffFn is still awaited and that after a
successful save you also update whatever source-of-truth (if any) you use for
initialDivisions so future errors can rollback correctly.

Comment on lines +1256 to +1307
table.getRowModel().rows.map((row, rowIdx) => {
const entry = row.original
const rows = table.getRowModel().rows
const nextRow = rows[rowIdx + 1]
const showCutoff =
cutoffRank != null &&
!selectedEventId &&
entry.overallRank <= cutoffRank &&
(!nextRow || nextRow.original.overallRank > cutoffRank)
return (
<Fragment key={row.id}>
<TableRow
className={cn(
"table-row",
row.getIsExpanded() && "border-b-0",
hasExpandableContent(row.original, selectedEventId) &&
"cursor-pointer",
)}
onClick={() => {
if (
hasExpandableContent(row.original, selectedEventId)
) {
row.toggleExpanded()
}
}}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} className="table-cell">
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
{row.getIsExpanded() && (
<ExpandedVideoRow
row={row}
selectedEventId={selectedEventId}
columnsCount={columns.length}
voteCounts={voteCounts}
isLoggedIn={isLoggedIn}
currentUserId={currentUserId}
/>
)}
onClick={() => {
if (hasExpandableContent(row.original, selectedEventId)) {
row.toggleExpanded()
}
}}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} className="table-cell">
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
{row.getIsExpanded() && (
<ExpandedVideoRow
row={row}
selectedEventId={selectedEventId}
columnsCount={columns.length}
voteCounts={voteCounts}
isLoggedIn={isLoggedIn}
currentUserId={currentUserId}
/>
)}
</Fragment>
))
{showCutoff && (
<tr>
<td colSpan={columns.length} className="p-0">
<div className="h-[3px] bg-orange-500" />
</td>
</tr>
)}
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.

⚠️ Potential issue | 🟠 Major

The cutoff line breaks when overall rows are sorted by something else.

showCutoff is derived from the current row order, so sorting overall view by athlete/event or reversing rank order makes the top-N athletes non-contiguous and the separator becomes incorrect. This needs to be gated to ascending overallRank order, or computed from a separate rank-sorted slice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/components/online-competition-leaderboard-table.tsx`
around lines 1256 - 1307, Summary: The cutoff separator is computed from the
current visual row order, so when the table is sorted by other columns the top-N
overall athletes are non-contiguous and the separator is wrong. Fix: change the
showCutoff logic to only render when the table is sorted by overallRank
ascending or compute cutoff from a rank-sorted slice. Specifically, in the
component use table.getState().sorting (or table.getState().sorting[0]) to
detect a single active sort whose id matches the overall-rank column id (the
column that provides entry.overallRank) and direction === "asc", and only then
allow the existing showCutoff code to run; alternatively, derive
rowsSortedByRank =
[...table.getRowModel().rows].sort((a,b)=>a.original.overallRank -
b.original.overallRank) and compute whether entry is the last within the top
cutoffRank using that sorted array instead of the visual rows. Apply this change
where showCutoff is computed (referencing showCutoff, cutoffRank,
entry.overallRank, table.getRowModel(), and table.getState().sorting).

Comment on lines +161 to +162
// Cutoff rank for this division (null = use competition default)
cutoffRank: int(),
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.

⚠️ Potential issue | 🟡 Minor

Apply rank-domain constraints to competition_divisions.cutoffRank as well.

At Line 162, this field currently allows negative values (and 0). Since this is an ordinal rank, persisting invalid values should be prevented consistently with the competition default cutoff.

Suggested schema hardening
-    cutoffRank: int(),
+    cutoffRank: int({ unsigned: true }),
📝 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
// Cutoff rank for this division (null = use competition default)
cutoffRank: int(),
// Cutoff rank for this division (null = use competition default)
cutoffRank: int({ unsigned: true }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/db/schemas/commerce.ts` around lines 161 - 162, The
cutoffRank field on competition_divisions currently uses int() and allows
0/negative values; change its schema to enforce the same rank-domain constraints
as the competition default (e.g., replace cutoffRank: int() with cutoffRank:
int().min(1).nullable() or the project’s equivalent validation chain used by
competition.defaultCutoffRank) so only positive ordinal ranks or null are
permitted; update any related tests or callers that assume 0/negative values.

Comment on lines +132 to +133
// Cutoff: default leaderboard cutoff rank per division (null = no cutoff line)
defaultCutoffRank: int(),
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.

⚠️ Potential issue | 🟡 Minor

Constrain defaultCutoffRank to valid rank values.

At Line 133, int() permits negative values (and 0), which are invalid for rank semantics and can create ambiguous UI behavior. Please enforce a positive domain at persistence boundaries (DB and/or validator).

Suggested schema hardening
-    defaultCutoffRank: int(),
+    defaultCutoffRank: int({ unsigned: true }),
📝 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
// Cutoff: default leaderboard cutoff rank per division (null = no cutoff line)
defaultCutoffRank: int(),
// Cutoff: default leaderboard cutoff rank per division (null = no cutoff line)
defaultCutoffRank: int({ unsigned: true }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/wodsmith-start/src/db/schemas/competitions.ts` around lines 132 - 133,
The defaultCutoffRank field currently uses int(), which allows 0/negative
values; change the schema for defaultCutoffRank on the competitions schema to
only accept null or positive integers (>0) (e.g., use a validator like
int().min(1) / positiveInt() or equivalent) and add a DB-level CHECK constraint
(DEFAULT_CUTOFF_RANK IS NULL OR DEFAULT_CUTOFF_RANK > 0) so both the application
validator and persistence layer enforce the same domain; update any related
input/DTO validators (e.g., create/update competition inputs) to mirror this
rule.

Comment on lines +70 to +79
const parsedCutoff = cutoffRank.trim() === "" ? null : parseInt(cutoffRank, 10)

if (
parsedCutoff !== null &&
(Number.isNaN(parsedCutoff) || parsedCutoff < 1)
) {
toast.error("Cutoff rank must be 1 or higher")
setIsSubmitting(false)
return
}
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node - <<'NODE'
for (const raw of ["10.5", "1e2", "08"]) {
  const parsedInt = parseInt(raw, 10)
  const numeric = Number(raw)
  console.log({ raw, parsedInt, numeric, isInteger: Number.isInteger(numeric) })
}
NODE

Repository: wodsmith/thewodapp

Length of output: 242


🏁 Script executed:

fd -type f "capacity-settings-form.tsx"

Repository: wodsmith/thewodapp

Length of output: 232


🏁 Script executed:

fd "capacity-settings-form.tsx"

Repository: wodsmith/thewodapp

Length of output: 164


🏁 Script executed:

wc -l "apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx"

Repository: wodsmith/thewodapp

Length of output: 181


🏁 Script executed:

git ls-files | grep "capacity-settings-form.tsx"

Repository: wodsmith/thewodapp

Length of output: 164


🏁 Script executed:

cat -n 'apps/wodsmith-start/src/routes/compete/organizer/$competitionId/-components/capacity-settings-form.tsx' | sed -n '65,115p'

Repository: wodsmith/thewodapp

Length of output: 2114


Reject decimal/exponent cutoff inputs instead of truncating them.

parseInt() silently coerces 10.5 to 10 and 1e2 to 1, allowing invalid cutoff values to save. The same truncation also leaks into hasChanges, masking whether the input actually changed.

Note: maxTotal already uses Number() with Number.isFinite() and Number.isInteger() checks (lines 102–103)—apply the same pattern to cutoffRank for consistency.

Suggested fix
-      const parsedCutoff = cutoffRank.trim() === "" ? null : parseInt(cutoffRank, 10)
+      const parsedCutoff = cutoffRank.trim() === "" ? null : Number(cutoffRank)

       if (
         parsedCutoff !== null &&
-        (Number.isNaN(parsedCutoff) || parsedCutoff < 1)
+        (!Number.isFinite(parsedCutoff) ||
+          !Number.isInteger(parsedCutoff) ||
+          parsedCutoff < 1)
       ) {
         toast.error("Cutoff rank must be 1 or higher")
         setIsSubmitting(false)
         return
       }
@@
-    const parsedCutoff = cutoffRank.trim() === "" ? null : parseInt(cutoffRank, 10)
-    if (parsedCutoff !== null && Number.isNaN(parsedCutoff)) return false
+    const parsedCutoff = cutoffRank.trim() === "" ? null : Number(cutoffRank)
+    if (
+      parsedCutoff !== null &&
+      (!Number.isFinite(parsedCutoff) || !Number.isInteger(parsedCutoff))
+    ) {
+      return false
+    }

Also applies to: 104–109

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/wodsmith-start/src/routes/compete/organizer/`$competitionId/-components/capacity-settings-form.tsx
around lines 70 - 79, Replace parseInt-based parsing of cutoffRank with numeric
validation using Number() and Number.isFinite/Number.isInteger checks: treat an
empty cutoffRank string as null, otherwise call Number(cutoffRank) and ensure
Number.isFinite(parsed) && Number.isInteger(parsed) && parsed >= 1; if
validation fails show the same toast and abort. Mirror this same
parsing/validation for any hasChanges comparison so the change detection
compares the canonical parsedCutoff (or null) rather than the truncated parseInt
result; follow the same pattern already used for maxTotal (Number +
Number.isFinite + Number.isInteger).

Comment thread lat.md/domain.md
Divisions segment athletes within a competition (e.g., "RX Male", "Scaled Female", "Masters 40+").

Stored in competition `settings` JSON. Athletes register into a specific division. Division-specific registration fees can override the competition default.
Stored in competition `settings` JSON. Athletes register into a specific division. Division-specific registration fees, capacity (max spots), and leaderboard cutoff rank can each override the competition default.
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.

⚠️ Potential issue | 🟡 Minor

Division storage detail is inaccurate after this feature change.

Line 48 says division config is stored in competition settings JSON, but fee/capacity/cutoff now live in competition_divisions. Please update wording so docs match runtime data model.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lat.md/domain.md` at line 48, The doc text incorrectly states that division
config is stored in the competition `settings` JSON; update the sentence in
lat.md/domain.md to reflect that division-specific registration fee, capacity
(max spots), and leaderboard cutoff rank are stored on the competition_divisions
data model/ table (e.g., `competition_divisions`) rather than in the competition
`settings` JSON, while keeping that athletes register into a specific division
and noting that these fields override the competition defaults.

Comment on lines +29 to +33
### Cutoff Rank

Configures a leaderboard cutoff line — a bold orange line rendered after the Nth-ranked athlete.

Uses the same two-level fallback as capacity: `competitionsTable.defaultCutoffRank` is the competition-wide default, `competitionDivisionsTable.cutoffRank` is the per-division override (null = use default). The effective cutoff flows to the public leaderboard via `getPublicCompetitionDivisionsFn` and renders in both `CompetitionLeaderboardTable` and `OnlineCompetitionLeaderboardTable` (desktop + mobile). Only shown on overall view, hidden in single-event view.
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.

⚠️ Potential issue | 🟡 Minor

Use wiki links for the new cutoff references.

This new lat.md section introduces several raw code references instead of [[...]] links, which breaks the knowledge-graph cross-linking for the added feature. As per coding guidelines, "Use wiki links ([[target]] or [[target|alias]]) to cross-reference sections and source code in lat.md/ files".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lat.md/organizer-dashboard.md` around lines 29 - 33, Replace the raw code
references in this section with wiki links so the knowledge graph picks them up:
convert "competitionsTable.defaultCutoffRank" and
"competitionDivisionsTable.cutoffRank" to wiki links (e.g.
[[competitionsTable.defaultCutoffRank]] /
[[competitionDivisionsTable.cutoffRank]]), change
"getPublicCompetitionDivisionsFn" to [[getPublicCompetitionDivisionsFn]] and the
component names "CompetitionLeaderboardTable" and
"OnlineCompetitionLeaderboardTable" to [[CompetitionLeaderboardTable]] and
[[OnlineCompetitionLeaderboardTable]] (use aliasing if you want different
display text); keep the surrounding explanatory text intact and ensure the
overall/single-event view wording remains unchanged.

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