@@ -511,4 +511,156 @@ describe("versioned key-files injection", () => {
511511 closeQuietly ( db ) ;
512512 }
513513 } ) ;
514+
515+ it ( "does not reuse cache across different projects at the same version" , ( ) => {
516+ setAftAvailabilityOverride ( true ) ;
517+ const db = makeDb ( ) ;
518+ const sessionId = "shared-session" ;
519+ const sessionMeta = {
520+ sessionId,
521+ isSubagent : false ,
522+ } as import ( "../types" ) . SessionMeta ;
523+ try {
524+ const projectA = tempDir ( "kf-proj-a-" ) ;
525+ const projectB = tempDir ( "kf-proj-b-" ) ;
526+ writeFileSync ( join ( projectA , "a.ts" ) , "a" ) ;
527+ writeFileSync ( join ( projectB , "b.ts" ) , "b" ) ;
528+ replaceProjectKeyFiles ( db , projectA , [
529+ {
530+ path : "a.ts" ,
531+ content : "project-a-block" ,
532+ localTokenEstimate : 10 ,
533+ generationConfigHash : "cfg" ,
534+ } ,
535+ ] ) ;
536+ replaceProjectKeyFiles ( db , projectB , [
537+ {
538+ path : "b.ts" ,
539+ content : "project-b-block" ,
540+ localTokenEstimate : 10 ,
541+ generationConfigHash : "cfg" ,
542+ } ,
543+ ] ) ;
544+ expect ( getKeyFilesVersion ( db , projectA ) ) . toBe ( 1 ) ;
545+ expect ( getKeyFilesVersion ( db , projectB ) ) . toBe ( 1 ) ;
546+
547+ const fromA = readVersionedKeyFiles ( {
548+ db,
549+ sessionId,
550+ sessionMeta,
551+ directory : projectA ,
552+ isCacheBusting : false ,
553+ config : { enabled : true , tokenBudget : 2000 } ,
554+ } ) ;
555+ const fromB = readVersionedKeyFiles ( {
556+ db,
557+ sessionId,
558+ sessionMeta,
559+ directory : projectB ,
560+ isCacheBusting : false ,
561+ config : { enabled : true , tokenBudget : 2000 } ,
562+ } ) ;
563+ expect ( fromA ) . toContain ( "project-a-block" ) ;
564+ expect ( fromB ) . toContain ( "project-b-block" ) ;
565+ expect ( fromB ) . not . toContain ( "project-a-block" ) ;
566+ } finally {
567+ clearKeyFilesCacheForSession ( sessionId ) ;
568+ closeQuietly ( db ) ;
569+ }
570+ } ) ;
571+
572+ it ( "invalidates cache when tokenBudget changes without a version bump" , ( ) => {
573+ setAftAvailabilityOverride ( true ) ;
574+ const db = makeDb ( ) ;
575+ const sessionId = "budget-session" ;
576+ const sessionMeta = {
577+ sessionId,
578+ isSubagent : false ,
579+ } as import ( "../types" ) . SessionMeta ;
580+ try {
581+ const project = tempDir ( "kf-budget-" ) ;
582+ writeFileSync ( join ( project , "big.ts" ) , "x" ) ;
583+ writeFileSync ( join ( project , "small.ts" ) , "y" ) ;
584+ replaceProjectKeyFiles ( db , project , [
585+ {
586+ path : "big.ts" ,
587+ content : "BIG-FILE-CONTENT" ,
588+ localTokenEstimate : 100 ,
589+ generationConfigHash : "cfg" ,
590+ } ,
591+ {
592+ path : "small.ts" ,
593+ content : "SMALL" ,
594+ localTokenEstimate : 5 ,
595+ generationConfigHash : "cfg" ,
596+ } ,
597+ ] ) ;
598+
599+ const tightBudget = readVersionedKeyFiles ( {
600+ db,
601+ sessionId,
602+ sessionMeta,
603+ directory : project ,
604+ isCacheBusting : false ,
605+ config : { enabled : true , tokenBudget : 10 } ,
606+ } ) ;
607+ const looseBudget = readVersionedKeyFiles ( {
608+ db,
609+ sessionId,
610+ sessionMeta,
611+ directory : project ,
612+ isCacheBusting : false ,
613+ config : { enabled : true , tokenBudget : 2000 } ,
614+ } ) ;
615+ expect ( tightBudget ) . not . toContain ( "BIG-FILE-CONTENT" ) ;
616+ expect ( looseBudget ) . toContain ( "BIG-FILE-CONTENT" ) ;
617+ expect ( looseBudget ) . not . toBe ( tightBudget ) ;
618+ } finally {
619+ clearKeyFilesCacheForSession ( sessionId ) ;
620+ closeQuietly ( db ) ;
621+ }
622+ } ) ;
623+
624+ it ( "cache hit when session, project, budget, and version are unchanged" , ( ) => {
625+ setAftAvailabilityOverride ( true ) ;
626+ const db = makeDb ( ) ;
627+ const sessionId = "hit-session" ;
628+ const sessionMeta = {
629+ sessionId,
630+ isSubagent : false ,
631+ } as import ( "../types" ) . SessionMeta ;
632+ const config = { enabled : true , tokenBudget : 2000 } ;
633+ try {
634+ const project = tempDir ( "kf-hit-" ) ;
635+ writeFileSync ( join ( project , "a.ts" ) , "a" ) ;
636+ replaceProjectKeyFiles ( db , project , [
637+ {
638+ path : "a.ts" ,
639+ content : "stable-hit" ,
640+ localTokenEstimate : 10 ,
641+ generationConfigHash : "cfg" ,
642+ } ,
643+ ] ) ;
644+ const first = readVersionedKeyFiles ( {
645+ db,
646+ sessionId,
647+ sessionMeta,
648+ directory : project ,
649+ isCacheBusting : false ,
650+ config,
651+ } ) ;
652+ const second = readVersionedKeyFiles ( {
653+ db,
654+ sessionId,
655+ sessionMeta,
656+ directory : project ,
657+ isCacheBusting : false ,
658+ config,
659+ } ) ;
660+ expect ( second ) . toBe ( first ) ;
661+ } finally {
662+ clearKeyFilesCacheForSession ( sessionId ) ;
663+ closeQuietly ( db ) ;
664+ }
665+ } ) ;
514666} ) ;
0 commit comments