The advance builder previously hard-coded the validity range to
[tip_slot, tip_slot + VALIDITY_RANGE_SLOTS=1799]. For early
Draft→VotingReady advance with the wide 1799-slot range, the upper
bound shoots ~30min past starting_time — way past drafting_end on
any DAO with windows narrower than 30 min, including Sulkta-shape
30-min DAOs whose drafting period happens to start partly elapsed.
Validator's getTimingRelation rejects straddles and the MCP layer
then errored 'tx validity range straddles drafting period
boundary'.
Two-part fix:
1. ProposalAdvanceArgs gains optional valid_from_slot_override +
invalid_from_slot_override fields. None preserves legacy behavior;
Some(...) lets the MCP layer dictate a clamped range. Builder
defends against degenerate ranges (invalid_from <= valid_from).
2. MCP-side dao_proposal_advance_unsigned, when transition is
DraftToVotingReady or VotingReadyToLocked and the natural [tip,
tip+1799] would overshoot the period end, clamps invalid_from
to the period_end slot. Refuses if remaining slots < 5 (chain
has no room to include the tx) and prompts the caller to wait
for the failed-too-late path instead.
Caught 2026-05-08 trying to drive preprod_test2 proposal #0
through the proper Draft→VotingReady arc — chain time was ~3 min
past starting_time, so 1799-slot range overshot drafting_end by
~27 min. Same code path now clamps to the remaining ~27 min of
drafting period.
Closes audit finding H-2 for the DraftToVotingReady and
VotingReadyToLocked transitions. Cosign + vote builders also have
H-2 (raw tip_slot for validity_from); those are deferred.