11/** Local SQL verifies receipt durability, concurrent claims and replay independently of tool completion. */
22
3- import { randomUUID } from 'node:crypto'
43import { readFileSync } from 'node:fs'
4+ import { generateId } from '@sim/utils/id'
55import type { Sql } from 'postgres'
66import { afterAll , beforeAll , describe , expect , it , vi } from 'vitest'
77
@@ -68,14 +68,14 @@ describe('service receipts in SQL', () => {
6868 it ( 'claims each known receipt once while preserving incomplete measurement and delivery failures' , async ( ) => {
6969 const client = state . client !
7070 const base = {
71- streamId : randomUUID ( ) ,
71+ streamId : generateId ( ) ,
7272 toolCallId : 'tool' ,
7373 workerOrigin : 'http://127.0.0.1:8080' ,
7474 }
75- const intentId = randomUUID ( )
75+ const intentId = generateId ( )
7676 await beginServiceMeter ( { ...base , id : intentId } )
7777 const receipt = {
78- id : randomUUID ( ) ,
78+ id : generateId ( ) ,
7979 streamId : base . streamId ,
8080 toolCallId : base . toolCallId ,
8181 service : 'exa' ,
@@ -111,17 +111,17 @@ describe('service receipts in SQL', () => {
111111 it ( 'closes each abandoned tool meter once and leaves in-flight meters and receipts open' , async ( ) => {
112112 const client = state . client !
113113 const scope = {
114- streamId : randomUUID ( ) ,
114+ streamId : generateId ( ) ,
115115 toolCallId : 'abandoned-tool' ,
116116 workerOrigin : 'http://127.0.0.1:8080' ,
117117 }
118- const abandoned = randomUUID ( )
119- const failed = randomUUID ( )
120- const inFlight = randomUUID ( )
118+ const abandoned = generateId ( )
119+ const failed = generateId ( )
120+ const inFlight = generateId ( )
121121 for ( const id of [ abandoned , failed , inFlight ] ) await beginServiceMeter ( { ...scope , id } )
122122 await finishServiceUsage ( failed , 'provider pricing unavailable' )
123123 const receipt = {
124- id : randomUUID ( ) ,
124+ id : generateId ( ) ,
125125 streamId : scope . streamId ,
126126 toolCallId : scope . toolCallId ,
127127 service : 'exa' ,
@@ -144,6 +144,14 @@ describe('service receipts in SQL', () => {
144144 )
145145 expect ( closed . every ( ( meter ) => meter . streamId === scope . streamId ) ) . toBe ( true )
146146 expect ( await closeAbandonedServiceMeters ( ) ) . toEqual ( [ ] )
147+ // The watchdog only stops the chat waiting, so the owner can still finish after the close.
148+ await finishServiceUsage ( abandoned )
149+ await finishServiceUsage ( failed , 'late failure' )
150+ const lateRows =
151+ await client `SELECT id, last_error FROM copilot_service_usage WHERE id IN ${ client ( [ abandoned , failed ] ) } `
152+ expect ( new Map ( lateRows . map ( ( row ) => [ row . id , row . last_error ] ) ) ) . toEqual (
153+ new Map ( closed . map ( ( meter ) => [ meter . id , meter . lastError ] ) )
154+ )
147155
148156 const open =
149157 await client `SELECT id FROM copilot_service_usage WHERE stream_id = ${ scope . streamId } AND delivered_at IS NULL`
0 commit comments