Skip to content

Add per-division global spots override for series sources - #433

Open
zacjones93 wants to merge 1 commit into
mainfrom
claude/fix-series-invite-global-spots-l84By
Open

Add per-division global spots override for series sources#433
zacjones93 wants to merge 1 commit into
mainfrom
claude/fix-series-invite-global-spots-l84By

Conversation

@zacjones93

@zacjones93 zacjones93 commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends the per-division allocation system to support independent overrides of the global-leaderboard contribution for series sources, while preserving the existing absolute-spots override behavior. This allows organizers to tune how many global-leaderboard qualifiers each division receives from a series (e.g., 3 RX, 2 Scaled) without affecting the per-competition direct tier.

Key Changes

  • New globalSpots column in competitionInviteSourceDivisionAllocationsTable: Stores per-division global-leaderboard overrides for series sources, nullable to indicate "use source default"

  • Dual-axis override model: Each allocation row now carries two independent nullable axes:

    • spots: Absolute total override (existing behavior, takes precedence)
    • globalSpots: Series-only per-division global-leaderboard override (new)
  • Updated resolver logic (resolveSourceAllocations): Implements precedence rules:

    1. If spots is non-null → return it directly
    2. Else if globalSpots is non-null (series only) → return directSpotsPerComp * seriesCompCount + globalSpots
    3. Else → return source default
  • New UI card in invite source details page: "Per-division global spots" card (series sources only) with:

    • Toggle per division to use default or override
    • Input field for override value
    • Independent save/discard from the existing allocations card
    • Merged payload builder that sends both axes to preserve state across saves
  • Updated schema documentation: Clarified the two-axis model and precedence rules in comments and ADR notes

  • Test coverage: Added four new test cases covering global-spots overrides, zero values, precedence with absolute-spots overrides, and fallback behavior

Implementation Details

  • The buildAllocationPayload() helper constructs a merged payload containing both spots and globalSpots for each division, ensuring that saving from either card doesn't accidentally clear the other axis
  • Per-division global-spots state is tracked independently from the allocations state, allowing the two UI sections to operate without interference
  • The resolver gracefully handles rows with both axes null (treats as if row were absent)
  • Series-source check (isSeriesSource) gates the global-spots UI and validation logic

https://claude.ai/code/session_01EnVk9h1h8GhuF8dUddRD7u


Summary by cubic

Adds per-division global spots overrides for series sources so organizers can set how many global-leaderboard qualifiers each division gets without changing per-comp direct spots. Updates schema, resolver, API, and UI to support a dual-axis override model.

  • New Features

    • Added nullable globalSpots to competitionInviteSourceDivisionAllocationsTable; spots is now nullable.
    • Dual-axis per-division overrides: spots (absolute total) and globalSpots (series-only global tier).
    • Updated resolveSourceAllocations precedence: spots > globalSpots (series) > source default.
    • Series source details page: new “Per-division global spots” card with use-default toggle, input, and independent save.
    • Server fns (listInviteSourceAllocationsFn, saveInviteSourceAllocationsFn) now read/write both axes and send merged payloads to avoid clearing the other axis; added tests for overrides, zero values, precedence, and fallbacks.
  • Migration

    • Add nullable globalSpots and make spots nullable on competitionInviteSourceDivisionAllocationsTable.
    • No backfill needed; existing overrides continue to work.
    • Rows with both axes null are treated as default and are deleted on save by saveInviteSourceAllocationsFn.

Written for commit f9a67c1. Summary will update on new commits. Review in cubic

…rces

Series sources now support per-division overrides on the global-leaderboard
portion (e.g. 3 RX globals, 2 Scaled globals) in addition to the existing
absolute-total override. Both axes live on the same allocation row keyed by
(sourceId, championshipDivisionId); the source details page stacks a new
"Per-division global spots" card above the existing per-division allocation
table for series sources, mirroring the same Use-default + numeric-input UX.

The resolver applies precedence per row: spots non-null → absolute total
override; else globalSpots non-null → directSpotsPerComp*compCount + globalSpots;
else → source default. Single-comp sources are unchanged in practice (UI
only exposes the new card for series).
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@zacjones93 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 59 minutes and 56 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d71d8721-da7e-4c96-b48f-ba0ff21a1b0d

📥 Commits

Reviewing files that changed from the base of the PR and between 66456c1 and f9a67c1.

📒 Files selected for processing (8)
  • apps/wodsmith-start/src/db/schemas/competition-invites.ts
  • apps/wodsmith-start/src/routes/compete/organizer/$competitionId/invites/sources/$sourceId.tsx
  • apps/wodsmith-start/src/server-fns/competition-invite-fns.ts
  • apps/wodsmith-start/src/server/competition-invites/allocations.ts
  • apps/wodsmith-start/src/server/competition-invites/claim.ts
  • apps/wodsmith-start/test/server/competition-invites/allocations.test.ts
  • apps/wodsmith-start/test/server/competition-invites/roster-allocations.test.ts
  • lat.md/competition-invites.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fix-series-invite-global-spots-l84By

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
Review rate limit: 0/1 reviews remaining, refill in 59 minutes and 56 seconds.

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

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

2 issues found across 8 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/server/competition-invites/allocations.ts">

<violation number="1" location="apps/wodsmith-start/src/server/competition-invites/allocations.ts:69">
P2: `globalSpots` row overrides are being applied to competition sources even though this override is intended to be series-only.</violation>
</file>

<file name="apps/wodsmith-start/src/routes/compete/organizer/$competitionId/invites/sources/$sourceId.tsx">

<violation number="1" location="apps/wodsmith-start/src/routes/compete/organizer/$competitionId/invites/sources/$sourceId.tsx:398">
P2: Each save action is coupled to both override sections, so saving one card can validate and persist unsaved changes from the other card.</violation>
</file>

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

Comment on lines +69 to 72
const globalSpots = globalSpotsOverride ?? source.globalSpots ?? 0
if (source.kind === COMPETITION_INVITE_SOURCE_KIND.SERIES) {
const direct = source.directSpotsPerComp ?? 0
const compCount = seriesCompCount ?? 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.

P2: globalSpots row overrides are being applied to competition sources even though this override is intended to be series-only.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/src/server/competition-invites/allocations.ts, line 69:

<comment>`globalSpots` row overrides are being applied to competition sources even though this override is intended to be series-only.</comment>

<file context>
@@ -55,12 +55,18 @@ export interface ResolvedSourceAllocations {
+  globalSpotsOverride: number | null,
 ): number {
-  const globalSpots = source.globalSpots ?? 0
+  const globalSpots = globalSpotsOverride ?? source.globalSpots ?? 0
   if (source.kind === COMPETITION_INVITE_SOURCE_KIND.SERIES) {
     const direct = source.directSpotsPerComp ?? 0
</file context>

})
}
setGlobalSpotsError(null)
const { payload, error } = buildAllocationPayload()

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.

P2: Each save action is coupled to both override sections, so saving one card can validate and persist unsaved changes from the other card.

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/invites/sources/$sourceId.tsx, line 398:

<comment>Each save action is coupled to both override sections, so saving one card can validate and persist unsaved changes from the other card.</comment>

<file context>
@@ -264,42 +394,17 @@ function InviteSourceDetailsPage() {
-        })
-      }
+    setGlobalSpotsError(null)
+    const { payload, error } = buildAllocationPayload()
+    if (error) {
+      setAllocationError(error)
</file context>

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.

2 participants