@@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test";
22import {
33 buildChatSystemPrompt ,
44 buildClaudeTaskGuidanceNote ,
5+ buildGptNarrateBeforeToolsNote ,
56 buildGrokLeafAntiThrashNote ,
67 buildGuidelines ,
78 buildPromptDisciplineBlock ,
@@ -372,6 +373,7 @@ describe("grok finish-bias residual gating (extends existing provider-family tes
372373 } ) ;
373374} ) ;
374375
376+ < < < << << HEAD
375377describe ( "promptResidual assembly (CL-8297)" , ( ) => {
376378 const TOOL_BUDGET =
377379 "Tool budget:\n" +
@@ -452,3 +454,79 @@ describe("claude XML task_guidance residual (provider residual, not a prompt for
452454 ) ;
453455 } ) ;
454456} ) ;
457+
458+ describe ( "gpt narrate-before-tools residual (CL-8310)" , ( ) => {
459+ it ( "is a 3-line narrate-before-tools note, not manage_tasks ceremony" , ( ) => {
460+ const note = buildGptNarrateBeforeToolsNote ( ) ;
461+ expect ( note ) . toContain ( "Narrate before tools (GPT worker):" ) ;
462+ expect ( note ) . toMatch ( / b e f o r e .* t o o l c a l l .* o n e s h o r t l i n e / is) ;
463+ expect ( note ) . toMatch ( / n o n a r r a t i o n b e t w e e n t h e m / i) ;
464+ expect ( note ) . toContain ( "write the report envelope" ) ;
465+ expect ( note . toLowerCase ( ) ) . not . toContain ( "manage_tasks" ) ;
466+ } ) ;
467+
468+ it ( "appears exactly once on a gpt leaf prompt" , ( ) => {
469+ const prompt = buildSubAgentSystemPrompt ( undefined , undefined , undefined , {
470+ orchestrator : false ,
471+ gptNarrateBeforeTools : true ,
472+ } ) ;
473+ const note = buildGptNarrateBeforeToolsNote ( ) ;
474+ expect ( countOccurrences ( prompt , note ) ) . toBe ( 1 ) ;
475+ expect ( prompt . trimEnd ( ) . endsWith ( note ) ) . toBe ( true ) ;
476+ } ) ;
477+
478+ it ( "appears exactly once on a gpt primary prompt" , ( ) => {
479+ const prompt = buildChatSystemPrompt (
480+ undefined ,
481+ undefined ,
482+ undefined ,
483+ [ ] ,
484+ "orchestrator" ,
485+ undefined ,
486+ undefined ,
487+ { gptNarrateBeforeTools : true } ,
488+ ) ;
489+ const note = buildGptNarrateBeforeToolsNote ( ) ;
490+ expect ( countOccurrences ( prompt , note ) ) . toBe ( 1 ) ;
491+ } ) ;
492+
493+ it ( "is absent by default on both primary and leaf" , ( ) => {
494+ const leaf = buildSubAgentSystemPrompt ( undefined , undefined , undefined , {
495+ orchestrator : false ,
496+ grokAntiThrash : false ,
497+ } ) ;
498+ const primary = buildChatSystemPrompt (
499+ undefined ,
500+ undefined ,
501+ undefined ,
502+ [ ] ,
503+ "orchestrator" ,
504+ ) ;
505+ expect ( leaf ) . not . toContain ( "Narrate before tools (GPT worker):" ) ;
506+ expect ( primary ) . not . toContain ( "Narrate before tools (GPT worker):" ) ;
507+ } ) ;
508+
509+ it ( "is absent on grok and claude prompts" , ( ) => {
510+ const grokLeaf = buildSubAgentSystemPrompt ( undefined , undefined , undefined , {
511+ orchestrator : false ,
512+ grokAntiThrash : true ,
513+ } ) ;
514+ const claudeLeaf = buildSubAgentSystemPrompt ( undefined , undefined , undefined , {
515+ orchestrator : false ,
516+ grokAntiThrash : false ,
517+ } ) ;
518+ const claudePrimary = buildChatSystemPrompt (
519+ undefined ,
520+ undefined ,
521+ undefined ,
522+ [ ] ,
523+ "orchestrator" ,
524+ ) ;
525+ for ( const prompt of [ grokLeaf , claudeLeaf , claudePrimary ] ) {
526+ expect ( prompt ) . not . toContain ( "Narrate before tools (GPT worker):" ) ;
527+ expect ( prompt ) . not . toContain ( "Narrate before tools (GPT" ) ;
528+ }
529+ // The grok row keeps its own residual, untouched.
530+ expect ( grokLeaf ) . toContain ( "Finish bias (xAI / Grok worker):" ) ;
531+ } ) ;
532+ } ) ;
0 commit comments