feat(validator): per-repository eligibility#1293
Merged
Merged
Conversation
Eligibility is now computed per repository instead of globally. Each repo gates and scores miners from only its own PRs/issues, against its own optionally-overridden thresholds — work in one repo never unlocks or penalizes another. - RepositoryConfig gains an `eligibility` block of 12 overridable knobs; resolve_eligibility overlays it onto the global default constants - finalize_miner_scores groups PRs by repo and gates each independently; the eligibility_mode bool and the gated/bypass split are removed - issue discovery gates per repo, with the new per-repo MIN_TOKEN_SCORE_FOR_VALID_ISSUE constant - MinerEvaluation carries a per-repo RepoEvaluation map; miner_evaluations is persisted one row per (uid, hotkey, github_id, repository_full_name) - the credibility mulligan is removed; per-repo gate defaults retuned - issue bounty payouts are no longer eligibility-gated Requires the matching gittensor-db schema change to land first.
entrius
approved these changes
May 17, 2026
plind-junior
added a commit
to plind-junior/gittensor
that referenced
this pull request
May 21, 2026
PR entrius#1293 added a per-repo min_token_score_for_base_score eligibility override and wired it into the resolver, but mirror/scoring.py kept reading the global MIN_TOKEN_SCORE_FOR_BASE_SCORE. Issue-discovery already honored the per-repo value, so issues and PRs in the same repo were gated by different thresholds -- a silent state asymmetry. calculate_base_score_for_pr_files now takes an optional threshold parameter and both callers (score_pr and the issue-discovery solving-PR cache miss) pass the resolved per-repo value. Regression tests cover the default plus permissive and stricter overrides. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 tasks
plind-junior
added a commit
to plind-junior/gittensor
that referenced
this pull request
May 21, 2026
PR entrius#1293 added a per-repo min_token_score_for_base_score eligibility override and wired it into the resolver, but mirror/scoring.py kept reading the global MIN_TOKEN_SCORE_FOR_BASE_SCORE. Issue-discovery already honored the per-repo value, so issues and PRs in the same repo were gated by different thresholds -- a silent state asymmetry. calculate_base_score_for_pr_files now takes an optional threshold parameter and both callers (score_pr and the issue-discovery solving-PR cache miss) pass the resolved per-repo value. Regression tests cover the default plus permissive and stricter overrides.
plind-junior
added a commit
to plind-junior/gittensor
that referenced
this pull request
May 21, 2026
PR entrius#1293 added a per-repo min_token_score_for_base_score eligibility override and wired it into the resolver, but mirror/scoring.py kept reading the global MIN_TOKEN_SCORE_FOR_BASE_SCORE. Issue-discovery already honored the per-repo value, so issues and PRs in the same repo were gated by different thresholds -- a silent state asymmetry. calculate_base_score_for_pr_files now takes an optional threshold parameter and both callers (score_pr and the issue-discovery solving-PR cache miss) pass the resolved per-repo value. Regression tests cover the default plus permissive and stricter overrides.
This was referenced May 21, 2026
plind-junior
added a commit
to plind-junior/gittensor
that referenced
this pull request
May 22, 2026
Collapse the three parallel per-repo config families (eligibility, scoring, time-decay) into one spec-driven mechanism. Each family was added separately (entrius#1293, entrius#1300) by copy-pasting the same resolve -> coerce -> parse -> validate scaffolding. - _FieldSpec declares each overridable field: caster, default constant, range bounds, and an optional note. Three spec tables drive everything. - Generic helpers replace the duplication: _resolve_overrides (was 3 pick-closure resolvers), _coerce_override (was 2), _parse_overrides (was 3 + 6 field-name tuples), _bound_desc/_validate_ranges (was 2 validators with ~15 inline checks). - resolve_*, _parse_*, _validate_*_configs become thin wrappers. Public API and dataclasses unchanged; no downstream caller touched. - Net -134 lines in load_weights.py; a 4th override family is now a ~6-line spec entry instead of ~80 lines of boilerplate. Pure refactor - no behavioral change. Adds 4 tests locking the centralized paths (divisor note, nested time_decay range rejection, inclusive-vs-exclusive bracket rendering). Full suite: 841 passing.
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Eligibility moves from a single global gate per miner to an independent gate per repository. Each repo computes its own eligible/ineligible miner set from only that repo's PRs/issues, against its own thresholds — work in one repo never unlocks or penalizes another.
Changes
RepositoryConfiggains an optionaleligibilityblock — 12 overridable knobs (min_valid_merged_prs,min_credibility, spam thresholds, the issue-discovery equivalents).resolve_eligibility()overlays a repo's overrides onto the global default constants. Theeligibility_modebool is removed — "no gate" is now a repo with zeroed thresholds (oc-1migrated accordingly).finalize_miner_scoresgroups PRs by repo and gates each repo independently; the gated/bypass split is gone.MinerEvaluationcarries a per-repoRepoEvaluationmap; the round-level scalars are rollups.MIN_TOKEN_SCORE_FOR_VALID_ISSUEconstant mirroringMIN_TOKEN_SCORE_FOR_BASE_SCORE.miner_evaluationsis written one row per(uid, hotkey, github_id, repository_full_name).merged / (merged + closed).Retuned defaults
MIN_VALID_MERGED_PRS5→3,MIN_VALID_SOLVED_ISSUES7→3,MIN_ISSUE_CREDIBILITY0.80→0.70, open-PR/open-issue spam bases 10/5→2/2.MIN_CREDIBILITYstays 0.80.Behaviour / emissions impact
This is stricter: work no longer pools across repos, so on-chain emissions reallocate the first round after deploy. Intended — see the feature plan.
Deploy order
The matching gittensor-db schema change (adds
repository_full_name, 4-tuple unique constraint) must merge first — the old constraint rejects multi-repo rows. das-gittensor API changes follow. PRs linked separately.Testing
ruff,ruff format,pyright, andpytest(795 passing) all green locally.