Review caught that the generic feeder rule was being applied to templates
that route by their own logic. It was harmless as dead code; driving the
renderer with it made several brackets worse than before.
The rule pairs rounds by array order and assumes match n is fed by 2n-1
and 2n. That describes advanceWinnerTemplate, not every bracket:
- afl_10's Wildcard Round feeds the Elimination Finals, skipping the round
listed next to it, so array order fabricated the entire chain and drew
ten wrong connectors contradicting advanceAFLWinner.
- fifa_48's Third Place Game sits between the Semifinals and the Finals,
so the Finals came out fed by the third place game. Once BracketTreeView
filtered the consolation round out, the group had three roots and the
whole World Cup bracket rendered with no connectors at all.
- ncaa_68 labelled Round of 64 #1/#2 with First Four feeds that
advanceFirstFourWinner doesn't use.
- nba_20's play-in halves in size but pairs the 7v8 loser with the 9v10
winner.
Follow each round's declared feedsInto, and derive edges only where the
round halves exactly — the condition under which the generic ceil(n/2)
mapping is true. Bespoke transitions that happen to halve are named
explicitly. Slots left without a feeder read TBD, which is honest.
Dropping those edges sends the group to the fallback, so the fallback now
has to keep drawing what those brackets already drew: halving U-shapes by
round size, and winner tracing through irregular shapes. Previously it
drew nothing, which also silently removed every connector from brackets
with no bracketTemplateId.
Also from review:
- clear-bracket deleted seasonParticipantResults for the entire sports
season with no rebuild. That table is keyed by season, not event, so it
wiped placements for every other event in the season — permanently
zeroing standings on a finalized qualifying season. Delete only the
matches and point the admin at Reprocess Bracket, which rebuilds
placements correctly.
- The clear-bracket form sent confirm=true from a hidden field, making the
server's completed-match guard unreachable. It's a checkbox now, so the
guard is real, including without JS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnzbrCHoM8ESbtbDamaqFb