@@ -5,11 +5,24 @@ import { createCompactingHandler } from "../handlers/compacting.ts";
55import { createMessagesHandler } from "../handlers/messages.ts" ;
66import { SessionManager } from "../session.ts" ;
77import { BatchDrainService } from "./batch-drain.ts" ;
8+ import { GraphitiAsyncService } from "./graphiti-async.ts" ;
89import { RedisCacheService } from "./redis-cache.ts" ;
910import { RedisClient } from "./redis-client.ts" ;
1011import { RedisEventsService } from "./redis-events.ts" ;
1112import { RedisSnapshotService } from "./redis-snapshot.ts" ;
1213
14+ const createGraphitiStub = ( ) => ( {
15+ getEpisodes ( ) {
16+ return Promise . resolve ( [ ] ) ;
17+ } ,
18+ searchMemoryFacts ( ) {
19+ return Promise . resolve ( [ ] ) ;
20+ } ,
21+ searchNodes ( ) {
22+ return Promise . resolve ( [ ] ) ;
23+ } ,
24+ } ) ;
25+
1326describe ( "hot-tier vertical slice" , ( ) => {
1427 it ( "records local state, prepares injection, transforms messages, and serves compaction context without live MCP" , async ( ) => {
1528 const redis = new RedisClient ( { endpoint : "redis://unused" } ) ;
@@ -24,9 +37,7 @@ describe("hot-tier vertical slice", () => {
2437 await redisCache . set ( "group-1" , {
2538 query : "Continue the overhaul" ,
2639 refreshedAt : Date . now ( ) ,
27- facts : [ { uuid : "fact-1" , fact : "Graphiti remains async" } ] ,
2840 nodes : [ { uuid : "node-1" , name : "ContextOverhaul" } ] ,
29- factUuids : [ "fact-1" ] ,
3041 nodeRefs : [ "node-1" ] ,
3142 } ) ;
3243
@@ -37,6 +48,8 @@ describe("hot-tier vertical slice", () => {
3748 redisEvents ,
3849 redisSnapshot ,
3950 redisCache ,
51+ createGraphitiStub ( ) as never ,
52+ { } as never ,
4053 ) ;
4154 manager . setParentId ( "session-1" , null ) ;
4255 manager . setState (
@@ -86,9 +99,9 @@ describe("hot-tier vertical slice", () => {
8699 transformOutput . messages [ 0 ] . parts [ 0 ] . text ,
87100 "<session_memory" ,
88101 ) ;
89- assertStringIncludes (
90- transformOutput . messages [ 0 ] . parts [ 0 ] . text ,
91- "<persistent_memory" ,
102+ assertEquals (
103+ transformOutput . messages [ 0 ] . parts [ 0 ] . text . includes ( "<persistent_memory" ) ,
104+ false ,
92105 ) ;
93106
94107 const events = await redisEvents . getRecentSessionEvents (
@@ -126,6 +139,8 @@ describe("hot-tier vertical slice", () => {
126139 redisEvents ,
127140 redisSnapshot ,
128141 redisCache ,
142+ createGraphitiStub ( ) as never ,
143+ { } as never ,
129144 ) ;
130145 manager . setParentId ( "session-1" , null ) ;
131146 manager . setState (
@@ -304,6 +319,53 @@ describe("hot-tier vertical slice", () => {
304319 } ) ;
305320 } ) ;
306321
322+ it ( "prefers remembered metadata query over stale cached query after drain success" , async ( ) => {
323+ const redis = new RedisClient ( { endpoint : "redis://unused" } ) ;
324+ const redisCache = new RedisCacheService ( redis , {
325+ ttlSeconds : 300 ,
326+ driftThreshold : 0.5 ,
327+ } ) ;
328+
329+ await redisCache . set ( "group-1" , {
330+ query : "older cached query" ,
331+ refreshedAt : Date . now ( ) - 60_000 ,
332+ nodes : [ ] ,
333+ nodeRefs : [ ] ,
334+ } ) ;
335+ await redisCache . rememberRefreshQuery ( "group-1" , "newer remembered query" ) ;
336+
337+ const refreshCalls : Array < { groupId : string ; query : string } > = [ ] ;
338+ const graphitiAsync = new GraphitiAsyncService (
339+ {
340+ getEpisodes ( ) {
341+ return Promise . resolve ( [ ] ) ;
342+ } ,
343+ searchMemoryFacts ( ) {
344+ return Promise . resolve ( [ ] ) ;
345+ } ,
346+ searchNodes ( input : { query : string ; groupIds : string [ ] } ) {
347+ refreshCalls . push ( { groupId : input . groupIds [ 0 ] , query : input . query } ) ;
348+ return Promise . resolve ( [ ] ) ;
349+ } ,
350+ } as never ,
351+ redisCache ,
352+ {
353+ drainGroup ( ) {
354+ return Promise . resolve ( { status : "success" as const } ) ;
355+ } ,
356+ } as never ,
357+ ) ;
358+
359+ graphitiAsync . scheduleDrain ( "group-1" ) ;
360+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
361+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
362+
363+ assertEquals ( refreshCalls , [ {
364+ groupId : "group-1" ,
365+ query : "newer remembered query" ,
366+ } ] ) ;
367+ } ) ;
368+
307369 it ( "classifies drift deterministically at the configured threshold boundary" , ( ) => {
308370 const redis = new RedisClient ( { endpoint : "redis://unused" } ) ;
309371 const redisCache = new RedisCacheService ( redis , {
@@ -314,17 +376,13 @@ describe("hot-tier vertical slice", () => {
314376 const aligned = redisCache . classifyRefresh ( {
315377 query : "alpha beta" ,
316378 refreshedAt : Date . now ( ) ,
317- facts : [ ] ,
318379 nodes : [ ] ,
319- factUuids : [ ] ,
320380 nodeRefs : [ ] ,
321381 } , "alpha beta gamma delta" ) ;
322382 const drifted = redisCache . classifyRefresh ( {
323383 query : "alpha beta" ,
324384 refreshedAt : Date . now ( ) ,
325- facts : [ ] ,
326385 nodes : [ ] ,
327- factUuids : [ ] ,
328386 nodeRefs : [ ] ,
329387 } , "alpha delta epsilon" ) ;
330388
@@ -352,6 +410,8 @@ describe("hot-tier vertical slice", () => {
352410 redisEvents ,
353411 redisSnapshot ,
354412 redisCache ,
413+ createGraphitiStub ( ) as never ,
414+ { } as never ,
355415 ) ;
356416 manager . setParentId ( "session-1" , null ) ;
357417 manager . setState (
@@ -362,9 +422,7 @@ describe("hot-tier vertical slice", () => {
362422 await redisCache . set ( "group-1" , {
363423 query : "primer" ,
364424 refreshedAt : Date . now ( ) ,
365- facts : [ ] ,
366425 nodes : [ ] ,
367- factUuids : [ ] ,
368426 nodeRefs : [ ] ,
369427 episodeSummaries : [ "Primer episode" ] ,
370428 } ) ;
@@ -378,9 +436,7 @@ describe("hot-tier vertical slice", () => {
378436 await redisCache . set ( "group-1" , {
379437 query : "older query" ,
380438 refreshedAt : Date . now ( ) - 301_000 ,
381- facts : [ { uuid : "fact-1" , fact : "Stale fact" } ] ,
382439 nodes : [ ] ,
383- factUuids : [ "fact-1" ] ,
384440 nodeRefs : [ ] ,
385441 } ) ;
386442 const stalePrepared = await manager . prepareInjection (
@@ -406,14 +462,11 @@ describe("hot-tier vertical slice", () => {
406462 await redisCache . set ( "group-1" , {
407463 query : "architecture token" ,
408464 refreshedAt : Date . now ( ) ,
409- facts : [ {
410- uuid : "fact-1" ,
411- fact :
412- "Exact token ALPHA-RECALL-42 identifies the architecture decision" ,
465+ nodes : [ {
466+ uuid : "node-1" ,
467+ name : "ALPHA-RECALL-42 architecture decision" ,
413468 } ] ,
414- nodes : [ ] ,
415- factUuids : [ "fact-1" ] ,
416- nodeRefs : [ ] ,
469+ nodeRefs : [ "node-1" ] ,
417470 } ) ;
418471
419472 const sameGroupManager = new SessionManager (
@@ -423,6 +476,8 @@ describe("hot-tier vertical slice", () => {
423476 redisEvents ,
424477 redisSnapshot ,
425478 redisCache ,
479+ createGraphitiStub ( ) as never ,
480+ { } as never ,
426481 ) ;
427482 sameGroupManager . setParentId ( "session-b" , null ) ;
428483 sameGroupManager . setState (
@@ -437,6 +492,8 @@ describe("hot-tier vertical slice", () => {
437492 redisEvents ,
438493 redisSnapshot ,
439494 redisCache ,
495+ createGraphitiStub ( ) as never ,
496+ { } as never ,
440497 ) ;
441498 otherGroupManager . setParentId ( "session-c" , null ) ;
442499 otherGroupManager . setState (
@@ -475,9 +532,7 @@ describe("hot-tier vertical slice", () => {
475532 await redisCache . set ( "group-1" , {
476533 query : "old recall topic" ,
477534 refreshedAt : Date . now ( ) - 301_000 ,
478- facts : [ { uuid : "fact-1" , fact : "Stale but still useful recall fact" } ] ,
479535 nodes : [ ] ,
480- factUuids : [ "fact-1" ] ,
481536 nodeRefs : [ ] ,
482537 } ) ;
483538
@@ -488,6 +543,8 @@ describe("hot-tier vertical slice", () => {
488543 redisEvents ,
489544 redisSnapshot ,
490545 redisCache ,
546+ createGraphitiStub ( ) as never ,
547+ { } as never ,
491548 ) ;
492549 manager . setParentId ( "session-1" , null ) ;
493550 manager . setState (
0 commit comments