@@ -325,6 +325,7 @@ export class SubAgentDirector extends DefaultDirector {
325325
326326 if ( stop === "complete" ) {
327327 this . reportReplied = true ;
328+ this . flushToolFailureRecoveryAudit ( ) ;
328329 const terminal : ReactorAction [ ] = [
329330 capabilities . checkpoint ( "subagent-complete" ) ,
330331 capabilities . reply ( lastText ( content ) ) ,
@@ -384,6 +385,7 @@ export class SubAgentDirector extends DefaultDirector {
384385 } ) ;
385386 this . onForcedStop ( "incomplete-report" ) ;
386387 this . reportReplied = true ;
388+ this . flushToolFailureRecoveryAudit ( ) ;
387389 const terminal : ReactorAction [ ] = [
388390 capabilities . checkpoint ( "subagent-incomplete-report" ) ,
389391 capabilities . reply (
@@ -480,6 +482,7 @@ export class SubAgentDirector extends DefaultDirector {
480482 } ) ;
481483 this . onForcedStop ( "stalled" ) ;
482484 this . reportReplied = true ;
485+ this . flushToolFailureRecoveryAudit ( ) ;
483486 const terminal : ReactorAction [ ] = [
484487 capabilities . checkpoint ( "subagent-stalled" ) ,
485488 capabilities . reply (
@@ -492,6 +495,25 @@ export class SubAgentDirector extends DefaultDirector {
492495 return terminal ;
493496 }
494497
498+ /**
499+ * Write the coalesced tool-failure-recovery audit once the burst ends —
500+ * when the armed nudge lands on an infer, or when the run goes terminal
501+ * (complete / forced stop / stalled) with the nudge still undelivered.
502+ * Without the terminal-path flush a burst that is never followed by an
503+ * infer would vanish from the audit trail entirely.
504+ */
505+ private flushToolFailureRecoveryAudit ( ) : void {
506+ if ( this . pendingToolFailureRecoveryCount === 0 ) return ;
507+ const count = this . pendingToolFailureRecoveryCount ;
508+ this . pendingToolFailureRecoveryCount = 0 ;
509+ this . interventions ( {
510+ id : "tool-failure-recovery" ,
511+ class : "nudge" ,
512+ ...( count > 1 ? { count } : { } ) ,
513+ state : this . interventionState ( ) ,
514+ } ) ;
515+ }
516+
495517 /**
496518 * Rewrite the infer action in a fall-through actions batch to carry the
497519 * armed nudge, once — this matches the infer after report-forced or
@@ -507,15 +529,7 @@ export class SubAgentDirector extends DefaultDirector {
507529 const text = this . pendingNudgeText ;
508530 this . pendingNudgeText = null ;
509531 this . lastConsumedNudgeText = text ;
510- if ( this . pendingToolFailureRecoveryCount > 0 ) {
511- this . interventions ( {
512- id : "tool-failure-recovery" ,
513- class : "nudge" ,
514- count : this . pendingToolFailureRecoveryCount ,
515- state : this . interventionState ( ) ,
516- } ) ;
517- this . pendingToolFailureRecoveryCount = 0 ;
518- }
532+ this . flushToolFailureRecoveryAudit ( ) ;
519533 const existing = actions [ inferIndex ] as Extract <
520534 ReactorAction ,
521535 { type : "infer" }
0 commit comments