authorgravatar for lucenz@proton.meSimone <lucenz@proton.me> 2026-09-01 00:59:39+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-31 18:59:39-04:00
log6d15c5bbc3f3c331a7466bb94c17413a35f7b659
treeecbd537a5103ee3cc17b4d4b8f3d4bf6c5caf6f0
parentf47e74004af232f0e3df8dc10093601d1c2c3ea3
signature Signed by PGP key B5690EEEBB952194

fix(server): preserve usage cache outside walked roots (#8540)

Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com>

2 files changed, 26 insertions(+), 1 deletions(-)

apps/server/src/usage/usageScanCache.test.ts+14
......@@ -193,6 +193,20 @@ describe("pruneScanCache with an unwalked root", () => {
193193 expect(removed).toBe(0);
194194 expect(cache.size).toBe(1);
195195 });
196
197 it("keeps entries under a sibling path that only shares the walked root prefix", () => {
198 const cache = cacheWith([["/claude/projects-copy/a.jsonl", 5000, [record()]]]);
199
200 const removed = pruneScanCache(cache, {
201 livePaths: new Set(),
202 walkedRoots: ["/claude/projects"],
203 windowStartMs: 4000,
204 retentionCutoffMs: 1000,
205 });
206
207 expect(removed).toBe(0);
208 expect(cache.size).toBe(1);
209 });
196210});
197211
198212describe("dedupeWithinFile", () => {
apps/server/src/usage/usageScanCache.ts+12-1
......@@ -14,6 +14,9 @@
1414 *
1515 * @module usageScanCache
1616 */
17// @effect-diagnostics nodeBuiltinImport:off
18import * as NodePath from "node:path";
19
1720import type { UsageProviderKind } from "@t3tools/contracts";
1821
1922import type { UsageRecord } from "./usageTranscripts.ts";
......@@ -229,7 +232,15 @@ export function pruneScanCache(cache: ScanCache, options: PruneOptions): number
229232 let removed = 0;
230233 for (const [path, entry] of cache) {
231234 const agedOut = entry.mtimeMs < options.retentionCutoffMs;
232 const underWalkedRoot = options.walkedRoots.some((root) => path.startsWith(root));
235 const underWalkedRoot = options.walkedRoots.some((root) => {
236 const relative = NodePath.relative(root, path);
237 return (
238 relative === "" ||
239 (relative !== ".." &&
240 !relative.startsWith(`..${NodePath.sep}`) &&
241 !NodePath.isAbsolute(relative))
242 );
243 });
233244 const deleted =
234245 underWalkedRoot && entry.mtimeMs >= options.windowStartMs && !options.livePaths.has(path);
235246 if (agedOut || deleted) {