@@ -81,9 +81,9 @@ const seedEvent = async ({
8181 } )
8282}
8383
84- const unsentCount = async ( windowKey : string ) : Promise < number > => {
84+ const totalCount = async ( windowKey : string ) : Promise < number > => {
8585 const rows = await getTestDb ( ) . $queryRaw < { count : bigint } [ ] > `
86- SELECT count(*) FROM "GroupedEmailEvents" WHERE "windowKey" = ${ windowKey } AND "sentAt" IS NULL `
86+ SELECT count(*) FROM "GroupedEmailEvents" WHERE "windowKey" = ${ windowKey } `
8787 return Number ( rows [ 0 ] . count )
8888}
8989
@@ -99,7 +99,7 @@ beforeEach(async () => {
9999afterAll ( disconnectTestDb )
100100
101101describe ( 'flush-grouped-email idempotency (real DB)' , ( ) => {
102- it ( 'sends one grouped email for multiple events and marks every row as sent ' , async ( ) => {
102+ it ( 'sends one grouped email for multiple events and deletes all rows on success ' , async ( ) => {
103103 const window = 'win_multi_event'
104104 const taskA = await seedTask ( { workspaceId : WS , assigneeId : CLIENT_A , assigneeType : 'client' , companyId : COMPANY } )
105105 const taskB = await seedTask ( { workspaceId : WS , assigneeId : CLIENT_A , assigneeType : 'client' , companyId : COMPANY } )
@@ -120,7 +120,7 @@ describe('flush-grouped-email idempotency (real DB)', () => {
120120
121121 expect ( mockCreateNotification ) . toHaveBeenCalledTimes ( 1 )
122122 expect ( result ) . toMatchObject ( { recipients : 1 , sent : 1 , sentGrouped : 1 , sentIndividual : 0 } )
123- expect ( await unsentCount ( window ) ) . toBe ( 0 )
123+ expect ( await totalCount ( window ) ) . toBe ( 0 )
124124 } )
125125
126126 it ( 'is idempotent: re-flushing a fully-sent window is a no-op' , async ( ) => {
@@ -142,8 +142,9 @@ describe('flush-grouped-email idempotency (real DB)', () => {
142142
143143 await flushGroupedEmailRun ( { workspaceId : WS , windowKey : window } )
144144 expect ( mockCreateNotification ) . toHaveBeenCalledTimes ( 1 )
145+ expect ( await totalCount ( window ) ) . toBe ( 0 )
145146
146- // Second flush: all rows already have sentAt set — no email, skipped return.
147+ // Second flush: rows were deleted — no email, skipped return.
147148 const result = await flushGroupedEmailRun ( { workspaceId : WS , windowKey : window } )
148149 expect ( mockCreateNotification ) . toHaveBeenCalledTimes ( 1 )
149150 expect ( result ) . toMatchObject ( { skipped : true } )
@@ -169,14 +170,14 @@ describe('flush-grouped-email idempotency (real DB)', () => {
169170 mockCreateNotification . mockRejectedValueOnce ( new Error ( 'copilot 5xx' ) )
170171 await expect ( flushGroupedEmailRun ( { workspaceId : WS , windowKey : window } ) ) . rejects . toThrow ( 'copilot 5xx' )
171172
172- // Rows are still unsent — retry can re-attempt.
173- expect ( await unsentCount ( window ) ) . toBe ( 2 )
173+ // Failed run: rows are preserved so the retry can re-attempt.
174+ expect ( await totalCount ( window ) ) . toBe ( 2 )
174175
175- // Retry succeeds.
176+ // Retry succeeds: rows are deleted .
176177 mockCreateNotification . mockResolvedValueOnce ( { id : 'notif_2' } )
177178 await flushGroupedEmailRun ( { workspaceId : WS , windowKey : window } )
178179 expect ( mockCreateNotification ) . toHaveBeenCalledTimes ( 2 )
179- expect ( await unsentCount ( window ) ) . toBe ( 0 )
180+ expect ( await totalCount ( window ) ) . toBe ( 0 )
180181 } )
181182
182183 it ( 'sends one email per recipient when the window holds events for multiple clients' , async ( ) => {
@@ -217,10 +218,10 @@ describe('flush-grouped-email idempotency (real DB)', () => {
217218 const recipients = mockCreateNotification . mock . calls . map ( ( c ) => c [ 0 ] . recipientClientId ) . sort ( )
218219 expect ( recipients ) . toEqual ( [ CLIENT_A , CLIENT_B ] . sort ( ) )
219220 expect ( result ) . toMatchObject ( { recipients : 2 , sent : 2 , sentGrouped : 2 , sentIndividual : 0 } )
220- expect ( await unsentCount ( window ) ) . toBe ( 0 )
221+ expect ( await totalCount ( window ) ) . toBe ( 0 )
221222 } )
222223
223- it ( 'skips events for archived tasks and marks their rows sent without emailing ' , async ( ) => {
224+ it ( 'skips events for archived tasks and deletes all rows on success ' , async ( ) => {
224225 const window = 'win_archived'
225226 const archivedTask = await seedTask ( {
226227 workspaceId : WS ,
@@ -244,11 +245,10 @@ describe('flush-grouped-email idempotency (real DB)', () => {
244245 // Only the live task appears in the grouped email (1 event); individual snapshot path.
245246 expect ( mockCreateNotification ) . toHaveBeenCalledTimes ( 1 )
246247 expect ( result ) . toMatchObject ( { sentGrouped : 0 , sentIndividual : 1 } )
247- // All rows are marked sent regardless of whether the task was live.
248- expect ( await unsentCount ( window ) ) . toBe ( 0 )
248+ expect ( await totalCount ( window ) ) . toBe ( 0 )
249249 } )
250250
251- it ( 'marks the recipient sent without emailing when every task in the window was archived' , async ( ) => {
251+ it ( 'deletes rows without emailing when every task in the window was archived' , async ( ) => {
252252 const window = 'win_all_archived'
253253 const archivedTask = await seedTask ( {
254254 workspaceId : WS ,
@@ -263,10 +263,10 @@ describe('flush-grouped-email idempotency (real DB)', () => {
263263
264264 expect ( mockCreateNotification ) . not . toHaveBeenCalled ( )
265265 expect ( result ) . toMatchObject ( { sent : 0 } )
266- expect ( await unsentCount ( window ) ) . toBe ( 0 )
266+ expect ( await totalCount ( window ) ) . toBe ( 0 )
267267 } )
268268
269- it ( 'marks the recipient sent without emailing when every task in the window was soft-deleted' , async ( ) => {
269+ it ( 'deletes rows without emailing when every task in the window was soft-deleted' , async ( ) => {
270270 const window = 'win_all_deleted'
271271 const deletedTask = await seedTask ( {
272272 workspaceId : WS ,
@@ -281,6 +281,6 @@ describe('flush-grouped-email idempotency (real DB)', () => {
281281
282282 expect ( mockCreateNotification ) . not . toHaveBeenCalled ( )
283283 expect ( result ) . toMatchObject ( { sent : 0 } )
284- expect ( await unsentCount ( window ) ) . toBe ( 0 )
284+ expect ( await totalCount ( window ) ) . toBe ( 0 )
285285 } )
286286} )
0 commit comments