PR #934 added MasternodeListEngine::rotation_quorum_type, which keeps the configured type authoritative everywhere the deployment fixes it and falls back to the served commitments only on a devnet that was never told its type via set_devnet_isd_type. That covers feed_qr_info's active-set path and stops such a devnet from aborting every QRInfo feed, but the rest of the rotation code still calls self.network.isd_llmq_type() directly:
validate_and_store_previous_cycle_quorums looks the previous cycle's quorums up under the configured type. On an unconfigured devnet whose deployed type differs, mn_list.quorums.get(&isd_type) misses and previous-cycle enrichment silently does nothing, so InstantSend locks from the previous cycle stay unverifiable.
is_cycle_fully_verified compares the stored cycle length against the configured type's active_quorum_count. A different deployed type has a different count, so the anti-downgrade gate and the "cycle complete" check both judge against the wrong number.
Both are soft failures (no abort, no wrong data accepted), which is why PR #934 left them alone.
Suggested direction
Resolve the rotation type once per feed and thread it through the previous-cycle path and the storage gate instead of re-deriving it from the network in each function. store_cycle_if_fully_verified already takes the type as a parameter, so the shape exists. Alternatively, record the resolved type on the engine the first time an unconfigured devnet sees a rotating commitment, so every path reads one value.
PR #934 added
MasternodeListEngine::rotation_quorum_type, which keeps the configured type authoritative everywhere the deployment fixes it and falls back to the served commitments only on a devnet that was never told its type viaset_devnet_isd_type. That coversfeed_qr_info's active-set path and stops such a devnet from aborting every QRInfo feed, but the rest of the rotation code still callsself.network.isd_llmq_type()directly:validate_and_store_previous_cycle_quorumslooks the previous cycle's quorums up under the configured type. On an unconfigured devnet whose deployed type differs,mn_list.quorums.get(&isd_type)misses and previous-cycle enrichment silently does nothing, so InstantSend locks from the previous cycle stay unverifiable.is_cycle_fully_verifiedcompares the stored cycle length against the configured type'sactive_quorum_count. A different deployed type has a different count, so the anti-downgrade gate and the "cycle complete" check both judge against the wrong number.Both are soft failures (no abort, no wrong data accepted), which is why PR #934 left them alone.
Suggested direction
Resolve the rotation type once per feed and thread it through the previous-cycle path and the storage gate instead of re-deriving it from the network in each function.
store_cycle_if_fully_verifiedalready takes the type as a parameter, so the shape exists. Alternatively, record the resolved type on the engine the first time an unconfigured devnet sees a rotating commitment, so every path reads one value.