You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(persistence): close unbounded temporal-window bypass in membership share budget #617
The #616 persistence trigger currently reduces temporal uncertainty to two envelope instants:
candidate_start := lower(NEW.valid_from_window)
candidate_end := upper(NEW.valid_to_window) when valid_to_window is non-null
and performs the same lower/upper calls for existing rows.
PostgreSQL range accessors return NULL for an unbounded side. Migration 0006_typed_membership_assignment requires non-empty tstzrange values but does not require finite bounds, so valid direct-SQL rows such as '(,2026-01-01]'::tstzrange or '[2026-01-10,)'::tstzrange are admitted by the schema. In the #616 trigger, those NULL bounds flow into <= predicates and evaluate to unknown/false, so an overlapping same-role share can be omitted from the aggregate. That can persist a state whose owner-equivalent known share exceeds unity.
This is not an application-helper-only concern: #616 explicitly owns direct PostgreSQL parity and must fail closed for every schema-admitted temporal window.
Required RED
On #615 or its verified successor, add PostgreSQL 18 direct-write contracts proving at least:
an existing same-role membership with an upper-unboundedvalid_to_window participates in the budget and prevents a later overlapping overrun;
a candidate with a lower-unboundedvalid_from_window participates in the budget and cannot bypass an existing share;
rejected writes leave the persisted row set unchanged;
The RED must exercise the canonical embedded migration path, not a test-only trigger definition.
Causal repair boundary
Treat schema-admitted unbounded start/end uncertainty as -infinity / infinity only for the conservative overlap envelope used by the storage admission predicate. Do not rewrite historical migrations, narrow 0006 ad hoc, or weaken the #616 binary64/share-budget contract. Preserve tenant/observed-unit/role serialization and exact binary64 numerator arithmetic.
If endpoint inclusivity requires separate refinement, keep it explicit; do not hide it behind tolerance or timestamp nudging.
Acceptance
Keep open until the surviving persistence vehicle has public RED -> minimal forward repair, exact-head live PostgreSQL evidence, owned coverage/security gates, qualifying review, normal prerequisite landing/restack, and downstream #604 recovery.
#617's invariant is preserved by the newer #618 repair. Surviving #615 head is now def43f135a75d6d20ed51ee918b902ede0ddf8cf: ebd816eb... replaced the intermediate scalar -infinity/infinity comparison with a tstzrange possible-activity envelope plus PostgreSQL &&, which natively retains unbounded sides and also fixes endpoint inclusivity. def43f13... is test-helper API doctoring only. Fresh exact-head Rust Foundation 35461497979 remains queued, so #617 stays open pending hosted PostgreSQL proof and the prerequisite landing chain.
Activity
seonghobae commentedon Sep 19, 2026
Owner-path repair is now ordinary-forward on #615.
4ad3a3cef1ef77972d71cb93b7b7627405c901b1valid_to_windowmust remain in the overlap budget;valid_from_windowmust not turn the overlap predicate into SQL UNKNOWN;e598a905627504ea052313d2b5b8508ca6d1c5a1lower(...)=NULLon an unbounded start is mapped to-infinityonly for the conservative envelope comparison;upper(...)=NULLon an unbounded end is mapped toinfinity;(0,1], and historical migrations remain unchanged.Fresh exact-head Rust Foundation run
35461260828is still pending, so this is not promoted to GREEN and #617 remains open.seonghobae commentedon Sep 19, 2026
#617's invariant is preserved by the newer #618 repair. Surviving #615 head is now
def43f135a75d6d20ed51ee918b902ede0ddf8cf:ebd816eb...replaced the intermediate scalar-infinity/infinitycomparison with atstzrangepossible-activity envelope plus PostgreSQL&&, which natively retains unbounded sides and also fixes endpoint inclusivity.def43f13...is test-helper API doctoring only. Fresh exact-head Rust Foundation35461497979remains queued, so #617 stays open pending hosted PostgreSQL proof and the prerequisite landing chain.