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): preserve tstzrange endpoint inclusivity in membership overlap admission #618
After #617 closes the unbounded-range NULL bypass, the #616 storage trigger still compares only scalar lower()/upper() timestamps with <=. That loses the inclusivity metadata carried by PostgreSQL tstzrange uncertainty windows.
0006_typed_membership_assignment permits non-empty ranges with inclusive or exclusive endpoints. The share-budget rule is intentionally conservative only when two memberships can overlap. Two uncertainty envelopes that merely meet at timestamp t cannot overlap when at least one relevant endpoint excludes t, but the current scalar predicate treats equality as overlap unconditionally.
Example: an existing membership has valid_to_window = '[2026-04-10,2026-04-11)' and a candidate has valid_from_window = '[2026-04-11,2026-04-11]'. The existing end can never reach 2026-04-11, so the spells are disjoint. The current upper(existing.valid_to_window) == lower(candidate.valid_from_window) comparison nevertheless rejects a second full share.
This is a buyer/scientific correctness issue in the opposite direction from #617: fail-closed storage must not silently collapse valid time-varying disjoint spells into a false overlap.
Required RED
On #615 or its verified successor, add canonical embedded PostgreSQL 18 contracts proving:
excluded existing upper endpoint + included candidate lower endpoint at the same timestamp is disjoint and remains admissible;
included existing upper endpoint + included candidate lower endpoint at the same timestamp is a real possible overlap and rejects an over-budget write;
included existing upper endpoint + excluded candidate lower endpoint at the same timestamp is disjoint and remains admissible;
Preserve PostgreSQL range semantics directly. Prefer constructing the possible-activity envelope from the earliest admissible start and latest admissible end while retaining endpoint inclusivity, then use range-overlap semantics (&&) rather than timestamp nudging, epsilon/tolerance, or ad hoc microsecond arithmetic. Open-ended and unbounded uncertainty must remain supported.
Do not change the exact binary64 share arithmetic, tenant/observed-unit/role guard serialization, row-local (0,1] constraint, or historical migrations.
Acceptance
Keep open until public RED -> minimal owner-consistent repair, exact-head live PostgreSQL evidence, coverage/security/review, prerequisite landing/restack, and downstream #604 recovery are complete.
Current surviving #615 head is now def43f135a75d6d20ed51ee918b902ede0ddf8cf. The only delta after causal repair ebd816eb... is compile/API doctoring: the new live-test helper originally declared Result<u64, PersistenceError> while canonical SqlSession::execute returns Result<(), PersistenceError>; def43f13... aligns the test helper to that existing API without changing production semantics. Fresh exact-head Rust Foundation 35461497979 is queued with all four jobs still pre-checkout, so no GREEN claim or blind rerun.
Activity
seonghobae commentedon Sep 19, 2026
#615 now carries the endpoint-semantics repair ordinary-forward.
bed68e3aceb49170a5a984622940159f22c26456ebd816eb9d8153d54905273aefe05ae7846fc767tstzrangefrom earliest admissible start to latest admissible end;&&instead of scalar<=, timestamp nudging, or tolerance;Fresh exact-head hosted evidence is still pending, so #618 remains open and no GREEN/merge claim is made.
seonghobae commentedon Sep 19, 2026
Current surviving #615 head is now
def43f135a75d6d20ed51ee918b902ede0ddf8cf. The only delta after causal repairebd816eb...is compile/API doctoring: the new live-test helper originally declaredResult<u64, PersistenceError>while canonicalSqlSession::executereturnsResult<(), PersistenceError>;def43f13...aligns the test helper to that existing API without changing production semantics. Fresh exact-head Rust Foundation35461497979is queued with all four jobs still pre-checkout, so no GREEN claim or blind rerun.