Skip to content

[Bug] Duplicate-GitHub penalty leaves cached issue_discovery_issues in repo allocation #1279

Description

@statxc

Description

_zero_for_duplicate_penalty() clears issue-discovery scalar fields, but it does not clear MinerEvaluation.issue_discovery_issues.

After #1235, final rewards are allocated by blend_emission_pools() from per-repo PR and issue rows. The issue allocator sums issue.discovery_earned_score directly from evaluation.issue_discovery_issues, and it does not skip evaluations with failed_reason.

That means a duplicate-GitHub miner restored from MinerEvaluationCache can be penalized, have issue_discovery_score = 0.0, but still keep stale cached issue rows that consume issue-discovery repo allocation.

In the live forward path, update_scores(..., blacklisted_uids=...) later zeros penalized UIDs, but the repo slice has already been divided using their stale issue rows. This can starve legitimate issue discoverers or prevent the slice from recycling correctly.

Affected Code

  • gittensor/validator/oss_contributions/inspections.py
    • _zero_for_duplicate_penalty() clears PR lists and issue-discovery counters, but not issue_discovery_issues.
  • gittensor/validator/emission_allocation.py
    • _collect_repo_issue_discovery_scores() reads evaluation.issue_discovery_issues directly.

Steps To Reproduce

Run this on current test:

.venv/bin/python - <<'PY'
from gittensor.classes import Issue, MinerEvaluation
from gittensor.validator.oss_contributions.inspections import detect_and_penalize_miners_sharing_github
from gittensor.validator.emission_allocation import blend_emission_pools
from gittensor.validator.utils.load_weights import RepositoryConfig

evals = {}
for uid in (1, 2):
    ev = MinerEvaluation(uid=uid, hotkey=f"hk{uid}", github_id="shared")
    issue = Issue(number=uid, pr_number=100 + uid, repository_full_name="r/issue", title="cached")
    issue.discovery_earned_score = 10.0
    ev.issue_discovery_issues = [issue]
    ev.issue_discovery_score = 10.0
    evals[uid] = ev

penalized = detect_and_penalize_miners_sharing_github(evals)
print("penalized:", sorted(penalized))
print("scalar_scores:", [evals[u].issue_discovery_score for u in (1, 2)])
print("issue_rows_left:", [len(evals[u].issue_discovery_issues) for u in (1, 2)])

repos = {"r/issue": RepositoryConfig(emission_share=1.0, issue_discovery_share=1.0)}
uids = {0, 1, 2, 111}
rewards = blend_emission_pools(evals, repos, uids)
print(dict(zip(sorted(uids), map(float, rewards))))
PY

Observed output:

penalized: [1, 2]
scalar_scores: [0.0, 0.0]
issue_rows_left: [1, 1]
{0: 0.0, 1: 0.45, 2: 0.45, 111: 0.1}

Expected Behavior

Duplicate-penalized miners should not contribute any PR-side or issue-discovery rows to repo allocation.

After penalty:

  • issue_discovery_score should be 0.0
  • issue_discovery_issues should be empty
  • _collect_repo_issue_discovery_scores() should not see score-bearing rows from failed/penalized evaluations

Actual Behavior

The penalty clears issue_discovery_score and counters, but stale issue_discovery_issues remain populated. blend_emission_pools() still allocates issue-discovery repo share to those rows.

Suggested Fix

At minimum, clear the issue row list in _zero_for_duplicate_penalty():

eval_.issue_discovery_issues = []

A more defensive follow-up would make the emission collectors skip evaluations with failed_reason is not None.

Acceptance Criteria

  • Add a regression test where duplicate-GitHub evaluations have populated issue_discovery_issues.
  • After detect_and_penalize_miners_sharing_github(), assert the issue row list is empty.
  • Add or extend an allocation test proving penalized/failed evaluations do not consume issue-discovery repo slices.

Related / Not Duplicate

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions