@@ -447,6 +447,15 @@ function logMessages(runtime: ReturnType<typeof createRuntime>): string[] {
447447 return runtime . log . mock . calls . map ( ( c : unknown [ ] ) => String ( c [ 0 ] ) ) ;
448448}
449449
450+ // The `[delivery] delivery requested but not completed` warning is routed to
451+ // runtime.error (with runtime.log fallback when error is unavailable). Tests
452+ // that look for that warning should use this helper rather than logMessages.
453+ function diagnosticMessages ( runtime : ReturnType < typeof createRuntime > ) : string [ ] {
454+ return [ ...runtime . error . mock . calls , ...runtime . log . mock . calls ] . map ( ( c : unknown [ ] ) =>
455+ String ( c [ 0 ] ) ,
456+ ) ;
457+ }
458+
450459// ---------------------------------------------------------------------------
451460// Tests
452461// ---------------------------------------------------------------------------
@@ -477,6 +486,9 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
477486 attempted : true ,
478487 succeeded : true ,
479488 } ) ;
489+ // Backward-compat field consumed by agent-command.ts to clear
490+ // pendingFinalDelivery — must mirror deliveryStatus.succeeded.
491+ expect ( result . deliverySucceeded ) . toBe ( true ) ;
480492 // No warning log on success
481493 expect ( logMessages ( runtime ) . some ( ( msg ) => msg . includes ( "[delivery]" ) ) ) . toBe ( false ) ;
482494 } ) ;
@@ -510,8 +522,9 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
510522 attempted : false ,
511523 succeeded : false ,
512524 } ) ;
525+ expect ( result . deliverySucceeded ) . toBe ( false ) ;
513526 expect (
514- logMessages ( runtime ) . some ( ( msg ) =>
527+ diagnosticMessages ( runtime ) . some ( ( msg ) =>
515528 msg . includes ( "[delivery] delivery requested but not completed" ) ,
516529 ) ,
517530 ) . toBe ( true ) ;
@@ -533,9 +546,9 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
533546 attempted : true ,
534547 succeeded : false ,
535548 } ) ;
536- expect ( logMessages ( runtime ) . some ( ( msg ) => msg . includes ( "delivery returned zero results" ) ) ) . toBe (
537- true ,
538- ) ;
549+ expect (
550+ diagnosticMessages ( runtime ) . some ( ( msg ) => msg . includes ( "delivery returned zero results" ) ) ,
551+ ) . toBe ( true ) ;
539552 } ) ;
540553
541554 it ( "catches thrown error in bestEffort mode without re-throwing" , async ( ) => {
@@ -597,7 +610,7 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
597610 expect ( result . deliveryStatus ) . toBeUndefined ( ) ;
598611 } ) ;
599612
600- it ( "returns succeeded=true with hadPartialFailure when onError fires but results exist " , async ( ) => {
613+ it ( "returns succeeded=false with hadPartialFailure when onError fires under best-effort " , async ( ) => {
601614 deliverSpy . mockImplementation ( async ( opts ) => {
602615 // Simulate partial failure: onError fires for one payload, but results still returned
603616 opts . onError ?.( new Error ( "Payload 2 failed" ) , { text : "hello" } as never ) ;
@@ -609,16 +622,25 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
609622 deliver : true ,
610623 channel : "discord" ,
611624 to : "channel:123456" ,
625+ bestEffortDeliver : true ,
612626 } ) ;
613627
628+ // Partial failures count as not-succeeded so `agent-command.ts` keeps the
629+ // durable `pendingFinalDelivery` retry marker; matches upstream's pre-PR
630+ // `!deliveryHadError` semantics.
614631 expect ( result . deliveryStatus ) . toEqual ( {
615632 requested : true ,
616633 attempted : true ,
617- succeeded : true ,
634+ succeeded : false ,
618635 hadPartialFailure : true ,
619636 } ) ;
620- // No [delivery] warning — succeeded is true
621- expect ( logMessages ( runtime ) . some ( ( msg ) => msg . includes ( "[delivery]" ) ) ) . toBe ( false ) ;
637+ expect ( result . deliverySucceeded ) . toBe ( false ) ;
638+ // [delivery] warning fires because succeeded is false
639+ expect (
640+ diagnosticMessages ( runtime ) . some ( ( msg ) =>
641+ msg . includes ( "[delivery] delivery requested but not completed" ) ,
642+ ) ,
643+ ) . toBe ( true ) ;
622644 } ) ;
623645
624646 it ( "logs warning when channel resolves to internal" , async ( ) => {
@@ -642,8 +664,68 @@ describe("deliverAgentCommandResult — delivery status tracking", () => {
642664 succeeded : false ,
643665 error : true ,
644666 } ) ;
645- expect ( logMessages ( runtime ) . some ( ( msg ) => msg . includes ( "channel resolved to internal" ) ) ) . toBe (
667+ expect (
668+ diagnosticMessages ( runtime ) . some ( ( msg ) => msg . includes ( "channel resolved to internal" ) ) ,
669+ ) . toBe ( true ) ;
670+ } ) ;
671+
672+ it ( "reports preflight rejection (not zero results) when explicit target fails resolution" , async ( ) => {
673+ // Simulate best-effort preflight rejection: deliveryPlan still resolves a
674+ // target string, but resolveAgentOutboundTarget returns ok:false. The
675+ // delivery code marks hadPreflightError and skips the deliver call; the
676+ // diagnostic must report the preflight reason, not "zero results".
677+ outboundTargetSpy . mockReturnValue ( {
678+ resolvedTarget : {
679+ ok : false as const ,
680+ error : new Error ( "target rejected by plugin" ) ,
681+ } as ReturnType < typeof agentDeliveryModule . resolveAgentOutboundTarget > [ "resolvedTarget" ] ,
682+ resolvedTo : "channel:123456" ,
683+ targetMode : "explicit" as const ,
684+ } ) ;
685+
686+ const { result, runtime } = await runDelivery ( {
687+ message : "hello" ,
688+ deliver : true ,
689+ bestEffortDeliver : true ,
690+ channel : "discord" ,
691+ to : "channel:123456" ,
692+ } ) ;
693+
694+ expect ( deliverSpy ) . not . toHaveBeenCalled ( ) ;
695+ expect ( result . deliveryStatus ) . toEqual ( {
696+ requested : true ,
697+ attempted : false ,
698+ succeeded : false ,
699+ error : true ,
700+ } ) ;
701+ const diagnostics = diagnosticMessages ( runtime ) ;
702+ expect ( diagnostics . some ( ( msg ) => msg . includes ( "preflight rejected delivery target" ) ) ) . toBe (
646703 true ,
647704 ) ;
705+ expect ( diagnostics . some ( ( msg ) => msg . includes ( "delivery returned zero results" ) ) ) . toBe ( false ) ;
706+ } ) ;
707+
708+ it ( "emits the [delivery] warning on stderr (runtime.error), not stdout" , async ( ) => {
709+ // Diagnostics belong on stderr so scripts that pipe stdout for payload
710+ // text don't conflate it with delivery status. Tested by verifying
711+ // runtime.error received the message and runtime.log did not.
712+ deliverSpy . mockResolvedValue ( [ ] ) ;
713+
714+ const { runtime } = await runDelivery ( {
715+ message : "hello" ,
716+ deliver : true ,
717+ channel : "discord" ,
718+ to : "channel:123456" ,
719+ } ) ;
720+
721+ const errorMessages = runtime . error . mock . calls . map ( ( c : unknown [ ] ) => String ( c [ 0 ] ) ) ;
722+ expect (
723+ errorMessages . some ( ( msg ) => msg . includes ( "[delivery] delivery requested but not completed" ) ) ,
724+ ) . toBe ( true ) ;
725+ expect (
726+ logMessages ( runtime ) . some ( ( msg ) =>
727+ msg . includes ( "[delivery] delivery requested but not completed" ) ,
728+ ) ,
729+ ) . toBe ( false ) ;
648730 } ) ;
649731} ) ;
0 commit comments