cancelDelaySeconds changes apply retroactively to existing positions
Admin updates to cancelDelaySeconds apply retroactively because the cancel check reads the current global value. A live position created under one delay can be cancelled under another, weakening the user-facing guarantee.
Description
updateCancelDelay() at L329 modifies the global cancelDelaySeconds. The cancel check at L787 reads this global value at cancel-time:
uint256 cancelAfter = uint256(position.createdAt) + cancelDelaySeconds;
If a user creates a position when the delay is 10 minutes and the admin later changes it to 1 hour, that position's lock-up is retroactively extended. The position was created under one set of rules and cancelled under another.
This works in both directions, increasing the delay locks existing Created positions longer than expected, while decreasing it to 0 makes all Created positions immediately cancellable.
The impact is bounded by MAX_CANCEL_DELAY_SECONDS (1 hour) and the short window positions typically spend in Created state. However, this becomes more relevant if cancelPosition is made user-callable (per L-01), since the delay would then function as a user-facing guarantee that can be retroactively changed.
Recommendation
Snapshot the applicable delay per-position at creation time. Add a field to PositionVault:
uint32 appliedCancelDelaySeconds;
Set it in storeNewPosition, and read it in cancelPosition instead of the global:
uint256 cancelAfter = uint256(position.createdAt) + uint256(position.appliedCancelDelaySeconds);
Resolution
Hardened. updateCancelDelay moved to onlyTimelock so retroactive changes traverse the timelock delay.

