Skip to content

Commit 54794d1

Browse files
committed
fix(api): listCaches reads __stats from prefix, not name
readBaseStats(client, key) constructs ${key}:__stats. listCaches was passing marker.name; for caches whose discovery-marker name happens to equal their prefix this is fine, but the protocol allows the two to differ (e.g. an alias-style registration). Stats would then read from the wrong key and report zeros even for an active cache. Adds a regression test where ALIAS != PREFIX and asserts stats are sourced from PREFIX.
1 parent c7c02c5 commit 54794d1

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

apps/api/src/cache-proposals/__tests__/cache-readonly.service.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,24 @@ describe('CacheReadonlyService', () => {
132132
expect(ac.status).toBe('stale');
133133
});
134134

135+
it('reads stats from prefix, not name, when they differ', async () => {
136+
const { service, client } = await buildService();
137+
const ALIAS = 'prod-llm';
138+
const PREFIX = 'betterdb_scache_prod';
139+
seedRegistry(client, {
140+
[ALIAS]: { type: 'semantic_cache', prefix: PREFIX },
141+
});
142+
client.hashes[`${PREFIX}:__stats`] = { hits: '90', misses: '10', total: '100' };
143+
client.hashes[`${ALIAS}:__stats`] = { hits: '0', misses: '0', total: '0' };
144+
145+
const result = await service.listCaches(CONNECTION_ID);
146+
expect(result).toHaveLength(1);
147+
expect(result[0].name).toBe(ALIAS);
148+
expect(result[0].prefix).toBe(PREFIX);
149+
expect(result[0].hit_rate).toBeCloseTo(0.9);
150+
expect(result[0].total_ops).toBe(100);
151+
});
152+
135153
it('returns empty when registry is empty', async () => {
136154
const { service } = await buildService();
137155
const result = await service.listCaches(CONNECTION_ID);

apps/api/src/cache-proposals/cache-readonly.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class CacheReadonlyService {
8383

8484
const entries: CacheListEntry[] = [];
8585
for (const marker of markers) {
86-
const stats = await this.readBaseStats(client, marker.name);
86+
const stats = await this.readBaseStats(client, marker.prefix);
8787
const heartbeat = await client.get(heartbeatKeyFor(marker.name));
8888
const status: CacheListEntry['status'] = heartbeat === null ? 'stale' : 'live';
8989
entries.push({

0 commit comments

Comments
 (0)