@@ -30,6 +30,7 @@ def fake_get(limit=1000, offset=0, include=None):
3030 build_graph ,
3131 find_tunnels ,
3232 graph_stats ,
33+ invalidate_graph_cache ,
3334 traverse ,
3435 )
3536
@@ -38,6 +39,9 @@ def fake_get(limit=1000, offset=0, include=None):
3839
3940
4041class TestBuildGraph :
42+ def setup_method (self ):
43+ invalidate_graph_cache ()
44+
4145 def test_empty_collection (self ):
4246 col = _make_fake_collection ([])
4347 nodes , edges = build_graph (col = col )
@@ -114,11 +118,43 @@ def test_dates_capped_at_five(self):
114118 nodes , _ = build_graph (col = col )
115119 assert len (nodes ["busy" ]["dates" ]) <= 5
116120
121+ def test_cache_returns_same_result (self ):
122+ """Second call within TTL returns cached nodes without re-scanning.
123+
124+ The cache intentionally ignores col/config args when warm — this is
125+ correct for the MCP server's single-palace use case. Callers that
126+ switch collections must call invalidate_graph_cache() first.
127+ """
128+ col = _make_fake_collection (
129+ [{"room" : "auth" , "wing" : "wing_code" , "hall" : "security" , "date" : "2026-01-01" }]
130+ )
131+ nodes1 , edges1 = build_graph (col = col )
132+ # Second call with a *different* collection — should still return cached result
133+ col2 = _make_fake_collection ([])
134+ nodes2 , edges2 = build_graph (col = col2 )
135+ assert nodes1 == nodes2
136+ assert edges1 == edges2
137+
138+ def test_invalidate_clears_cache (self ):
139+ """invalidate_graph_cache() forces a fresh scan on next call."""
140+ col = _make_fake_collection (
141+ [{"room" : "auth" , "wing" : "wing_code" , "hall" : "security" , "date" : "2026-01-01" }]
142+ )
143+ build_graph (col = col )
144+ invalidate_graph_cache ()
145+ col_empty = _make_fake_collection ([])
146+ nodes , edges = build_graph (col = col_empty )
147+ assert nodes == {}
148+ assert edges == []
149+
117150
118151# --- traverse ---
119152
120153
121154class TestTraverse :
155+ def setup_method (self ):
156+ invalidate_graph_cache ()
157+
122158 def _build_col (self ):
123159 return _make_fake_collection (
124160 [
@@ -156,6 +192,9 @@ def test_traverse_max_hops(self):
156192
157193
158194class TestFindTunnels :
195+ def setup_method (self ):
196+ invalidate_graph_cache ()
197+
159198 def _build_tunnel_col (self ):
160199 return _make_fake_collection (
161200 [
@@ -192,6 +231,9 @@ def test_find_tunnels_both_wings(self):
192231
193232
194233class TestGraphStats :
234+ def setup_method (self ):
235+ invalidate_graph_cache ()
236+
195237 def test_empty_graph (self ):
196238 col = _make_fake_collection ([])
197239 stats = graph_stats (col = col )
0 commit comments