refactor(types): centralize proposer selection on ValidatorIndex#732
Merged
tcoratger merged 1 commit intoMay 18, 2026
Merged
Conversation
The round-robin arithmetic `int(slot) % int(num_validators)` was duplicated between `ValidatorIndex.is_proposer_for` and the debug log line in `validator/service.py`. Both sites now derive from one classmethod, so the rule cannot drift. Adds `ValidatorIndex.proposer_for_slot(slot, num_validators)` as a classmethod factory. Returns a `ValidatorIndex`, type lives on the type it returns. `is_proposer_for` becomes a one-line predicate that delegates to the classmethod. Picked over a free function or a method on `Slot`/`Validators`: - Free function felt procedural in an OO codebase where every other selection helper in `types/` is a method. - Method on `Slot` would have needed a forward reference to `ValidatorIndex` and a circular-import workaround. - Method on `Validators` lives in fork-specific code, but the arithmetic is fork-stable. The classmethod sits next to `is_proposer_for` in `types/validator.py`, no new file, no cycle, no fork dependency. A parametric consistency test verifies the classmethod and the predicate agree at every slot for any registry size. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 19, 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.
Summary
The round-robin arithmetic
int(slot) % int(num_validators)wasduplicated between
ValidatorIndex.is_proposer_forand a debug logline in
validator/service.py. Both sites now derive from oneclassmethod, so the consensus-load-bearing rule cannot drift across
call sites.
What changed
types/validator.pyAdded
ValidatorIndex.proposer_for_slot(slot, num_validators)classmethod:
Rewrote
is_proposer_forto delegate:subspecs/validator/service.pyReplaced the second copy of the arithmetic with a call to the
classmethod:
tests/lean_spec/types/test_validator_utils.pyAdded
TestProposerForSlotwith five tests covering round-robin,wraparound, single validator, return type, and a parametric
consistency test that proves
proposer_for_slotandis_proposer_foragree at every slot for any registry size. The consistency test is
the architectural insurance: if either method drifts, it fails loudly.
Design notes
The agent originally suggested a free function. Pushed back during
review because the codebase convention is methods on types
(
Checkpoint.advance_to,JustifiedSlots.is_slot_justified,ValidatorIndex.is_valid,ValidatorIndex.compute_subnet_id).Other placements considered:
Slotwould have read most naturally asslot.proposer(num)buttypes/validator.pyalready importsSlot, so the reverse reference would have required a forward-refstring or function-local import.
Validatorsis the most OO reading — the registryknows its own size and selects its proposer. Blocked:
Validatorslives in fork-specific
forks/lstar/containers/validator.pyandthe arithmetic is fork-stable.
The classmethod on
ValidatorIndexis the idiomatic Python factorypattern: a constructor that returns an instance from inputs. Lives
next to
is_proposer_for, no new file, no cycle, no fork dependency.Test plan
ruff check,ruff format --check,ty checkall passpytest tests/lean_spec/types/test_validator_utils.py tests/lean_spec/subspecs/validator-> 109 passedagree at every slot across registry sizes from 1 to 1000
🤖 Generated with Claude Code