@@ -16,6 +16,7 @@ vi.mock("@cap/database/schema", () => ({
1616 videoId : "upload.videoId" ,
1717 phase : "upload.phase" ,
1818 updatedAt : "upload.updatedAt" ,
19+ startedAt : "upload.startedAt" ,
1920 } ,
2021 videoProcessingJobs : { videoId : "job.videoId" } ,
2122} ) ) ;
@@ -26,6 +27,7 @@ vi.mock("drizzle-orm", () => ({
2627 inArray : ( left : unknown , right : unknown ) => ( { in : [ left , right ] } ) ,
2728 isNull : ( value : unknown ) => ( { null : value } ) ,
2829 lte : ( left : unknown , right : unknown ) => ( { lte : [ left , right ] } ) ,
30+ gte : ( left : unknown , right : unknown ) => ( { gte : [ left , right ] } ) ,
2931 sql : ( strings : TemplateStringsArray , ...values : unknown [ ] ) => ( {
3032 strings : [ ...strings ] ,
3133 values,
@@ -159,6 +161,38 @@ describe("committed source recovery", () => {
159161} ) ;
160162
161163describe ( "durable recovery scheduling" , ( ) => {
164+ it ( "does not create a durable job for an unfinished legacy upload" , async ( ) => {
165+ const now = new Date ( "2026-09-09T20:00:00Z" ) ;
166+ const legacy = selectChain ( [ { videoId, ownerId : userId } ] ) ;
167+ mocks . db . mockReturnValueOnce ( legacy ) . mockReturnValue ( selectChain ( [ video ] ) ) ;
168+ mocks . get . mockReturnValue (
169+ Effect . succeed (
170+ Option . some ( JSON . stringify ( { ...manifest , is_complete : false } ) ) ,
171+ ) ,
172+ ) ;
173+ const result = await recoverStaleDesktopSegments ( { now } ) ;
174+ expect ( result . statuses ) . toEqual ( { "source-incomplete" : 1 } ) ;
175+ expect ( mocks . queue ) . not . toHaveBeenCalled ( ) ;
176+ expect ( mocks . put ) . not . toHaveBeenCalled ( ) ;
177+ expect ( JSON . stringify ( legacy . where . mock . calls ) ) . toContain (
178+ "2026-09-02T20:00:00.000Z" ,
179+ ) ;
180+ } ) ;
181+
182+ it ( "continues inspecting legacy uploads after a storage failure" , async ( ) => {
183+ const legacy = selectChain ( [
184+ { videoId, ownerId : userId } ,
185+ { videoId : "second" , ownerId : userId } ,
186+ ] ) ;
187+ mocks . db . mockReturnValueOnce ( legacy ) . mockReturnValue ( selectChain ( [ video ] ) ) ;
188+ mocks . get . mockReturnValueOnce (
189+ Effect . fail ( new Error ( "storage unavailable" ) ) ,
190+ ) ;
191+ const result = await recoverStaleDesktopSegments ( ) ;
192+ expect ( result . statuses ) . toEqual ( { failed : 1 , queued : 1 } ) ;
193+ expect ( mocks . queue ) . toHaveBeenCalledTimes ( 1 ) ;
194+ } ) ;
195+
162196 it ( "recovers old retry and expired processing jobs without a recording-age cutoff" , async ( ) => {
163197 mocks . db . mockReturnValue ( selectChain ( [ ] ) ) ;
164198 mocks . recoverable . mockResolvedValue ( [
@@ -192,14 +226,14 @@ describe("durable recovery scheduling", () => {
192226
193227 it ( "adopts stranded legacy processing rows without assuming their inventory is complete" , async ( ) => {
194228 const chain = selectChain ( [ { videoId, ownerId : userId } ] ) ;
195- mocks . db . mockReturnValue ( chain ) ;
229+ mocks . db . mockReturnValueOnce ( chain ) . mockReturnValue ( selectChain ( [ video ] ) ) ;
196230 mocks . queue . mockRejectedValue ( new SourceCommitPendingError ( ) ) ;
197231 const result = await recoverStaleDesktopSegments ( ) ;
198232 expect ( result . statuses ) . toEqual ( { "source-committing" : 1 } ) ;
199233 const query = JSON . stringify ( chain . where . mock . calls ) ;
200234 expect ( query ) . toContain ( '"processing"' ) ;
201235 expect ( query ) . not . toContain ( "28 HOUR" ) ;
202- expect ( query ) . not . toContain ( "startedAt" ) ;
236+ expect ( query ) . toContain ( "startedAt" ) ;
203237 expect ( mocks . put ) . not . toHaveBeenCalled ( ) ;
204238 } ) ;
205239
@@ -231,7 +265,7 @@ describe("durable recovery scheduling", () => {
231265 ownerId : userId ,
232266 } ) ) ,
233267 ) ;
234- mocks . db . mockReturnValue ( legacy ) ;
268+ mocks . db . mockReturnValueOnce ( legacy ) . mockReturnValue ( selectChain ( [ video ] ) ) ;
235269 const result = await recoverStaleDesktopSegments ( ) ;
236270 expect ( mocks . recoverable ) . toHaveBeenCalledWith (
237271 expect . objectContaining ( { limit : 15 } ) ,
0 commit comments