Extract shared crown-eligibility predicates so scoring and live-crown can't drift#454
Merged
Merged
Conversation
added 3 commits
June 8, 2026 12:36
The scoring replay (replay_crown_time_window) and the live-crown snapshot (snapshot_current_crown_holders) each hand-copied the executable_check and can_fund eligibility predicates. The two paths must return identical verdicts or the dashboard's live crown holder diverges from who the ledger actually rewards, but that invariant was enforced only by copy-paste. Consolidate both into a single make_crown_predicates factory so the invariant is structural. Calling the factory once per direction also removes the loop-variable default-arg binding the snapshot copy needed. Pure refactor, no behavior change. Adds a parity test locking the factory's semantics to is_executable_rate / min_executable_tao_leg. Fixes #450
End-to-end guard for the #450 invariant: feed both replay_crown_time_window and snapshot_current_crown_holders identical state and assert they resolve the crown to the same holder (squatter dropped by both via the funding gate). Catches a future one-sided divergence even if it bypassed the factory.
entrius
approved these changes
Jun 8, 2026
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
The per-block scoring replay (
replay_crown_time_window) and the per-forward-step live-crown snapshot (snapshot_current_crown_holders) each hand-copied the same two crown-eligibility predicates —executable_checkandcan_fund. The code documents that these paths must return identical verdicts (otherwise the dashboard's live crown holder diverges from who the ledger actually rewards), but that invariant was enforced only by copy-paste.This extracts both into a single
make_crown_predicates(...)factory inscoring.py, so the invariant is structural rather than convention.Why
Not cosmetic dedup — the duplication backed a documented correctness invariant. A one-sided edit to the fail-open-on-unknown-collateral rule or the bounds gate would silently desync the live view from the rewarded ledger. This subnet has already been bitten by live-crown-vs-ledger divergence (the v1.0.9 collateral-zeroing mass-recycle, #443).
Changes
allways/validator/scoring.py: addmake_crown_predicates; both functions call it. Calling it once per direction also removes the loop-variable default-arg binding the snapshot copy needed (eliminates a late-binding footgun).tests/test_scoring_v1.py: newTestCrownPredicateParity— matrix parity test locking the factory tois_executable_rate/min_executable_tao_leg(both directions × bounds set/unset × edge rates × collateral configs), plus explicit fail-open-on-absent and boundary-squat-drop cases.Scope / risk
snapshot_current_crown_holdersis still called unconditionally every forward step; only its internals change.Verification
tests/test_scoring_v1.py: 151 passed (incl. 3 new), before and afterruff format.ruff check: clean.embitcollection errors in chain-provider test files are unrelated (this diff touches neither chain providers nor their tests).Fixes #450