Skip to content

fix: stale results guard, calculation post results, default UTC#132

Merged
adrunkhuman merged 4 commits intomasterfrom
fix/results-entry-integrity
Mar 21, 2026
Merged

fix: stale results guard, calculation post results, default UTC#132
adrunkhuman merged 4 commits intomasterfrom
fix/results-entry-integrity

Conversation

@adrunkhuman
Copy link
Owner

Summary

Test plan

  • uv run pytest — 295 passed, 1 skipped
  • Smoke: enter results for a fixture, confirm → results saved, announcement includes match results
  • Smoke: attempt to confirm a stale results-entry session on an already-scored fixture → error message shown, session cleared
  • Verify TZ=Europe/Warsaw override still works for deployments that need it

Closes #121
Closes #102
Closes #77

🤖 Generated with Claude Code

adrunkhuman and others added 3 commits March 21, 2026 22:12
…TC (#121, #102, #77)

#121: ResultsEntryHandler.save_results() now re-validates the fixture before
writing. Raises ValueError if the fixture is closed or scores already exist,
preventing a stale confirmation button from silently overwriting scored results.
ResultsConfirmView.confirm() surfaces the error to the admin; session is
preserved so they can cancel explicitly. Uses the existing fixture_has_scores()
DB method — no new queries.

#102: _post_calculation_to_channel() now prepends the entered match results to
the announcement via new format_fixture_results() in prediction_parser.py. Data
was already present in FixtureScoreResult — just not passed through to the post.

#77: Default timezone changed from Europe/Warsaw to UTC. Existing stored
deadlines are unaffected — they carry an embedded UTC offset in the ISO string
so parse_iso() ignores APP_TZ for them. Deadline inputs via the admin DM
workflow are now expected in UTC. .env.example updated accordingly.

Closes #121, #102, #77.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Clear results session immediately in ResultsConfirmView.confirm() error path
  rather than relying on the 120s view timeout; buttons are already removed via
  view=None so the session had no reachable cleanup path within the window.

- Make db.save_results() atomic: wraps check+write in BEGIN IMMEDIATE so the
  fixture-status and scores-exist guards are not a TOCTOU against concurrent
  admin sessions or panel corrections.

- Use strict=True in format_fixture_results() zip so a games/results length
  mismatch surfaces as an explicit error rather than a silently truncated post.

- Wrap ZoneInfo() construction in timezone.py with a try/except and re-raise
  as RuntimeError with the invalid key in the message, so a bad TZ env var
  fails at startup with a clear diagnostic instead of a raw ZoneInfoNotFoundError.

- Update test_timezone.py to reflect UTC default (two tests hardcoded the old
  Europe/Warsaw expectation).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uard test

Wrap the INSERT and commit in db.save_results() in a try/except that calls
db.rollback() on failure, matching the pattern used by every other BEGIN
IMMEDIATE block in the file. Previously a write-time error would leave the
IMMEDIATE lock held until the connection closed rather than releasing it
promptly.

Standardise early-exit rollbacks to db.rollback() (aiosqlite connection method)
instead of db.execute("ROLLBACK") raw SQL to stay consistent with the rest of
the file.

Add test_save_results_db_rejects_scores_exist_open_fixture: exercises the
scores-exist guard at the real SQLite layer by inserting scores directly without
closing the fixture, covering the path that the existing mock-based test only
approximated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to patient-quietude / matchday-typer-pr-132 March 21, 2026 21:28 Destroyed
@railway-app
Copy link

railway-app bot commented Mar 21, 2026

🚅 Deployed to the matchday-typer-pr-132 environment in patient-quietude

Service Status Web Updated (UTC)
matchday-typer ✅ Success (View Logs) Mar 21, 2026 at 9:43 pm

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to patient-quietude / matchday-typer-pr-132 March 21, 2026 21:43 Destroyed
@adrunkhuman adrunkhuman merged commit caab8b2 into master Mar 21, 2026
2 checks passed
@adrunkhuman adrunkhuman deleted the fix/results-entry-integrity branch March 21, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant