Review: Generic email blast system with pluggable audience queries
Verdict: APPROVED
Re-review of board item #993. Previous review flagged 5 items. 2 were valid disputes (arch-email and sop-email-send exist). 3 were claimed as fixed but are NOT present in the current issue body.
Disputed Items (Resolved)
- [x]
arch-email— EXISTS. Full architecture note with 6 sections (Overview, Components, Layouts, Email Flow, Preview & Approval, Decisions). Previous review's search_notes call returned zero spuriously. Confirmed via get_note_toc. - [x]
sop-email-send— EXISTS (note id 1108). Full SOP with 5 sections (Purpose, Steps, Contract Emails gate, New Email Type Checklist, Rules). Confirmed via get_note_toc.
Claimed Fixes — NOT Applied
All 3 claimed fixes are absent from the current Forgejo issue #456 body (verified 2026-04-12 via WebFetch):
- [ ] Migration number — still says
alembic/versions/031_add_email_types.py. Local checkout tops at 030, remote main likely at 044+ (per #449 CrashLoopBackOff from migration 044). Should say NNN with instruction to determine next slot from remote main. - [ ]
brand.pynot in File Targets as a separate modify target. The description mentions "using brand.py tokens" inside the email.py bullet, but brand.py itself has zero pink color tokens (onlyCOLOR_RED = "#d42026"). ACOLOR_PINKconstant must be added to brand.py for Queens branding, and brand.py must appear as its own file target. - [ ] Dependencies #457 and #448 not added to Related. Related section has only 4 bullets: project-westside-basketball, story:WS-S32, arch-email, sop-email-send. No cross-references to downstream consumers.
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, discovered during Utah Invitational tournament fee billing
- [x] Repo — forgejo_admin/basketball-api
- [x] User Story — present, matches WS-S32
- [x] Context — thorough, references existing endpoints and architecture
- [x] File Targets — present with should-modify and should-not-touch
- [x] Acceptance Criteria — 7 criteria, all testable
- [x] Test Expectations — unit + integration + run command
- [x] Constraints — present, includes Gmail inline-style requirement
- [x] Checklist — present
- [x] Related — present but incomplete (missing dependency cross-refs)
Traceability
- [x] story:WS-S32 label — verified in project-westside-basketball Admin stories list
- [x] story note verified — "As an admin, I want a generic email blast system with pluggable audience queries so that new email types ship as config, not code changes"
- [x] arch:email label — present on board item
- [x] arch note verified — arch-email exists with full architecture (6 sections)
- [x] Forgejo issue — basketball-api#456, open
File Targets
- [x]
src/basketball_api/services/email_queries.py— NEW file, confirmed does not exist yet. Correct. - [x]
src/basketball_api/services/email.py— verified exists. Has 9 send functions and _brand_wrapper as described. - [x]
src/basketball_api/routes/admin.py— verified exists. Has 4 hardcoded email endpoints. No existing /email/blast endpoint. - [x]
src/basketball_api/models.py— verified. EmailType enum at L63-70 with 7 values as described. - [ ]
alembic/versions/031_add_email_types.py— ISSUE: Migration number 031 is wrong. Local checkout has up to 030. Remote main has 040-044 (per #449 context). Next slot is likely 045+. Must say NNN with agent instruction to determine from remote main. - [ ]
brand.py— MISSING from file targets. brand.py has no pink tokens. Must be listed as a modify target with instruction to add COLOR_PINK for Queens branding.
Repo Placement
OK — issue filed on basketball-api, all file targets in basketball-api. Single repo.
Dependencies
- #994 / basketball-api#457 (Tournament product creation) — downstream consumer of tournament_committed query. Not documented in Related.
- #966 / basketball-api#448 (Add player_ids filter to blast endpoint) — depends on this ticket creating the blast endpoint. Not documented in Related.
- #965 / basketball-api#447 (email_log.player_id NULL on blast sends) — related to blast sends. Dependency unclear but relevant.
Acceptance Criteria
7 AC, all agent-verifiable. Test commands are real. Same missing criteria as initial review:
- No AC for alembic migration success (alembic upgrade head)
- No AC for idempotency / double-send protection
Blast Radius
Same as initial review. EmailType enum expansion via alembic is the primary risk (migration number collision = CrashLoopBackOff). brand.py changes are safe — additive only.
Decomposition Assessment
No decomposition needed if refinements are applied. 5 file targets in one repo, 7 AC, single agent pass.
Recommendation
3 items remain from the initial review. The 2 disputed items are resolved (notes exist).
[BODY]Fix migration filename: replace031withNNNand instruct agent to determine next slot from remote main HEAD.[BODY]Addsrc/basketball_api/brand.pyas a separate file target: "Add COLOR_PINK token for Queens branding."[BODY]Add dependency cross-references to Related: #457 (downstream consumer), #448 (depends on blast endpoint).