feat(rewards): allocate emissions by bounded per-repo emission_share#1238
Closed
RenzoMXD wants to merge 1 commit into
Closed
feat(rewards): allocate emissions by bounded per-repo emission_share#1238RenzoMXD wants to merge 1 commit into
RenzoMXD wants to merge 1 commit into
Conversation
Closes entrius#1215 Replaces the per-PR repo_weight_multiplier factor with per-repo emission share allocation at aggregation time. Every PR scores as if its repo contributes 1.0 to the multiplier chain; final reward is divided proportionally inside each repository's emission_share x OSS_EMISSION_SHARE slice. Deliverables - D1 RepositoryConfig.weight renamed to emission_share, validated at load time as float in [0, 1] with sum across registry <= 1.0. - D2 Each active repo receives exactly emission_share x pool, split between PR-side and issue-discovery-side by issue_discovery_share. Single eligible PR claims the full slice; many PRs split it by per-PR earned_score. - D3 master_repositories.json migrated in-place (current values already satisfy the new invariant; sum is 0.71 so 0.29 routes to recycle). - D4 repo_weight_multiplier removed from per-PR scoring, ScoredPR, PullRequest, Issue, mirror adapters, and the storage layer. No code path multiplies by per-repo weight at PR granularity. - D5/D6 Eight named tests in tests/validator/test_load_weights.py cover registry invariants; fifteen named tests in tests/validator/emissions/ test_allocate.py cover allocation behavior including the issue_discovery_share=0 short-circuit (oc-1 case), issue_discovery_share=1 short-circuit, within-repo spill in both directions, cross-repo linked issues attaching to the issue's home repo, multi-repo cumulative slices, full-registry zero-recycle invariant, and registry-slack routing. - D7 Atomic ship: both legacy normalize.py modules deleted, no backward-compat parameters on the new allocator, SQL persistence drops repo_weight_multiplier and discovery_repo_weight_multiplier from the bulk upsert paths in storage/queries.py and storage/repository.py. - D8 issue_discovery_share field on RepositoryConfig defaults to 0.5; entrius/oc-1 sets it to 0.0 explicitly. Issue-discovery rewards attach to the issue's home repo via Issue.repository_full_name, not the solving PR's home repo. - D9 constants.py collapses to OSS_EMISSION_SHARE = 0.90 (combined scoring pool) and ISSUES_TREASURY_EMISSION_SHARE = 0.10. The flat 45% RECYCLE_EMISSION_SHARE is removed -- recycle becomes natural slack from unclaimed per-repo slices and any registry-level shortfall. - D10 Two policy shifts called out below. - D11 Per-repo allocation lives in validator/emissions/allocate.py; the emissions/ namespace sits beside oss_contributions/ and issue_discovery/ so the allocation step is no longer an OSS-only concept. Within-repo sub-slices spill across the PR/issue split when one side is empty. Monetary policy shifts (flagged per D10) - Recycle baseline removed. Previously recycle was guaranteed 45% of emissions every round. Under this change recycle only fires from (a) repos with no eligible nonzero-scored activity on either side and (b) registry slack when sum(emission_share) < 1.0. - PR-vs-issue split inside the OSS pool. Previously 30 OSS + 10 ID = 75:25 PR-vs-ID. With OSS_EMISSION_SHARE = 0.90 combined and per-repo issue_discovery_share defaulting to 0.5, repos without an explicit override now split 50:50 within their slice. Per-miner collateral from open PRs is preserved: total_collateral_score x OSS_EMISSION_SHARE is deducted from each UID's allocated reward in forward.apply_collateral_deductions. Test plan - ruff check . clean - ruff format --check . clean - pyright clean - pytest tests/ -- 739 passing
Collaborator
|
Issue #1215 deliverables missed: D1 (sum-overflow validation logs but does not raise — a registry summing > 1.0 silently loads), D7 (SQL columns dropped from INSERT/UPDATE in storage/queries.py and storage/repository.py with no migration script). Closing. |
Contributor
Author
|
Hi, @anderdc |
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.
Closes #1215
Summary
Replaces the per-PR
repo_weight_multiplierfactor with per-repo emission share allocation at aggregation time. Every PR scores as if its repo contributes 1.0 to the multiplier chain; the final reward is divided proportionally inside each repository'semission_share × OSS_EMISSION_SHAREslice. Allocate-then-distribute, never multiply-then-cap.Deliverables (mapped 1:1 to #1215)
D1 —
RepositoryConfig.weightrenamed toemission_share. Load-time validation enforces per-entry[0, 1]and registry sum≤ 1.0. Strictly greater than 1.0 is rejected; less than 1.0 is valid and routes the remainder to recycle.D2 — Each active repo receives exactly
emission_share × pool. Single eligible PR claims the full slice; many PRs split it proportionally byearned_score. A high-throughput repo cannot exceed its slice; a low-throughput active repo cannot under-claim it.D3 —
master_repositories.jsonmigrated in-place. Current values already satisfy the new invariant (sum = 0.71), so 0.29 routes to recycle as registry slack.entrius/oc-1gets explicitissue_discovery_share: 0.0per the issue body's canonical optimization-track example.D4 —
repo_weight_multiplierremoved from per-PR scoring,ScoredPR,PullRequest,Issue, mirror adapters, CLI miner-score breakdown, and the storage layer. No code path multiplies by per-repo weight at PR granularity.D5 / D6 —
tests/validator/test_load_weights.pycovers registry invariants (per-entry bounds, sum-≤-1.0 rejection,issue_discovery_sharedefault 0.5).tests/validator/emissions/test_allocate.pyadds 15 named tests covering:issue_discovery_share = 0short-circuit (the oc-1 canonical case) -issue_discovery_share = 1short-circuit (opposite direction)pr_side_spills_to_issue_sideANDissue_side_spills_to_pr_side)D7 — Atomic ship. Both legacy
normalize.pymodules deleted (no backward-compat path). New allocator has no optional fallback params. SQL persistence dropsrepo_weight_multiplierfromBULK_UPSERT_PULL_REQUESTSanddiscovery_repo_weight_multiplierfromBULK_UPSERT_ISSUES(columns no longer written; existing DB columns can be dropped via ad-hocALTER TABLEpost-merge, mirroring the precedent from #1202).D8 —
issue_discovery_share: float = 0.5added toRepositoryConfig. Defaults to 0.5 (even PR/issue split) per the issue body.entrius/oc-1sets0.0explicitly. Allocation attaches to the issue's home repo viaIssue.repository_full_name; cross-repo mechanics (solving-PR token cache, one-issue-per-PR canonical owner, anti-gaming gates) are unchanged.D9 —
constants.pycollapses to:OSS_EMISSION_SHARE = 0.90(combined scoring pool — replaces both oldOSS_EMISSION_SHARE = 0.30andISSUE_DISCOVERY_EMISSION_SHARE = 0.10)ISSUES_TREASURY_EMISSION_SHARE = 0.10(down from 0.15, still flat to UID 111)RECYCLE_EMISSION_SHAREremoved — recycle becomes natural slack from unclaimed per-repo slices plus registry-level shortfall.D10 — Recycle and split behavior tested explicitly (see test names in D5/D6 above). Per-round invariant
OSS + treasury + recycle = 1.0asserted intest_round_totals_sum_to_one_when_all_repos_active_and_registry_full.D11 — Per-repo allocation lives in
gittensor/validator/emissions/allocate.py. Theemissions/namespace sits alongsideoss_contributions/andissue_discovery/so allocation is no longer modeled as an OSS-only concern. Within-repo sub-slices spill across the PR/issue split when exactly one side is empty; both empty recycles the repo slice.Monetary policy shifts (flagged per D10)
This change carries two intentional policy shifts on top of the architectural one:
Recycle baseline removed. Today recycle is guaranteed 45% of emissions every round regardless of activity. Under this change recycle only fires from (a) repos with no eligible nonzero-scored activity on either side and (b) registry slack when
Σ emission_share < 1.0. Round-totals invariant validated by test.PR-vs-issue split inside the OSS pool. Today's effective split is 75:25 (30 OSS + 10 ID, combined). With
OSS_EMISSION_SHARE = 0.90combined and per-repoissue_discovery_sharedefaulting to 0.5, repos without an explicit override now split 50:50 within their slice.entrius/oc-1opts out viaissue_discovery_share = 0.0.Other preserved semantics
Per-miner collateral from open PRs is preserved:
total_collateral_score × OSS_EMISSION_SHAREis deducted from each UID's allocated reward inforward.apply_collateral_deductions, so open-PR spam still costs the miner emission share.Test plan
ruff check .— cleanruff format --check .— cleanpyright— 0 errorspytest tests/— 739 passing (existing 728 + 11 new in emissions/test_allocate.py)