feat(scoring): reward crown depth via a floored, EMA-anchored quality factor#449
Open
anderdc wants to merge 2 commits into
Open
feat(scoring): reward crown depth via a floored, EMA-anchored quality factor#449anderdc wants to merge 2 commits into
anderdc wants to merge 2 commits into
Conversation
… factor The crown is winner-take-all per direction: the best-rate miner earns the full pool whether their rate is 0.5% or 30% below market, so there's no marginal incentive to quote deeper. Scale crown reward by how far the rate beats a per-direction "market" reference, floored at 0.5 (forgiving, like volume_factor); the unearned remainder recycles. The reference is self-referential: a trimmed, volume-weighted, recency-decayed average of the subnet's own completed-swap clearing rates — no oracle, no contract change. Trim + volume weight + per-miner cap defend it against wash manipulation. - storage: clearing_rate column on swap_outcomes (CREATE + idempotent ALTER), populated at SwapCompleted from the swap's snapshotted rate; get_clearing_rates_by_direction_since excludes 0-rate (legacy/timed-out) rows - scoring: compute_quality_reference / quality_factor helpers; a quality_weighted_blocks accumulator parallel to cap_weighted_blocks, folded into reward as base * vol_factor * quality (independent multiply) - determinism: stable total-order sort + math.fsum, now_block=window_end, no wall-clock — every validator must compute a byte-identical reference - bootstrap: reference disabled below QUALITY_N_MIN observations (factor 1.0), so the feature is a no-op at deploy until real swap history accrues Scope: depth only. No breadth/rank-spillage. No sigma-gate edge-sitter exclusion — that belongs to the reservation-bid-window work, which makes edge-sitters arbitrageable so the market polices them. QUALITY_ANCHOR (0.05) is a placeholder — calibrate against live rate dispersion before trusting it. Tests: 23 new (reference math incl. shuffle-invariance, factor shape, e2e weighting incl. bootstrap/direction/stacking, storage round-trip, watcher population). Full suite 685 pass.
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 & why
The crown is winner-take-all per direction: the best-rate miner earns the full pool whether their rate is 0.5% or 30% below market, so there's no marginal incentive to quote deeper. This scales crown reward by how far the rate beats a per-direction "market" reference, floored at 0.5 (forgiving, mirroring
volume_factor). The unearned remainder recycles.The reference is self-referential: a trimmed, volume-weighted, recency-decayed average of the subnet's own completed-swap clearing rates — no external oracle, no contract change. Trim + volume-weight + per-miner cap defend it against wash manipulation.
Changes
state_store.py):clearing_ratecolumn onswap_outcomes(CREATE + idempotent ALTER migration);get_clearing_rates_by_direction_sinceexcludesclearing_rate=0(legacy/timed-out) rows.event_watcher.py):SwapCompletedresolves the swap's snapshotted rate from the live tracker; unparseable → 0.0.scoring.py):compute_quality_reference/direction_aware_improvement/quality_factorhelpers; aquality_weighted_blocksaccumulator parallel tocap_weighted_blocks, folded into reward asbase × vol_factor × quality(independent multiply — compounds to 0.25 worst case).scoring_trace.py):quality_fsurfaced in the scoring log.Safeguards
(rate, block, miner, vol)+math.fsum;now_block = window_end; no wall-clock. Guarded by a shuffle-invariance test.QUALITY_N_MINobservations (factor 1.0) → the feature is a guaranteed no-op at deploy until real swap history accrues (legacy rows haveclearing_rate=0).Scope (deliberately narrow)
Depth only. No breadth/rank-spillage. No σ-gate edge-sitter exclusion — that belongs to the reservation-bid-window workstream, which makes edge-sitters arbitrageable so the market polices them. The hard
is_executable_ratedust floor stays.QUALITY_ANCHOR(0.05) is a placeholder — calibrate against live rate dispersion before trusting it.Tests
23 new (reference math incl. shuffle-invariance, factor shape, e2e weighting incl. bootstrap/direction/stacking, storage round-trip, watcher population). Full suite 685 pass.