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
Blocked-by: #6250 (the shared predicate must land first — PR #6541)
Filed by the #6250 developer agent per that issue's ruling: "OUT OF SCOPE — the two out-of-lane consumers. packages/services/service-messaging/** (domain:services) ... must NOT be edited. Migrating them onto the predicate is a follow-up per lane, filed once the predicate exists." The predicate now exists, so this is that filing.
What is left
packages/services/service-messaging/src/messaging-service.ts declares a private isUniqueViolation(err) — the most complete of the four copies #6250 inventoried, and the one isUniqueViolationError in @objectstack/types was seeded from:
One call site: the lost check-then-act race on the inbox read-receipt unique index (isUniqueViolation(err) && (await flipToRead())).
Why this is finding and not a defect
No user hits anything today. This copy is three-dialect complete — it is the copy that was right. The cost is the fork itself: the next driver quirk gets taught to whichever copy its discoverer is standing in, and the two silently diverge. That is exactly how the REST copy came to miss MySQL while this one did not. Grade it in triage; do not read the finding label as "small".
The migration
@objectstack/service-messaging already depends on @objectstack/types, so this is an import swap plus deleting the local function. The shared predicate is a strict superset of this one on every channel:
same three codes, plus MySQL's errno 1062 (the numeric field mysql2 sets beside code for the same condition);
additionally follows one bounded step down the cause chain, which pool and query-builder layers wrap with — service-messaging's copy would return false on a wrapped conflict and silently skip the flipToRead() fallback.
That last point is the only behaviour change, and it is in the direction the call site wants (a wrapped conflict is still a conflict). Worth a test at the call site rather than a blind swap.
Blocked-by: #6250 (the shared predicate must land first — PR #6541)
Filed by the #6250 developer agent per that issue's ruling: "OUT OF SCOPE — the two out-of-lane consumers.
packages/services/service-messaging/**(domain:services) ... must NOT be edited. Migrating them onto the predicate is a follow-up per lane, filed once the predicate exists." The predicate now exists, so this is that filing.What is left
packages/services/service-messaging/src/messaging-service.tsdeclares a privateisUniqueViolation(err)— the most complete of the four copies #6250 inventoried, and the oneisUniqueViolationErrorin@objectstack/typeswas seeded from:One call site: the lost check-then-act race on the inbox read-receipt unique index (
isUniqueViolation(err) && (await flipToRead())).Why this is
findingand not a defectNo user hits anything today. This copy is three-dialect complete — it is the copy that was right. The cost is the fork itself: the next driver quirk gets taught to whichever copy its discoverer is standing in, and the two silently diverge. That is exactly how the REST copy came to miss MySQL while this one did not. Grade it in triage; do not read the
findinglabel as "small".The migration
@objectstack/service-messagingalready depends on@objectstack/types, so this is an import swap plus deleting the local function. The shared predicate is a strict superset of this one on every channel:errno 1062(the numeric field mysql2 sets besidecodefor the same condition);unique constraintandunique violation(inherited from the REST limb 唯一约束冲突没有单一判别谓词:仓内四套各自为政的方言词表,REST 的 409 映射漏掉 MySQL(Duplicate entry落成 500 INTERNAL_ERROR) #6250 replaced), sounique constraint failedis subsumed;causechain, which pool and query-builder layers wrap with —service-messaging's copy would returnfalseon a wrapped conflict and silently skip theflipToRead()fallback.That last point is the only behaviour change, and it is in the direction the call site wants (a wrapped conflict is still a conflict). Worth a test at the call site rather than a blind swap.