@@ -62,6 +62,38 @@ function fileReadTurns(
6262 ] ;
6363}
6464
65+ function shellTurns (
66+ id : string ,
67+ command : string ,
68+ result : string ,
69+ isError = false ,
70+ ) : ConversationTurn [ ] {
71+ return [
72+ makeTurn ( {
73+ role : "assistant" ,
74+ content : [
75+ {
76+ type : "tool_call" ,
77+ id,
78+ name : "run_shell" ,
79+ arguments : { command } ,
80+ } ,
81+ ] ,
82+ } ) ,
83+ makeTurn ( {
84+ role : "user" ,
85+ content : [
86+ {
87+ type : "tool_result" ,
88+ callId : id ,
89+ isError,
90+ content : [ { type : "text" , text : result } ] ,
91+ } ,
92+ ] ,
93+ } ) ,
94+ ] ;
95+ }
96+
6597function userTurn ( text : string ) : ConversationTurn {
6698 return makeTurn ( { role : "user" , content : [ { type : "text" , text } ] } ) ;
6799}
@@ -550,6 +582,83 @@ describe("iterative folding", () => {
550582 ) ;
551583 } ) ;
552584
585+ test ( "iterative union keeps prefix-sharing constraints distinct" , ( ) => {
586+ const first = buildHandoffFold (
587+ [
588+ userTurn (
589+ "Ship the widget.\nMust never write to /tmp\nNever touch src/auth" ,
590+ ) ,
591+ ] ,
592+ "narrative" ,
593+ ) ;
594+ const second = buildHandoffFold (
595+ [
596+ spineTurn ( first . spineText ) ,
597+ userTurn (
598+ "Continue.\nMust never write to /tmp/cache\nNever touch src/auth.ts" ,
599+ ) ,
600+ ] ,
601+ "narrative" ,
602+ { priorFileText : new TextDecoder ( ) . decode ( first . blob . bytes ) } ,
603+ ) ;
604+ expect ( second . artifact . constraints ) . toEqual (
605+ expect . arrayContaining ( [
606+ "Must never write to /tmp" ,
607+ "Must never write to /tmp/cache" ,
608+ "Never touch src/auth" ,
609+ "Never touch src/auth.ts" ,
610+ ] ) ,
611+ ) ;
612+ } ) ;
613+
614+ test ( "iterative union keeps prefix-sharing decisions distinct" , ( ) => {
615+ const first = buildHandoffFold (
616+ [
617+ userTurn ( "Ship the widget." ) ,
618+ userTurn ( "Use src/auth" ) ,
619+ userTurn ( "Keep going." ) ,
620+ ] ,
621+ "narrative" ,
622+ ) ;
623+ const second = buildHandoffFold (
624+ [
625+ spineTurn ( first . spineText ) ,
626+ userTurn ( "Use src/auth.ts" ) ,
627+ userTurn ( "Keep going." ) ,
628+ ] ,
629+ "narrative" ,
630+ { priorFileText : new TextDecoder ( ) . decode ( first . blob . bytes ) } ,
631+ ) ;
632+ expect ( second . artifact . decisions ) . toEqual (
633+ expect . arrayContaining ( [ "Use src/auth" , "Use src/auth.ts" ] ) ,
634+ ) ;
635+ } ) ;
636+
637+ test ( "iterative union keeps prefix-sharing verification distinct" , ( ) => {
638+ const first = buildHandoffFold (
639+ [
640+ userTurn ( "Run the suite." ) ,
641+ ...shellTurns ( "c1" , "bun test" , "1 pass, 0 fail" ) ,
642+ ] ,
643+ "narrative" ,
644+ ) ;
645+ const second = buildHandoffFold (
646+ [
647+ spineTurn ( first . spineText ) ,
648+ userTurn ( "Run the module tests." ) ,
649+ ...shellTurns ( "c2" , "bun test src/foo.test.ts" , "1 pass, 0 fail" ) ,
650+ ] ,
651+ "narrative" ,
652+ { priorFileText : new TextDecoder ( ) . decode ( first . blob . bytes ) } ,
653+ ) ;
654+ expect ( second . artifact . verification ) . toEqual (
655+ expect . arrayContaining ( [
656+ "PASS: bun test" ,
657+ "PASS: bun test src/foo.test.ts" ,
658+ ] ) ,
659+ ) ;
660+ } ) ;
661+
553662 test ( "narrative ## Goal/Files in the prior summary do not overwrite schema" , ( ) => {
554663 const first = buildHandoffFold ( foldedRegion ( ) , "First fold narrative." ) ;
555664 const poisoned = renderHandoffFile (
@@ -590,6 +699,38 @@ describe("iterative folding", () => {
590699 "Never touch src/legacy." ,
591700 ) ;
592701 } ) ;
702+
703+ test ( "partial prior-file constraints do not drop extra carried spine constraints" , ( ) => {
704+ const first = buildHandoffFold (
705+ [
706+ userTurn (
707+ "Ship the widget.\nMust never write to /tmp\nNever touch src/auth" ,
708+ ) ,
709+ ] ,
710+ "narrative" ,
711+ ) ;
712+ const kept = first . artifact . constraints . filter ( ( constraint ) =>
713+ constraint . includes ( "/tmp" ) ,
714+ ) ;
715+ expect ( kept . length ) . toBeGreaterThan ( 0 ) ;
716+ expect ( first . artifact . constraints . length ) . toBeGreaterThan ( kept . length ) ;
717+ const partial = renderHandoffFile (
718+ { ...first . artifact , constraints : kept } ,
719+ "narrative" ,
720+ handoffBlobUri ( HANDOFF_LATEST_KEY ) ,
721+ ) ;
722+ const second = buildHandoffFold (
723+ [ spineTurn ( first . spineText ) , userTurn ( "Continue." ) ] ,
724+ "narrative" ,
725+ { priorFileText : partial } ,
726+ ) ;
727+ expect ( second . artifact . constraints ) . toEqual (
728+ expect . arrayContaining ( [
729+ "Must never write to /tmp" ,
730+ "Never touch src/auth" ,
731+ ] ) ,
732+ ) ;
733+ } ) ;
593734} ) ;
594735
595736describe ( "tool-body dumps" , ( ) => {
0 commit comments