@@ -164,6 +164,48 @@ describe("createIfAbsent", () => {
164164 }
165165 }
166166 ) ;
167+
168+ redisTest (
169+ "reads a COMPLETED record back through createIfAbsent, with an envelope" ,
170+ async ( { redisOptions } ) => {
171+ const store = coordinator ( redisOptions ) ;
172+ try {
173+ await store . createIfAbsent ( {
174+ record : record ( "w_a" ) ,
175+ status : "COMPLETED" ,
176+ completion : completion ( ) ,
177+ } ) ;
178+
179+ const second = await store . createIfAbsent ( { record : record ( "w_a" ) , status : "PENDING" } ) ;
180+
181+ expect ( second . outcome ) . toBe ( "exists" ) ;
182+ if ( second . outcome !== "exists" ) throw new Error ( "unreachable" ) ;
183+ expect ( second . status ) . toBe ( "COMPLETED" ) ;
184+ expect ( second . completion ?. output ) . toEqual ( { inline : '{"ok":true}' } ) ;
185+ } finally {
186+ await store . quit ( ) ;
187+ }
188+ }
189+ ) ;
190+
191+ redisTest (
192+ "reads a COMPLETED record back through createIfAbsent, with no envelope" ,
193+ async ( { redisOptions } ) => {
194+ const store = coordinator ( redisOptions ) ;
195+ try {
196+ await store . createIfAbsent ( { record : record ( "w_a" ) , status : "COMPLETED" } ) ;
197+
198+ const second = await store . createIfAbsent ( { record : record ( "w_a" ) , status : "PENDING" } ) ;
199+
200+ expect ( second . outcome ) . toBe ( "exists" ) ;
201+ if ( second . outcome !== "exists" ) throw new Error ( "unreachable" ) ;
202+ expect ( second . status ) . toBe ( "COMPLETED" ) ;
203+ expect ( second . completion ) . toBeUndefined ( ) ;
204+ } finally {
205+ await store . quit ( ) ;
206+ }
207+ }
208+ ) ;
167209} ) ;
168210
169211describe ( "registerOrReport" , ( ) => {
@@ -746,6 +788,51 @@ describe("createWithIdempotencyKey", () => {
746788 }
747789 } ) ;
748790
791+ redisTest (
792+ "the original creator's own retry does not discard its own record" ,
793+ async ( { redisOptions } ) => {
794+ const store = coordinator ( redisOptions ) ;
795+ const probe = createRedisClient ( redisOptions ) ;
796+ try {
797+ const withKey = record ( idA , {
798+ idempotencyKey : "key-1" ,
799+ userProvidedIdempotencyKey : true ,
800+ } ) ;
801+
802+ const first = await store . createWithIdempotencyKey ( {
803+ record : withKey ,
804+ environmentId : ENV_ID ,
805+ idempotencyKey : "key-1" ,
806+ } ) ;
807+ expect ( first ) . toEqual ( { waitpointId : idA , created : true } ) ;
808+
809+ // The SAME caller, retrying with the SAME record id and the SAME key — not a
810+ // different id racing for the same reservation.
811+ const retry = await store . createWithIdempotencyKey ( {
812+ record : withKey ,
813+ environmentId : ENV_ID ,
814+ idempotencyKey : "key-1" ,
815+ } ) ;
816+
817+ expect ( retry ) . toEqual ( { waitpointId : idA , created : false } ) ;
818+ // The record must survive: a wrongly-discarded record would delete this too.
819+ expect ( await probe . exists ( `wp:{${ idA } }` ) ) . toBe ( 1 ) ;
820+
821+ // The real proof: something usable is still there for every later caller that
822+ // blocks on this id.
823+ const registered = await store . registerOrReport ( {
824+ waitpointId : idA ,
825+ runId : "run_1" ,
826+ createdAt : NOW ,
827+ } ) ;
828+ expect ( registered . outcome ) . toBe ( "registered" ) ;
829+ } finally {
830+ probe . disconnect ( ) ;
831+ await store . quit ( ) ;
832+ }
833+ }
834+ ) ;
835+
749836 redisTest ( "sets no expiry when the record carries none" , async ( { redisOptions } ) => {
750837 const store = coordinator ( redisOptions ) ;
751838 const probe = createRedisClient ( redisOptions ) ;
@@ -918,6 +1005,51 @@ describe("absorbBlockers", () => {
9181005 }
9191006 ) ;
9201007
1008+ redisTest (
1009+ "a later absorb reads back the stored envelope, not a bare flag" ,
1010+ async ( { redisOptions } ) => {
1011+ const store = coordinator ( redisOptions ) ;
1012+ try {
1013+ const envelope = completion ( { output : { inline : '{"first":true}' } } ) ;
1014+
1015+ // Reported once, with an envelope — this write is what's under test.
1016+ await store . absorbBlockers ( {
1017+ runId : RUN_ID ,
1018+ edges : [ edge ( "w_a" , { reported : { completion : envelope } } ) ] ,
1019+ } ) ;
1020+
1021+ // Same waitpoint id, arriving unreported this time: takes the "read `done` back"
1022+ // path, exposing whatever the first call actually stored under that id.
1023+ const second = await store . absorbBlockers ( { runId : RUN_ID , edges : [ edge ( "w_a" ) ] } ) ;
1024+
1025+ expect ( second . alreadyDelivered ) . toHaveLength ( 1 ) ;
1026+ expect ( second . alreadyDelivered [ 0 ] ! . completion ) . toEqual ( envelope ) ;
1027+ } finally {
1028+ await store . quit ( ) ;
1029+ }
1030+ }
1031+ ) ;
1032+
1033+ redisTest (
1034+ "a later absorb for a no-envelope delivery reads back no completion" ,
1035+ async ( { redisOptions } ) => {
1036+ const store = coordinator ( redisOptions ) ;
1037+ try {
1038+ await store . absorbBlockers ( {
1039+ runId : RUN_ID ,
1040+ edges : [ edge ( "w_a" , { reported : { } } ) ] ,
1041+ } ) ;
1042+
1043+ const second = await store . absorbBlockers ( { runId : RUN_ID , edges : [ edge ( "w_a" ) ] } ) ;
1044+
1045+ expect ( second . alreadyDelivered ) . toHaveLength ( 1 ) ;
1046+ expect ( second . alreadyDelivered [ 0 ] ! . completion ) . toBeUndefined ( ) ;
1047+ } finally {
1048+ await store . quit ( ) ;
1049+ }
1050+ }
1051+ ) ;
1052+
9211053 redisTest ( "reports a repeated already-delivered id once" , async ( { redisOptions } ) => {
9221054 const store = coordinator ( redisOptions ) ;
9231055 try {
@@ -1544,3 +1676,162 @@ describe("the resume cycle drains and can start again", () => {
15441676 }
15451677 } ) ;
15461678} ) ;
1679+
1680+ // Every test above is a sequence of awaits. Redis guarantees atomicity WITHIN a script, so
1681+ // those tests can only ever prove single-script invariants. These races drive real
1682+ // concurrent calls (Promise.all over N copies) against the multi-script TypeScript
1683+ // sequences, and assert an invariant that holds regardless of who wins — never a timing.
1684+ describe ( "genuine concurrency" , ( ) => {
1685+ const CONCURRENCY = 8 ;
1686+
1687+ redisTest (
1688+ "exactly one of N concurrent completers wins, and every caller sees its completion" ,
1689+ async ( { redisOptions } ) => {
1690+ const store = coordinator ( redisOptions ) ;
1691+ try {
1692+ await store . createIfAbsent ( { record : record ( "w_a" ) , status : "PENDING" } ) ;
1693+ await store . registerOrReport ( { waitpointId : "w_a" , runId : "run_1" , createdAt : NOW } ) ;
1694+ await store . registerOrReport ( { waitpointId : "w_a" , runId : "run_2" , createdAt : NOW } ) ;
1695+
1696+ const results = await Promise . all (
1697+ Array . from ( { length : CONCURRENCY } , ( _ , i ) =>
1698+ store . complete ( {
1699+ waitpointId : "w_a" ,
1700+ completion : completion ( { output : { inline : `{"racer":${ i } }` } } ) ,
1701+ } )
1702+ )
1703+ ) ;
1704+
1705+ const winners = results . filter ( ( r ) => r . outcome === "completed" ) ;
1706+ const losers = results . filter ( ( r ) => r . outcome === "already" ) ;
1707+ expect ( winners ) . toHaveLength ( 1 ) ;
1708+ expect ( losers ) . toHaveLength ( CONCURRENCY - 1 ) ;
1709+
1710+ // Every caller, winner and losers alike, reads back the SAME stored completion.
1711+ const stored = winners [ 0 ] ! . completion ;
1712+ for ( const r of results ) {
1713+ expect ( r . completion ) . toEqual ( stored ) ;
1714+ }
1715+
1716+ // And every caller returns the full watcher list — a race must never truncate it.
1717+ for ( const r of results ) {
1718+ expect ( r . watchers . map ( ( w ) => w . runId ) . sort ( ) ) . toEqual ( [ "run_1" , "run_2" ] ) ;
1719+ }
1720+ } finally {
1721+ await store . quit ( ) ;
1722+ }
1723+ }
1724+ ) ;
1725+
1726+ redisTest (
1727+ "a pre-existing registration survives N concurrent attempts to re-register its field" ,
1728+ async ( { redisOptions } ) => {
1729+ const store = coordinator ( redisOptions ) ;
1730+ try {
1731+ await store . createIfAbsent ( { record : record ( "w_a" ) , status : "PENDING" } ) ;
1732+ await store . registerOrReport ( {
1733+ waitpointId : "w_a" ,
1734+ runId : "run_1" ,
1735+ spanIdToComplete : "span_first" ,
1736+ createdAt : NOW ,
1737+ } ) ;
1738+
1739+ // Same run, same (absent) batch index as the registration above, so every one of
1740+ // these collides on the exact same watcher field.
1741+ await Promise . all (
1742+ Array . from ( { length : CONCURRENCY } , ( _ , i ) =>
1743+ store . registerOrReport ( {
1744+ waitpointId : "w_a" ,
1745+ runId : "run_1" ,
1746+ spanIdToComplete : `span_racer_${ i } ` ,
1747+ createdAt : NOW ,
1748+ } )
1749+ )
1750+ ) ;
1751+
1752+ const completed = await store . complete ( { waitpointId : "w_a" , completion : completion ( ) } ) ;
1753+ const forRun1 = completed . watchers . filter ( ( w ) => w . runId === "run_1" ) ;
1754+ expect ( forRun1 ) . toHaveLength ( 1 ) ;
1755+ expect ( forRun1 [ 0 ] ! . spanIdToComplete ) . toBe ( "span_first" ) ;
1756+ } finally {
1757+ await store . quit ( ) ;
1758+ }
1759+ }
1760+ ) ;
1761+
1762+ redisTest (
1763+ "exactly one of N concurrent idempotency-keyed creators wins, and every loser cleans up" ,
1764+ async ( { redisOptions } ) => {
1765+ const store = coordinator ( redisOptions ) ;
1766+ const probe = createRedisClient ( redisOptions ) ;
1767+ try {
1768+ const ids = Array . from ( { length : CONCURRENCY } , ( ) => generateWaitpointId ( "MANUAL" ) ) ;
1769+
1770+ const results = await Promise . all (
1771+ ids . map ( ( id ) =>
1772+ store . createWithIdempotencyKey ( {
1773+ record : record ( id , { idempotencyKey : "key-1" , userProvidedIdempotencyKey : true } ) ,
1774+ environmentId : ENV_ID ,
1775+ idempotencyKey : "key-1" ,
1776+ } )
1777+ )
1778+ ) ;
1779+
1780+ const winners = results . filter ( ( r ) => r . created ) ;
1781+ expect ( winners ) . toHaveLength ( 1 ) ;
1782+
1783+ const winnerId = winners [ 0 ] ! . waitpointId ;
1784+ for ( const r of results ) {
1785+ expect ( r . waitpointId ) . toBe ( winnerId ) ;
1786+ }
1787+ expect ( await probe . exists ( `wp:{${ winnerId } }` ) ) . toBe ( 1 ) ;
1788+
1789+ for ( const id of ids ) {
1790+ if ( id === winnerId ) continue ;
1791+ expect ( await probe . exists ( `wp:{${ id } }` ) ) . toBe ( 0 ) ;
1792+ expect ( await probe . exists ( `wp:{${ id } }:w` ) ) . toBe ( 0 ) ;
1793+ }
1794+ } finally {
1795+ probe . disconnect ( ) ;
1796+ await store . quit ( ) ;
1797+ }
1798+ }
1799+ ) ;
1800+
1801+ redisTest (
1802+ "registerBlocks racing complete never leaves a waitpoint double-booked or the pending count negative" ,
1803+ async ( { redisOptions } ) => {
1804+ const store = coordinator ( redisOptions ) ;
1805+ try {
1806+ for ( let i = 0 ; i < 30 ; i ++ ) {
1807+ const waitpointId = `w_race_${ i } ` ;
1808+ const runId = `run_race_${ i } ` ;
1809+ await store . createIfAbsent ( { record : record ( waitpointId ) , status : "PENDING" } ) ;
1810+
1811+ // Two edges for the SAME waitpoint: registerBlocks registers them one at a
1812+ // time, so a concurrent complete() has a real window to land between the two
1813+ // registrations — the exact straddle that makes absorbBlockers' per-group
1814+ // reported/unreported split matter, rather than racing a single all-or-nothing
1815+ // group.
1816+ const [ blocked ] = await Promise . all ( [
1817+ store . registerBlocks ( {
1818+ runId,
1819+ edges : [ edge ( waitpointId , { batchIndex : 0 } ) , edge ( waitpointId , { batchIndex : 1 } ) ] ,
1820+ } ) ,
1821+ store . complete ( { waitpointId, completion : completion ( ) } ) ,
1822+ ] ) ;
1823+
1824+ const state = await store . readBlockState ( runId ) ;
1825+ const delivered = state . deliveredIds . includes ( waitpointId ) ;
1826+ const pending = state . pendingIds . includes ( waitpointId ) ;
1827+
1828+ expect ( delivered && pending ) . toBe ( false ) ;
1829+ expect ( blocked . storePendingTotal ) . toBeGreaterThanOrEqual ( 0 ) ;
1830+ expect ( blocked . storePendingTotal ) . toBeLessThanOrEqual ( 1 ) ;
1831+ }
1832+ } finally {
1833+ await store . quit ( ) ;
1834+ }
1835+ }
1836+ ) ;
1837+ } ) ;
0 commit comments