hotfix: make ScorecardTracker methods async to match await callers #117

Merged
cal merged 1 commits from hotfix/scorecard-tracker-async into main 2026-03-20 18:41:45 +00:00
Owner

Summary

Production is broken/scorebug and the live scorebug tracker are throwing TypeError because PR #106 added await to scorecard_tracker calls but the tracker methods were still sync.

Errors in production

TypeError: object NoneType can't be used in 'await' expression   # /scorebug
TypeError: object list can't be used in 'await' expression       # live_scorebug_tracker

Changes

  • commands/gameplay/scorecard_tracker.py — all 6 public methods made async
  • commands/voice/cleanup_service.py — 5 unpublish_scorecard calls now use await
  • tests/test_scorebug_bugs.py — 2 tests updated to async

Test results

28/28 affected tests pass.

🤖 Generated with Claude Code

## Summary **Production is broken** — `/scorebug` and the live scorebug tracker are throwing `TypeError` because PR #106 added `await` to `scorecard_tracker` calls but the tracker methods were still sync. ## Errors in production ``` TypeError: object NoneType can't be used in 'await' expression # /scorebug TypeError: object list can't be used in 'await' expression # live_scorebug_tracker ``` ## Changes - `commands/gameplay/scorecard_tracker.py` — all 6 public methods made `async` - `commands/voice/cleanup_service.py` — 5 `unpublish_scorecard` calls now use `await` - `tests/test_scorebug_bugs.py` — 2 tests updated to async ## Test results 28/28 affected tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
cal added 1 commit 2026-03-20 18:34:14 +00:00
Closes #94

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cal force-pushed hotfix/scorecard-tracker-async from 8e984d1d07 to 4e75656225 2026-03-20 18:37:51 +00:00 Compare
cal reviewed 2026-03-20 18:40:02 +00:00
cal left a comment
Author
Owner

AI Code Review

Files Reviewed

  • commands/gameplay/scorecard_tracker.py (modified)
  • commands/voice/cleanup_service.py (modified)
  • tests/test_scorebug_bugs.py (modified)

Findings

Correctness

The fix is accurate and complete. All 6 public methods on ScorecardTracker that were called with await by external callers are now properly declared async:

  • publish_scorecard — called with await in scorebug.py:96
  • unpublish_scorecard — called with await in 5 places across cleanup_service.py
  • get_scorecard — called with await in scorebug.py:167
  • get_all_scorecards — called with await in live_scorebug_tracker.py:98
  • update_timestamp — called with await in scorebug.py:210
  • cleanup_stale_entries — made async for consistency (not called externally via await in cleanup_service.py — see note below)

A full grep of the codebase confirms there are no remaining callers of these methods that are missing await. The two production TypeError messages cited in the PR body map precisely to get_all_scorecards (returns a list) and get_scorecard (returns None when no scorecard published) — both are fixed.

Note on cleanup_stale_entries: The method is declared async in this PR, but its only caller in cleanup_service.py (line 144: self.tracker.cleanup_stale_entries(valid_channel_ids)) is calling a different object — self.tracker is a VoiceChannelTracker, not a ScorecardTracker. The ScorecardTracker.cleanup_stale_entries has no external async callers today, but making it async is defensive and consistent — not a problem.

The five unpublish_scorecard call sites in cleanup_service.py are all correct. The two that were reformatted to the multi-line parenthesized await (...) style are functionally identical to the single-line pattern used at the other three sites.

Security

No issues. No new inputs, no new external calls, no secrets.

Style & Conventions

No issues. All methods retain their existing docstrings, return types, and logic unchanged. The test file correctly adds @pytest.mark.asyncio and async def to both affected test methods and updates all four call sites within those tests to use await. This matches the project's established async test pattern.

Suggestions

None that would block merging. The save_data() and load_data() methods remain sync, which is correct — they do blocking file I/O but there are no async alternatives being bypassed here and the files are small JSON blobs. If file I/O ever becomes a concern, aiofiles could be introduced, but that is out of scope for this hotfix.

Verdict: COMMENT (APPROVED)

The fix is correct, complete, and minimal. Every caller that previously received a non-awaitable object from a sync method now correctly awaits an async coroutine. Tests are updated and passing (28/28 per PR body). This is a clean, targeted hotfix with no unintended side effects. Approving — Gitea blocks self-approval so posting as COMMENT.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `commands/gameplay/scorecard_tracker.py` (modified) - `commands/voice/cleanup_service.py` (modified) - `tests/test_scorebug_bugs.py` (modified) ### Findings #### Correctness The fix is accurate and complete. All 6 public methods on `ScorecardTracker` that were called with `await` by external callers are now properly declared `async`: - `publish_scorecard` — called with `await` in `scorebug.py:96` - `unpublish_scorecard` — called with `await` in 5 places across `cleanup_service.py` - `get_scorecard` — called with `await` in `scorebug.py:167` - `get_all_scorecards` — called with `await` in `live_scorebug_tracker.py:98` - `update_timestamp` — called with `await` in `scorebug.py:210` - `cleanup_stale_entries` — made `async` for consistency (not called externally via `await` in `cleanup_service.py` — see note below) A full grep of the codebase confirms there are no remaining callers of these methods that are missing `await`. The two production `TypeError` messages cited in the PR body map precisely to `get_all_scorecards` (returns a list) and `get_scorecard` (returns `None` when no scorecard published) — both are fixed. **Note on `cleanup_stale_entries`:** The method is declared `async` in this PR, but its only caller in `cleanup_service.py` (line 144: `self.tracker.cleanup_stale_entries(valid_channel_ids)`) is calling a different object — `self.tracker` is a `VoiceChannelTracker`, not a `ScorecardTracker`. The `ScorecardTracker.cleanup_stale_entries` has no external async callers today, but making it `async` is defensive and consistent — not a problem. The five `unpublish_scorecard` call sites in `cleanup_service.py` are all correct. The two that were reformatted to the multi-line parenthesized `await (...)` style are functionally identical to the single-line pattern used at the other three sites. #### Security No issues. No new inputs, no new external calls, no secrets. #### Style & Conventions No issues. All methods retain their existing docstrings, return types, and logic unchanged. The test file correctly adds `@pytest.mark.asyncio` and `async def` to both affected test methods and updates all four call sites within those tests to use `await`. This matches the project's established async test pattern. #### Suggestions None that would block merging. The `save_data()` and `load_data()` methods remain sync, which is correct — they do blocking file I/O but there are no async alternatives being bypassed here and the files are small JSON blobs. If file I/O ever becomes a concern, `aiofiles` could be introduced, but that is out of scope for this hotfix. ### Verdict: COMMENT (APPROVED) The fix is correct, complete, and minimal. Every caller that previously received a non-awaitable object from a sync method now correctly awaits an `async` coroutine. Tests are updated and passing (28/28 per PR body). This is a clean, targeted hotfix with no unintended side effects. Approving — Gitea blocks self-approval so posting as COMMENT. --- *Automated review by Claude PR Reviewer*
cal merged commit be4213aab6 into main 2026-03-20 18:41:45 +00:00
cal deleted branch hotfix/scorecard-tracker-async 2026-03-20 18:41:46 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 Participants
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: cal/major-domo-v2#117
No description provided.