Root cause: expires_at == today was NOT filtered (used '< today'), so a
product expiring ON today kept its resources in desired scopes -> no diff
-> no removal. Changed to '<='. Applied to W3 (CP + grant loops) and W2
(active filter). Also W2 previously had NO expiry filter on active CPs at
all.
AList expects bare token (not 'Bearer <token>'). With 'Bearer' prefix,
all role/get calls returned non-data responses -> currentPaths degraded
to [] -> W3 kept re-applying same scopes every run (false toAdd) and
never detected expired scopes (false toRemove). This is the root cause
of W3 not showing hoe's expiry removal.
When CP record is drafted with product set before customer,
the webhook fires with customerId=null -> now returns
skipWriteBack=true (routed to No-op) instead of throwing.
Record re-fires webhook properly once customer field is set.