Deduplicate Alice Uwamahoro player+parent rows (keep 202, delete 201) #420

Closed
opened 2026-04-10 18:33:49 +00:00 by forgejo_admin · 1 comment

Type

Bug

Lineage

Standalone — discovered during 2026-04-10 Westside Ops session. Confirmed by Coach Marcus in WKQ Stakeholders group that Alice Uwamahoro is one kid, not two. Symptom of the email normalization root-cause bug (basketball-api #418).

Repo

forgejo_admin/basketball-api

What Broke

Alice Uwamahoro has TWO player rows in prod with TWO separate parent rows, for the same real person. The mother re-submitted the registration form 6 minutes apart with a slightly different dot placement in her Gmail address. Gmail delivers both to the same inbox, but the basketball-api uniqueness check (no normalization) created separate rows.

Concrete rows:

  • Player id 201aliceuwamahoro13a.@gmail.com, parent_id 175, created 2026-04-08 21:16:37
  • Player id 202aliceuwamahoro13.a@gmail.com, parent_id 176, created 2026-04-08 21:22:40

Same phone (385-235-2876), same parent name (Justin Gatonda), same kid. Marcus confirmed in WKQ chat she should be on 16U Elite Queens with a $100/month contract — this blocked until dedupe.

Repro Steps

  1. SELECT id, name, created_at FROM players WHERE name = 'Alice Uwamahoro';
  2. Observe: 2 rows

Expected Behavior

One player row for Alice Uwamahoro, one parent row. Row 202 (the corrected later submission) is canonical. Row 201 and its parent (id 175) should be removed.

Environment

  • Cluster/namespace: prod (basketball-api)
  • Service version/commit: current main
  • Affected tables: players (ids 201, 202), parents (ids 175, 176)
  • Related tickets: basketball-api #418 (root cause — email normalization)
  • Related alerts: none (silent data corruption)
  • Discovery: Westside Ops Streamlit query, confirmed via Marcus in WKQ Stakeholders group

Acceptance Criteria

  • Delete player id 201 and any dependent rows (player_teams, orders, registrations — should be none, both are contract_status = 'none')
  • Delete parent id 175 (should be orphaned after player delete)
  • SELECT COUNT(*) FROM players WHERE name = 'Alice Uwamahoro' returns 1
  • Row 202 is preserved and can proceed through normal contract flow
  • Dedupe done via Alembic migration, not direct SQL shell delete (audit trail)
  • Migration is idempotent (safe to re-run)
  • No regression — row 202 still has valid parent relationship
  • westside-basketball — project this affects
  • basketball-api #418 — root cause (email normalization)
  • Unblocks: Alice Uwamahoro contract creation (16U Elite Queens, $100/month)
### Type Bug ### Lineage Standalone — discovered during 2026-04-10 Westside Ops session. Confirmed by Coach Marcus in WKQ Stakeholders group that Alice Uwamahoro is one kid, not two. Symptom of the email normalization root-cause bug (basketball-api #418). ### Repo `forgejo_admin/basketball-api` ### What Broke Alice Uwamahoro has TWO player rows in prod with TWO separate parent rows, for the same real person. The mother re-submitted the registration form 6 minutes apart with a slightly different dot placement in her Gmail address. Gmail delivers both to the same inbox, but the basketball-api uniqueness check (no normalization) created separate rows. Concrete rows: - Player id **201** — `aliceuwamahoro13a.@gmail.com`, parent_id 175, created 2026-04-08 21:16:37 - Player id **202** — `aliceuwamahoro13.a@gmail.com`, parent_id 176, created 2026-04-08 21:22:40 Same phone (385-235-2876), same parent name (Justin Gatonda), same kid. Marcus confirmed in WKQ chat she should be on 16U Elite Queens with a $100/month contract — this blocked until dedupe. ### Repro Steps 1. `SELECT id, name, created_at FROM players WHERE name = 'Alice Uwamahoro';` 2. Observe: 2 rows ### Expected Behavior One player row for Alice Uwamahoro, one parent row. Row 202 (the corrected later submission) is canonical. Row 201 and its parent (id 175) should be removed. ### Environment - Cluster/namespace: prod (basketball-api) - Service version/commit: current main - Affected tables: `players` (ids 201, 202), `parents` (ids 175, 176) - Related tickets: basketball-api #418 (root cause — email normalization) - Related alerts: none (silent data corruption) - Discovery: Westside Ops Streamlit query, confirmed via Marcus in WKQ Stakeholders group ### Acceptance Criteria - [ ] Delete player id 201 and any dependent rows (player_teams, orders, registrations — should be none, both are `contract_status = 'none'`) - [ ] Delete parent id 175 (should be orphaned after player delete) - [ ] `SELECT COUNT(*) FROM players WHERE name = 'Alice Uwamahoro'` returns 1 - [ ] Row 202 is preserved and can proceed through normal contract flow - [ ] Dedupe done via Alembic migration, not direct SQL shell delete (audit trail) - [ ] Migration is idempotent (safe to re-run) - [ ] No regression — row 202 still has valid parent relationship ### Related - `westside-basketball` — project this affects - basketball-api #418 — root cause (email normalization) - Unblocks: Alice Uwamahoro contract creation (16U Elite Queens, $100/month)
Author
Owner

Scope Review: READY

Review note: review-925-2026-04-10

Scope is solid. Concrete row IDs verified, acceptance criteria testable, Alembic migration path is correct (alembic/versions/ — next sequential number after 030). Both target rows have contract_status = 'none' so no dependent rows to worry about. Idempotency requirement is called out. Audit trail via Alembic (not raw SQL) aligns with the never-alter-prod-directly convention.

Minor notes (non-blocking):

  • story:WS-S7 is a loose thematic fit (this is data cleanup from the #418 normalization bug, not an email announcement feature). Acceptable as foundational data hygiene.
  • arch-basketball-api backing note does not exist in pal-e-docs yet — pre-existing gap across many basketball-api tickets, not this ticket's responsibility.

Ready for todonext_up. Dispatch a dev agent to write an idempotent migration that deletes player 201 and parent 175 (with guards).

## Scope Review: READY Review note: `review-925-2026-04-10` Scope is solid. Concrete row IDs verified, acceptance criteria testable, Alembic migration path is correct (`alembic/versions/` — next sequential number after 030). Both target rows have `contract_status = 'none'` so no dependent rows to worry about. Idempotency requirement is called out. Audit trail via Alembic (not raw SQL) aligns with the never-alter-prod-directly convention. Minor notes (non-blocking): - `story:WS-S7` is a loose thematic fit (this is data cleanup from the #418 normalization bug, not an email announcement feature). Acceptable as foundational data hygiene. - `arch-basketball-api` backing note does not exist in pal-e-docs yet — pre-existing gap across many basketball-api tickets, not this ticket's responsibility. Ready for `todo` → `next_up`. Dispatch a dev agent to write an idempotent migration that deletes player 201 and parent 175 (with guards).
forgejo_admin 2026-04-10 22:08:46 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/basketball-api#420
No description provided.