Skip to content

Commit ef33390

Browse files
committed
fix: don't cache fabricated zero when mirror scoring_data_stored=False
1 parent 7a3fbfb commit ef33390

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

‎gittensor/validator/issue_discovery/mirror_scan.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,18 @@ def _resolve_solving_pr_score(
446446
)
447447
return None
448448

449+
if not files_response.scoring_data_stored:
450+
# Treat as availability failure (parity with MirrorRequestError above):
451+
# caching the would-be zero score would block in-cycle retries by
452+
# sibling miners whose discovered issues share this solving PR.
453+
cache_stats.fetch_failures += 1
454+
bt.logging.warning(
455+
f'Mirror scoring data unavailable for solving PR #{solving_pr.pr_number} '
456+
f'({issue.repo_full_name}): scoring_data_stored=False — '
457+
f'issue #{issue.issue_number} not scored'
458+
)
459+
return None
460+
449461
file_changes, file_contents = mirror_files_to_legacy(
450462
issue.repo_full_name, solving_pr.pr_number, files_response.files
451463
)

‎tests/validator/issue_discovery/test_mirror_scan.py‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,86 @@ def test_resolve_increments_fetch_failures_on_request_error(self):
628628
# Failed lookups are NOT cached (so a retry is possible)
629629
assert cache == {}
630630

631+
def test_resolve_treats_unavailable_scoring_data_as_failure(self):
632+
# scoring_data_stored=False is data-availability noise, not a real
633+
# zero score. Same handling as MirrorRequestError: increment
634+
# fetch_failures, return None, leave cache empty so a sibling miner's
635+
# later lookup can retry within the cycle.
636+
from gittensor.validator.issue_discovery.mirror_scan import (
637+
_CacheStats,
638+
_resolve_solving_pr_score,
639+
)
640+
641+
client = Mock()
642+
client.get_pr_files.return_value = MirrorPullRequestFilesResponse.from_dict(
643+
{
644+
'repo_full_name': 'entrius/gittensor-ui',
645+
'pr_number': 100,
646+
'head_sha': 'h',
647+
'base_sha': 'b',
648+
'merge_base_sha': 'mb',
649+
'scoring_data_stored': False,
650+
'files': [],
651+
}
652+
)
653+
cache = {}
654+
stats = _CacheStats()
655+
656+
issue = MirrorIssue.from_dict(_issue_dict())
657+
result = _resolve_solving_pr_score(
658+
issue, issue.solving_pr, cache, stats, client, _EMPTY_LANGS, _EMPTY_TOKEN_CONFIG
659+
)
660+
661+
assert result is None
662+
assert stats.misses == 1
663+
assert stats.fetch_failures == 1
664+
assert cache == {}
665+
666+
def test_unavailable_scoring_data_is_not_cached_across_sibling_lookups(self):
667+
# Acceptance for issue #836: a single scoring_data_stored=False response
668+
# feeding two issues that share the same solving PR (i.e. across two
669+
# miners discovering the same PR) results in two misses, two fetch
670+
# failures, and an empty cache. Without the fix, the first call would
671+
# cache base_score=0 / token_score=0, the second would be a "hit" on
672+
# that fabricated zero, and fetch_failures would never increment.
673+
from gittensor.validator.issue_discovery.mirror_scan import (
674+
_CacheStats,
675+
_resolve_solving_pr_score,
676+
)
677+
678+
client = Mock()
679+
client.get_pr_files.return_value = MirrorPullRequestFilesResponse.from_dict(
680+
{
681+
'repo_full_name': 'entrius/gittensor-ui',
682+
'pr_number': 100,
683+
'head_sha': 'h',
684+
'base_sha': 'b',
685+
'merge_base_sha': 'mb',
686+
'scoring_data_stored': False,
687+
'files': [],
688+
}
689+
)
690+
cache = {}
691+
stats = _CacheStats()
692+
693+
issue_a = MirrorIssue.from_dict(_issue_dict(issue_number=50))
694+
issue_b = MirrorIssue.from_dict(_issue_dict(issue_number=51))
695+
696+
result_a = _resolve_solving_pr_score(
697+
issue_a, issue_a.solving_pr, cache, stats, client, _EMPTY_LANGS, _EMPTY_TOKEN_CONFIG
698+
)
699+
result_b = _resolve_solving_pr_score(
700+
issue_b, issue_b.solving_pr, cache, stats, client, _EMPTY_LANGS, _EMPTY_TOKEN_CONFIG
701+
)
702+
703+
assert result_a is None
704+
assert result_b is None
705+
assert stats.hits == 0
706+
assert stats.misses == 2
707+
assert stats.fetch_failures == 2
708+
assert cache == {}
709+
assert client.get_pr_files.call_count == 2
710+
631711

632712
class TestOpenIssueSpamSourceIsMirror:
633713
"""The open-issue spam multiplier sources its count from mirror's response,

0 commit comments

Comments
 (0)