@@ -466,4 +466,65 @@ describe("routine execution self-close (DLD-3231)", () => {
466466 expect ( res . status ) . toBe ( 422 ) ;
467467 expect ( res . body . gate ) . toBe ( "comment_required" ) ;
468468 } ) ;
469+
470+ describe ( "deliverableType gateBlockCount reset (DLD-3465)" , ( ) => {
471+ it ( "PATCH deliverableType null→value resets gateBlockCount to 0" , async ( ) => {
472+ // Regression: setting deliverableType on a code issue used to NOT reset gateBlockCount,
473+ // causing it to keep incrementing and agents to be skipped on wakeups.
474+ const issue = makeIssue ( { status : "in_progress" , deliverableType : null , gateBlockCount : 1 , executionWorkspaceId : "ws-1" } ) ;
475+ mockIssueService . getById . mockResolvedValue ( issue ) ;
476+ mockIssueService . update . mockImplementation ( async ( id : string , fields : Record < string , unknown > ) => ( {
477+ ...issue ,
478+ ...fields ,
479+ gateBlockCount : fields . gateBlockCount as number ,
480+ } ) ) ;
481+
482+ const res = await request ( createAgentApp ( ) )
483+ . patch ( `/api/issues/${ issue . id } ` )
484+ . send ( { deliverableType : "report" } ) ;
485+
486+ expect ( res . status ) . toBe ( 200 ) ;
487+ expect ( mockIssueService . update ) . toHaveBeenCalledWith (
488+ issue . id ,
489+ expect . objectContaining ( { gateBlockCount : 0 , deliverableType : "report" } ) ,
490+ ) ;
491+ expect ( res . body . gateBlockCount ) . toBe ( 0 ) ;
492+ } ) ;
493+
494+ it ( "PATCH deliverableType value→null resets gateBlockCount to 0" , async ( ) => {
495+ // Same logic: when deliverableType reverts, gateBlockCount resets.
496+ const issue = makeIssue ( { status : "in_progress" , deliverableType : "report" , gateBlockCount : 3 , executionWorkspaceId : "ws-1" } ) ;
497+ mockIssueService . getById . mockResolvedValue ( issue ) ;
498+ mockIssueService . update . mockImplementation ( async ( id : string , fields : Record < string , unknown > ) => ( {
499+ ...issue ,
500+ ...fields ,
501+ gateBlockCount : fields . gateBlockCount as number ,
502+ } ) ) ;
503+
504+ const res = await request ( createAgentApp ( ) )
505+ . patch ( `/api/issues/${ issue . id } ` )
506+ . send ( { deliverableType : null } ) ;
507+
508+ expect ( res . status ) . toBe ( 200 ) ;
509+ expect ( mockIssueService . update ) . toHaveBeenCalledWith (
510+ issue . id ,
511+ expect . objectContaining ( { gateBlockCount : 0 , deliverableType : null } ) ,
512+ ) ;
513+ expect ( res . body . gateBlockCount ) . toBe ( 0 ) ;
514+ } ) ;
515+
516+ it ( "PATCH deliverableType with no change is a no-op (no update called)" , async ( ) => {
517+ // When deliverableType stays the same, the request is a no-op and update is not called.
518+ const issue = makeIssue ( { status : "in_progress" , deliverableType : "report" , gateBlockCount : 2 , executionWorkspaceId : "ws-1" } ) ;
519+ mockIssueService . getById . mockResolvedValue ( issue ) ;
520+
521+ const res = await request ( createAgentApp ( ) )
522+ . patch ( `/api/issues/${ issue . id } ` )
523+ . send ( { deliverableType : "report" } ) ;
524+
525+ expect ( res . status ) . toBe ( 200 ) ;
526+ // No update should be called for no-op changes
527+ expect ( mockIssueService . update ) . not . toHaveBeenCalled ( ) ;
528+ } ) ;
529+ } ) ;
469530} ) ;
0 commit comments