Skip to content

Seed knockout round-1 games from group-stage standings - #50

Closed
ylynfatt wants to merge 1 commit into
knockout-entrant-slotsfrom
seed-knockout-from-groups
Closed

ylynfatt wants to merge 1 commit into
knockout-entrant-slotsfrom
seed-knockout-from-groups

Conversation

@ylynfatt

Copy link
Copy Markdown
Owner

Summary

Phase ③ of World Cup–style advancement — stacked on #49 (entrant slot descriptors), merge that first; this PR then retargets to main automatically.

Answers "how do teams carry over from the group stage": the stage page now has a Seed from group stage card for admins.

  • SeedStageFromGroups action — the stage-to-stage analog of AdvanceBracketWinner:
    • preview() resolves every entrant slot against the source stage's current standings (group positions via the per-group calculator with all in-group tiebreakers; best_placed ranks via the cross-group ranking) — read-only.
    • execute() re-resolves and fills round-1 home/away in a transaction. Idempotent: re-running after a result correction overwrites the qualifiers — refused once any round-1 game has kicked off.
  • Review card on the stage page (admins only): all 16 resolved matchups shown as Team (Winner Group A) v Team (Best-placed Phase 1: foundational cleanup of teams, games, and results #1), an amber warning while the source stage still has unfinished games (seed now, re-apply later), inline errors for unresolvable slots, and a confirm-guarded Apply seeding button posting to the new stages.seed-from-groups route.
  • Stage::previousGroupedStage() extracted to the model, shared by the seeder and the entrant builder's sourceStage prop.

Verified read-only against the real 2026 World Cup dev data: all 32 slots of the configured R32 resolve correctly (12 groups + 8 best-thirds).

Remaining phase ④ (separate PR): best-thirds allocation tables / no-rematch assignment + manual swap.

Testing

  • 10 new feature tests: resolution correctness (both descriptor types), preview purity, idempotent re-seed after a result flip, kicked-off refusal, unresolvable-slot errors, missing-source error, page payload for owner vs guest, endpoint authorization
  • Full suite: 431 passed

🤖 Generated with Claude Code

Phase 3 of World Cup style advancement. A knockout stage with entrant
descriptors can now pull its real teams from the previous grouped
stage's standings — auto-resolved, admin-confirmed:

- SeedStageFromGroups action: preview() resolves every slot (group
  position via the per-group standings calculator, best_placed rank via
  the cross-group ranking) without writing; execute() fills round-1
  home/away in a transaction
- Idempotent re-seeding after result corrections, refused once any
  round-1 game has kicked off
- Stage page gains a "Seed from <stage>" review card for admins: every
  resolved matchup, an incomplete-source warning, unresolvable-slot
  errors inline, and an Apply/Re-apply confirm button
- Stage::previousGroupedStage() extracted and shared with the entrant
  builder's sourceStage lookup

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ylynfatt
ylynfatt deleted the branch knockout-entrant-slots July 19, 2026 20:30
@ylynfatt ylynfatt closed this Jul 19, 2026
@ylynfatt
ylynfatt deleted the seed-knockout-from-groups branch July 19, 2026 20:33
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