@@ -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
632712class TestOpenIssueSpamSourceIsMirror :
633713 """The open-issue spam multiplier sources its count from mirror's response,
0 commit comments