Skip to content

feat(validator): per-repo scoring config + mirror-side since windows#1300

Merged
entrius merged 12 commits into
testfrom
feat/per-repo-scoring-config
May 19, 2026
Merged

feat(validator): per-repo scoring config + mirror-side since windows#1300
entrius merged 12 commits into
testfrom
feat/per-repo-scoring-config

Conversation

@anderdc
Copy link
Copy Markdown
Collaborator

@anderdc anderdc commented May 18, 2026

Summary

Per-repo validator scoring work, three changes on one branch:

  1. Issue credibility gate 0.70 → 0.80 — stricter MIN_ISSUE_CREDIBILITY; also drops the issue-discovery review clean-bonus and its derived constants.
  2. Per-repo scoring config block — 9 optional knobs on each master_repositories.json entry, each resolving to a global default when omitted (resolver pattern: optional RepoScoringConfig → frozen ResolvedScoringresolve_scoring()). No entry sets any knob yet, so per-repo behavior is unchanged.
  3. Mirror-side since windows — the validator now sends das-github-mirror a per-repo since map; the mirror windows each repo server-side. The client-side re-filter (_maybe_add_pr window checks, _issue_within_window, the widest-window max()) is deleted.

Changes that ship regardless of per-repo config (global defaults)

  • PR_LOOKBACK_DAYS 35 → 30 — narrower scoring window
  • MIN_ISSUE_CREDIBILITY 0.70 → 0.80 — stricter issue gate
  • issue-discovery review clean-bonus + review-penalty constants removed

These are live the moment this merges — worth a subnet announcement.

⚠️ Merge dependency

The mirror-POST commit (8663fb9) calls POST /api/v1/miners/:id/pulls and .../issues — handlers added by das-github-mirror #109. Do not merge until #109 is deployed to the prod mirror. #109 is backwards-compatible (GET endpoints untouched), so the mirror deploy is independent and risk-free; this is purely a relative-ordering constraint.

The scoring block

All knobs optional; omitted → global default.

knob default bounds
pr_lookback_days 30 [1, 90]
open_pr_collateral_percent 0.20 [0, 1]
review_penalty_rate 0.15 (0, 1]
standard_issue_multiplier 1.33 [1, 5]
maintainer_issue_multiplier 1.66 [1, 5]
time_decay.grace_period_hours 12 [0, 168]
time_decay.sigmoid_midpoint_days 10 [1, 90]
time_decay.sigmoid_steepness 0.4 [0.01, 5]
time_decay.min_multiplier 0.05 [0, 1]

Type of Change

  • New feature

Testing

Full suite passes (814 tests); ruff + ruff format + pyright clean.

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Changes are documented (gittensor-docs-ui updated on test)

anderdc added 12 commits May 17, 2026 14:08
Aligns MIN_ISSUE_CREDIBILITY with the PR-side MIN_CREDIBILITY gate
(0.80). Discoverers in the 0.70-0.80 issue-credibility band lose
issue-discovery eligibility.
…ring

The issue-discovery review multiplier gave a 1.1x bonus when the solving
PR had zero CHANGES_REQUESTED rounds. Nothing reviews an issue — the
multiplier reads the solving PR's review rounds — so the bonus had no
clear justification. Clean solves now score 1.0x; the linear penalty
for revision rounds is unchanged.
…percent

Introduces the `scoring` block in master_repositories.json, a sibling of
`eligibility`, resolved against the global constants by resolve_scoring()
— the same pattern as resolve_eligibility(). First knob:
open_pr_collateral_percent (default 0.20, range [0, 1]), the fraction of an
open PR's potential score held as collateral. Omitting the block leaves a
repo on every default.
Adds review_penalty_rate to the scoring block (default 0.15, range
(0, 1]) — the per-CHANGES_REQUESTED-round deduction applied to PR earned
scores and, inversely, to open-PR collateral.

Issue discovery keeps no separate review rate: nothing reviews an issue,
so its review-quality multiplier reads the solving PR's rounds and now
uses that repo's review_penalty_rate. ISSUE_REVIEW_PENALTY_RATE is
removed. The dead _MAX_CHANGES_REQUESTED_REVIEWS constant — referenced
only by tests — goes with it.
Adds standard_issue_multiplier to the scoring block (default 1.33,
range [1, 5]) — the multiplier a PR earns for closing a valid linked
issue authored by a non-maintainer. _calculate_pr_multipliers now
resolves the scoring config once and threads it into the issue
multiplier.
Adds maintainer_issue_multiplier to the scoring block (default 1.66,
range [1, 5]) — the multiplier a PR earns for closing a valid linked
issue authored by a maintainer. Independent of standard_issue_multiplier;
each is range-checked on its own.
Introduces the nested time_decay block under scoring, resolved by
resolve_time_decay() into a frozen ResolvedTimeDecay. First sub-knob:
grace_period_hours (default 12, range [0, 168]) — hours after merge
before decay begins. calculate_time_decay now takes the resolved
time-decay config instead of reading the global constant.
Adds sigmoid_midpoint_days to the time_decay block (default 10, range
[1, 90]) — days after merge at which the decay multiplier reaches 50%.
Adds sigmoid_steepness to the time_decay block (default 0.4, range
[0.01, 5]) — the steepness scalar of the decay sigmoid.
Adds min_multiplier to the time_decay block (default 0.05, range
[0, 1]) — the floor the decay multiplier never drops below. Set to 1.0
to disable time decay for a repo entirely.
Adds pr_lookback_days to the scoring block (default 30, range [1, 90])
— the rolling window for PR scoring and issue discovery. The global
default drops 35 -> 30.

One mirror query serves every repo, so it fetches the widest configured
window; load.py then re-filters each PR to its own repo (merged_at for
MERGED, the existing created_at rule for stale CLOSED) and the issue
scan re-filters each issue by updated_at. A repo at the widest window
keeps every fetched item.
The validator sends each repo's pr_lookback_days as a since_by_repo map
to the mirror's new POST endpoints, which window each repo server-side.
This replaces the client-side workaround that fetched the widest window
and re-filtered every PR/issue locally.

- MirrorClient.get_miner_pulls/get_miner_issues take since_by_repo; a
  non-empty map POSTs the per-repo windows, an omitted/empty map keeps
  the plain GET (the unbounded open-issue-count call). _get and _post
  share one retry loop.
- load.py / scan.py build the map from master_repositories and drop the
  downstream re-filter (_maybe_add_pr window checks, _issue_within_window,
  the max() widest-window logic).

Requires the das-github-mirror POST endpoints (entrius/das-github-mirror#109)
deployed first.
@xiao-xiao-mao xiao-xiao-mao Bot added the feature Net-new functionality label May 18, 2026
@entrius entrius merged commit febcf37 into test May 19, 2026
3 checks passed
@entrius entrius deleted the feat/per-repo-scoring-config branch May 19, 2026 03:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants