This answer was provided by Pieter Wuille (@pwuille) on Twitter.
Conceptually it doesn't make sense, because script conditions are monotonic. What would and(pk(A),not(pk(B)))
mean? "B does not sign" is trivially satisfied; B would just never bother signing.
Similarly, not(older(N))
would not mean younger(N)
. There (intentionally) does not exist a way in script to express a younger-than condition (because it would mean a tx that invalidates itself). "not(older(N))" would just be "do not prove time is past N", also trivial.
For example, Miniscript l:older(N)
translates to IF 0 ELSE <N> CHECKSEQUENCEVERIFY
.
CSV and CLTV don't actually observe the time; they observe the nLocktime/nSequence field in the transaction. There wouldn't be any problems with having an ability in Script to make arbitrary (including less than, negation, ...) statements about them.
However, it would likely be pointless. The nSequence and nLocktime fields themselves do observe time, and can only express larger-than constraints. Bitcoin transaction validity should be monotonic: once valid, absent double-spend, they remain valid.
The alternative would be a logistical nightmare. All mempool transactions would need to be reevaluated every block. Reasoning about validity of unconfirmed transactions would be a pain (e.g. what if you're paid using a tx spending the output of a soon-to-be expired tx?)