Skip to content

fix: normalize github_id to str, prevent false cancel votes on truncated timelines#1416

Open
zeroknowledge0x wants to merge 1 commit into
entrius:testfrom
zeroknowledge0x:fix/issue-1413-int-str-github-id-normalization
Open

fix: normalize github_id to str, prevent false cancel votes on truncated timelines#1416
zeroknowledge0x wants to merge 1 commit into
entrius:testfrom
zeroknowledge0x:fix/issue-1413-int-str-github-id-normalization

Conversation

@zeroknowledge0x
Copy link
Copy Markdown

Summary

Normalizes github_id / solver_github_id to str at all boundaries to prevent int/str dict key mismatches, and returns a lookup-failure sentinel when a closed issue's authoritative close event is missing from the (possibly truncated) timeline.

Fixes #1413
Fixes #1411

Changes

Bug #1413 — int/str github_id mismatch

Root cause: _solver_from_closed_event() returns databaseId directly from GraphQL as int, while registered_miners keys come from get_github_identity()str(user_id). Even though forward.py line 132 wraps the lookup in str(), the inconsistency is fragile and breaks duplicate detection in inspections.py.

Fix:

  • github_api_tools._solver_from_closed_event — normalize databaseId to str at the source; update return type from tuple[Optional[int], ...] to tuple[Optional[str], ...]
  • forward.pystr() normalize registered_miners dict keys
  • inspections.pystr() normalize github_id_to_uids dict keys

Bug #1411 — false cancel votes on truncated timelines

Root cause: _ISSUE_CLOSURE_QUERY fetches only the last 20 CLOSED_EVENT nodes. On high-churn issues the current close event can fall outside that window. _select_current_close_event then returns None, find_solver_from_closure_event returns (None, None) (not a failure sentinel), and forward.py votes cancel on a legitimately solved bounty.

Fix: In find_solver_from_closure_event, when close_event is None but closedAt is set and completed close events exist in the timeline (meaning the authoritative event was truncated), return None (lookup failure) instead of (None, None). This causes forward.py to skip the issue rather than cancel it.

Testing

  • All 34 tests in tests/utils/test_github_api_tools.py pass (updated 6 assertions from int to str)
  • All 4 tests in tests/validator/test_issue_competitions_forward.py pass
  • All 561 tests in tests/validator/ pass

…nt false cancel votes

Fixes entrius#1413: Normalize solver_github_id from GraphQL's databaseId (int) to
str at the source (_solver_from_closed_event) so dict lookups against
registered_miners keys always match. Also harden the dict comprehension in
forward.py and inspections.py with explicit str() normalization.

Fixes entrius#1411: When _select_current_close_event returns None but the issue has
a closedAt and completed close events exist in the timeline (none matching
closedAt), return None (lookup failure sentinel) instead of (None, None).
This prevents forward.py from voting cancel on a legitimately solved issue
whose authoritative close event fell outside the truncated timeline window.

Changes:
- _solver_from_closed_event: return str(dbId) instead of int
- find_solver_from_closure_event: update return type to tuple[Optional[str], ...]
- forward.py: str() normalize registered_miners keys
- inspections.py: str() normalize github_id_to_uids keys
- Update tests to expect str solver IDs
@xiao-xiao-mao xiao-xiao-mao Bot added the bug Something isn't working label May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: int/str github_id mismatch breaks duplicate penalty and bounty lookup [Bug]: Issue bounty forward false cancel when closure timeline truncated

2 participants