Validation: Add declined status to ContractStatus enum

validation-379-2026-04-07 Doc

validation pass

Verdict: PASS

Ticket

forgejo_admin/basketball-api#379 — Added declined value to ContractStatus enum so families who explicitly declined contracts are distinguishable from those never contacted. Alembic migration updated Postgres enum and set 5 players to declined.

Environment

Production cluster, namespace basketball-api, pod basketball-api-868ffc7cbf-qzpz6, image tag 7f4a9dbe97a009c84a1a2c5ce0b3231814ae1731.

Tiers Executed

Tier 1 (CI pipeline) + Tier 3 (production verification). No staging environment for this repo.

Checks

# Criterion How Verified Result Evidence
1 <code>declined = "declined"</code> added to ContractStatus enum Python import in running container: <code>from basketball_api.models import ContractStatus; [e.value for e in ContractStatus]</code> PASS Enum values: ['none', 'offered', 'signed', 'declined']
2 Alembic migration adds enum value to Postgres and updates players (ids 98, 94, 134 per issue; 89, 140 also set) SQL query: <code>SELECT unnest(enum_range(NULL::contractstatus))::text</code> and <code>SELECT id, name, contract_status FROM players WHERE contract_status = 'declined'</code> PASS Postgres enum: ['none', 'offered', 'signed', 'declined']. 5 players declined: id=89 Connor Behunin, id=94 Patrick Kirschman, id=98 Boston Greenhalgh, id=134 Stein Kunic, id=140 Maureen
3 Email blast endpoints exclude <code>contract_status=declined</code> Source inspection: <code>grep -r "declined" /app/src/</code> — email_queries.py uses <code>Player.contract_status.notin_([ContractStatus.signed, ContractStatus.declined])</code> PASS Filter in email_queries.py excludes both signed and declined. Same pattern in admin.py routes.
4 No regression in contract signing flow Contract status distribution query + endpoint smoke tests. Distribution: none=5, offered=26, signed=27, declined=5. Docs endpoint returns 200. Contract endpoint returns 401 (expected — auth required). PASS All status values present and correctly distributed. No unexpected zeros or missing categories.

Pipeline & Deployment

Woodpecker pipeline #404: all 5 steps green (clone, postgres, test, build-and-push, update-kustomize-tag). Pod running with 0 restarts, age 108s at validation time. ArgoCD synced new image.

Regression Check

Contract status distribution is healthy (none=5, offered=26, signed=27, declined=5 — totals 63 players). API docs endpoint responsive (HTTP 200). No crash loops or unexpected restarts.

Discovered Issues

None. Issue body listed 3 players (98, 94, 134) but migration correctly updated 5 (also 89, 140). This is correct — additional players were identified during implementation.