fix(validator): non-earner trace reads live quotes, not dead last_known_rates - #704
Merged
Conversation
…wn_rates non_earner_lines pulled rates from self.last_known_rates, whose writers were deleted in the B3.6 substrate teardown; the getattr default hid the dead reference, so every non-earner was labelled no_rate_posted regardless of cause (a 3-strike miner with a live quote read no_rate_posted, not ineligible). Thread the round's live_quote_rates read into the trace and drop the dead lookup.
Merged
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.
Problem
The scoring trace labelled every non-earner `reason="no_rate_posted"`, regardless of actual cause. `non_earner_lines` read `getattr(self, 'last_known_rates', {})` — but every writer of that attribute was deleted in the B3.6 substrate teardown (87a6732). The `getattr` default masked the dead reference, so the dict was always empty and `diagnose_non_earner` short-circuited on its first branch.
Seen on testnet 2026-08-22: uid 12 (50 ok / 3 fail → struck out, correct per #699) with a live sol→btc quote logged as `no_rate_posted eligible=False`, which sent a debugging session chasing a restart/rate-replay theory that didn't exist. The true reason was `ineligible`.
Fix
No change to reward math or crown logic — diagnostic text only.
Tests
`TestNonEarnerLinesUseLiveRates`: a struck-out miner with a live quote reads `ineligible`; a miner with no live quote still reads `no_rate_posted`.