{"version":3,"file":"compaction.test.d.ts","sourceRoot":"","sources":["../../../src/cache/__tests__/compaction.test.ts"],"names":[],"mappings":"","sourcesContent":["// T-044..T-054\nimport { describe, expect, it } from \"vitest\";\nimport { KeepaliveScheduler, summarize, type Turn, trimMiddle } from \"../compaction.js\";\nimport { type CacheUsageReport, resolveRetention, totalInputTokens } from \"../policy.js\";\n\ndescribe(\"cache usage report (T-044, T-046)\", () => {\n\tit(\"exposes three token fields\", () => {\n\t\tconst u: CacheUsageReport = {\n\t\t\tcachedInputTokens: 100,\n\t\t\tcacheWriteTokens: 10,\n\t\t\tuncachedInputTokens: 50,\n\t\t};\n\t\texpect(u.cachedInputTokens).toBeDefined();\n\t\texpect(u.cacheWriteTokens).toBeDefined();\n\t\texpect(u.uncachedInputTokens).toBeDefined();\n\t});\n\n\tit(\"cached + uncached equals total input\", () => {\n\t\tconst u: CacheUsageReport = {\n\t\t\tcachedInputTokens: 300,\n\t\t\tcacheWriteTokens: 25,\n\t\t\tuncachedInputTokens: 200,\n\t\t};\n\t\texpect(totalInputTokens(u)).toBe(500);\n\t});\n});\n\ndescribe(\"resolveRetention (T-047, T-048, T-049)\", () => {\n\tit(\"defaults to role default when no override\", () => {\n\t\texpect(resolveRetention({ roleDefault: \"long\" })).toBe(\"long\");\n\t});\n\n\tit(\"CLI flag overrides role default\", () => {\n\t\texpect(resolveRetention({ roleDefault: \"long\", cliFlag: \"none\" })).toBe(\"none\");\n\t});\n});\n\ndescribe(\"trimMiddle (T-050, T-051, T-052)\", () => {\n\tfunction mkTurns(n: number): Turn[] {\n\t\treturn Array.from({ length: n }, (_, i) => ({\n\t\t\tindex: i,\n\t\t\tbytes: `turn-${i}`,\n\t\t}));\n\t}\n\n\tit(\"drops 1..24, preserves 25..30 with N=5 recent floor (30-turn history)\", () => {\n\t\tconst turns = mkTurns(30);\n\t\tconst result = trimMiddle(turns, { recentFloor: 5 });\n\t\texpect(result.kept.length).toBe(6); // summary + 5 recent\n\t\t// Last 5 kept\n\t\tconst recent = result.kept.slice(1);\n\t\texpect(recent.map((t) => t.index)).toEqual([25, 26, 27, 28, 29]);\n\t\t// Dropped 25 turns\n\t\texpect(result.droppedCount).toBe(25);\n\t});\n\n\tit(\"produces deterministic stable summary block\", () => {\n\t\tconst turns = mkTurns(20);\n\t\tconst a = trimMiddle(turns, { recentFloor: 5 }).summary;\n\t\tconst b = trimMiddle(turns, { recentFloor: 5 }).summary;\n\t\texpect(a.bytes).toBe(b.bytes);\n\t\texpect(a.bytes).toContain(\"compact\");\n\t});\n\n\tit(\"no-op when turns ≤ recentFloor + 1\", () => {\n\t\tconst turns = mkTurns(3);\n\t\tconst result = trimMiddle(turns, { recentFloor: 5 });\n\t\texpect(result.droppedCount).toBe(0);\n\t\texpect(result.kept).toEqual(turns);\n\t});\n\n\tit(\"summarize includes dropped indices for auditability\", () => {\n\t\tconst s = summarize([\n\t\t\t{ index: 1, bytes: \"a\" },\n\t\t\t{ index: 2, bytes: \"bb\" },\n\t\t]);\n\t\texpect(s).toContain(\"[1,2]\");\n\t\texpect(s).toContain(\"3 bytes\");\n\t});\n});\n\ndescribe(\"KeepaliveScheduler (T-053, T-054)\", () => {\n\tit(\"returns skip when retention=none\", () => {\n\t\tconst k = new KeepaliveScheduler();\n\t\tk.markActivity(0);\n\t\texpect(k.tick(10_000, { intervalMs: 5_000, retention: \"none\", enabled: true })).toBe(\"skip\");\n\t});\n\n\tit(\"returns skip when disabled\", () => {\n\t\tconst k = new KeepaliveScheduler();\n\t\tk.markActivity(0);\n\t\texpect(k.tick(10_000, { intervalMs: 5_000, retention: \"long\", enabled: false })).toBe(\"skip\");\n\t});\n\n\tit(\"returns ping after interval elapsed with retention=long\", () => {\n\t\tconst k = new KeepaliveScheduler();\n\t\tk.markActivity(0);\n\t\texpect(k.tick(5_000, { intervalMs: 5_000, retention: \"long\", enabled: true })).toBe(\"ping\");\n\t});\n\n\tit(\"shuts off after idle 2x interval\", () => {\n\t\tconst k = new KeepaliveScheduler();\n\t\tk.markActivity(0);\n\t\texpect(k.tick(11_000, { intervalMs: 5_000, retention: \"long\", enabled: true })).toBe(\"shutoff\");\n\t});\n\n\tit(\"default off: enabled=false skips even when interval passed\", () => {\n\t\tconst k = new KeepaliveScheduler();\n\t\tk.markActivity(0);\n\t\tconst r = k.tick(10_000, { intervalMs: 5_000, retention: \"long\", enabled: false });\n\t\texpect(r).toBe(\"skip\");\n\t});\n});\n"]}