Review: Bug: teams/save appends instead of replacing (CI blocker)
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Lineage — standalone, correctly documented as unplanned discovery
- [x] Repo —
forgejo_admin/basketball-api - [x] What Broke / Expected Behavior — substitutes for User Story (appropriate for bug)
- [ ] User Story — absent (acceptable for bug type; What Broke + Expected Behavior serve the same purpose)
- [x] Context — embedded in "What Broke" section with root cause analysis
- [x] File Targets — specific files, line numbers, and all three branches documented
- [x] Test Expectations — run command provided, pass/fail counts specified
- [x] Acceptance Criteria — 5 criteria, all verifiable
- [x] Constraints — scope bounded ("2-line fix"), future design intent documented
- [x] Related — upstream blockers (#170, #172) and migration reference
- [x] Repro Steps — clear numbered steps with expected vs actual
- [x] Environment — CI context and prod impact noted
File Targets
- [x]
src/basketball_api/routes/admin.pyline 697 — verified:admin_teams_save()function starts at line 697 - [x]
src/basketball_api/routes/admin.pylines 749-753 (temp team branch) — verified:player.teams.append(real_team)at line 752, no precedingclear() - [x]
src/basketball_api/routes/admin.pylines 770-773 (existing team branch) — verified:player.teams.append(team)at line 772, no precedingclear() - [x]
src/basketball_api/routes/admin.pylines 732-735 (unassign branch) — verified:player.teams.clear()at line 734, already correct as ticket states - [x]
tests/test_admin_teams.pyline 290 — verified:test_temp_team_dedupexists, assertslen(player1.teams) == 1at line 316 - [x]
alembic/versions/019_player_teams_junction.py— verified: migration file exists
Repo Placement
OK — Forgejo issue filed on
forgejo_admin/basketball-api, fix targets files in the same repo. Single-repo fix, no cross-repo coordination needed.Dependencies
- Blocks: Issue #170 (jersey sync) and PR #172 are blocked by this CI failure — documented in scope.
- Board item #393 ("Baby Betty contradictory jersey state") shares the
arch:stripe-webhooklabel and is also a teams-related bug in backlog — may be related but no explicit dependency documented. - No items currently in
in_progressornext_upthat conflict with this fix (the two in_progress items are Phase 14: Billing Tiers and Phase 15: Production Port).
Acceptance Criteria
All 5 criteria are agent-verifiable:
- [x]
player.teams.clear()insertion — grep-verifiable after fix - [x]
test_temp_team_deduppasses —pytest tests/test_admin_teams.py::TestTeamsSave::test_temp_team_dedup -v - [x] All 18
test_admin_teams.pytests pass —pytest tests/test_admin_teams.py -v - [x] Full suite (555 tests) —
python -m pytest - [x] CI pipeline succeeds — observable post-merge
Blast Radius
- Source code: Only
admin.pyusesplayer.teams.append()in production code. The two locations identified in the ticket are the only append sites. No other routes or services have this pattern. - Test fixtures: 5 test files use
player.teams.append()in fixture setup — these are correct (building test state, not simulating save behavior). - No downstream consumers: The
/admin/teams/saveendpoint is called only by the SPA draft board. No other services consume it. - Idempotency concern: Adding
clear()beforeappend()means re-saving the same assignments will clear+re-add. Thecidsdedup check (lines 750-751, 770-771) becomes redundant afterclear()but harmless. Consider whetherupdatedcounter logic needs adjustment — currently it only increments whenreal_team.id not in cids, but afterclear()the player will always have 0 teams, soupdatedwill always increment. This is a minor behavioral change but likely acceptable.
Issues Found
- Label mismatch:
arch:stripe-webhookis incorrect. This bug is in the/admin/teams/saveroute (admin.py). There is no Stripe or webhook code involved. The correct architecture label should reflect the admin/draft-board component (e.g.,arch:admin-apiorarch:draft-board). Board item #393 has the same mislabel.
Recommendation
Fix the
arch:stripe-webhook label on board item #404 to an appropriate architecture label (e.g., arch:admin-api or arch:draft-board). The scope document itself is excellent — thorough root cause analysis, precise file targets with verified line numbers, clear acceptance criteria, and bounded scope. Once the label is corrected, this ticket is READY for agent execution.