userGroups write triggers skip any grant with a future toAt, so a future-dated INSERT evades the deleted-user, inactive-group and enamel-admin-minimum guards while the corrected read counts it as current
Write-side liveness on public.userGroups is 'toAt IS NULL'; read-side liveness (fn_terraLiveGroupMembership, enamel_084) is 'toAt IS NULL OR toAt > now()'. All four write triggers gate on WHEN (new.toAt IS NULL AND new.deletedAt IS NULL), so an INSERT carrying a FUTURE toAt is invisible to tg_userGroups_forbidGrantForDeletedUser, tg_userGroups_forbidGrantForInactiveGroup and tg_userGroups_guardEnamelAdminMinimum, and the corrected read then counts that row as current. Source fix: align the trigger WHEN clauses to the read predicate. guardEnamelAdminMinimum is the one that matters most and differs IN KIND: the other two validate a row and a reader can re-check them (enamel_084's core re-checks users.deletedAt and groups.isActive itself, so the core is not the exposure), but guardEnamelAdminMinimum defends an invariant ACROSS rows, which no per-row re-check can reconstruct - a future-dated write can leave the admin minimum violated with nothing in the system aware. Census 2026-10-06, SELECT-only, fleet-wide: ZERO rows with a future toAt in any appKey, zero on a deleted user, zero on an inactive or deleted group, zero future fromAt, and the enamel admin minimum is 1 under BOTH predicates - so this is LATENT with no current violator, not absent. Acceptance: (1) trigger WHEN clauses aligned to the read predicate; (2) forced red that CREATES a future-toAt INSERT against a deleted user and against the admin-minimum boundary and sees each REFUSED where it previously succeeded - today's population contains none of these, so a rehearsal over live shape proves nothing and the arms must be minted; (3) audit design-ping BEFORE implementing, Class-A, it changes which writes get validated. Found while answering pmmaster's constraint-read invitation on TERRA-277 (coder-enamel-cc-muwed7lskedu, ruled by pmmaster muwedv86j0e1). Distinct from ENAMEL-78, which is the groups.value rename/immutability defect plus the unguarded groups.deletedAt soft-delete; does NOT block enamel_084, whose core re-checks what it needs.
Activity
-
Duplicate of ENAMEL-81, filed by pmmaster-evolutiva-cc for the same userGroups future-toAt trigger asymmetry within the same minute. Full content, census and acceptance folded onto ENAMEL-81.