Problem
src/services/briefing-cache.ts — three related issues with cache invalidation:
1. `activityHash` is dead code
```ts
set(briefing: BriefingOutput, activityHash: string): void {
this.entry = { briefing, generatedAt: Date.now(), activityHash, invalidated: false };
}
get(): BriefingOutput | null {
if (!this.entry) return null;
if (this.entry.invalidated) return null;
if (Date.now() - this.entry.generatedAt > this.ttlMs) return null;
return { ...this.entry.briefing, cached: true };
}
```
The hash is stored in `set()` and never read by `get()`. The caller (`core-source.ts`) computes `createHash("md5").update(JSON.stringify(activity.totals))` and passes it in — dead weight.
2. Cache key doesn't capture facet content
Even if `activityHash` were wired into `get()`, the hash is built from `activity.totals` (conversation count, tool call count, error count). Adding entities to bundle apps (CRM rows, tasks, research notes) doesn't change any of those totals. So the cache stays valid for the full TTL even when the underlying app data has been transformed.
3. No auto-invalidation on data-change events
The SSE-event invalidation that `HomeService` was supposed to provide on `data.changed` / `bundle.*` was deleted in PR #219 because `HomeService` had zero runtime consumers (the class existed and was tested but was never wired into the runtime). Today the cache is purely TTL-based, defaults to 5 min, with no escape hatch except a force-refresh.
Symptom
Add entities to your apps, reload the home dashboard — briefing still shows the pre-update state for up to 5 minutes. Operators can't tell whether they're looking at fresh or stale content.
Suggested fixes (one or more)
- Wire `activityHash` into `get()` so the cache invalidates when activity totals change. Cheap; doesn't fix facet-content changes but catches new-conversation / new-tool-call cases.
- Hash the facet payload too — include facet counts or a content checksum in the cache key.
- Subscribe the cache to `data.changed` events at runtime. The `SseEventManager.onEvent` API already exists; just needs an owner that wires the briefing cache into it. (This was `HomeService`'s job before it was deleted; deciding to revive that orchestrator vs. wiring directly is part of this design.)
Context
Surfaced during local testing of PR #219. See PR #219 (commit `d938d29` deleted the unused HomeService) and the discussion thread for more context.
Problem
src/services/briefing-cache.ts— three related issues with cache invalidation:1. `activityHash` is dead code
```ts
set(briefing: BriefingOutput, activityHash: string): void {
this.entry = { briefing, generatedAt: Date.now(), activityHash, invalidated: false };
}
get(): BriefingOutput | null {
if (!this.entry) return null;
if (this.entry.invalidated) return null;
if (Date.now() - this.entry.generatedAt > this.ttlMs) return null;
return { ...this.entry.briefing, cached: true };
}
```
The hash is stored in `set()` and never read by `get()`. The caller (`core-source.ts`) computes `createHash("md5").update(JSON.stringify(activity.totals))` and passes it in — dead weight.
2. Cache key doesn't capture facet content
Even if `activityHash` were wired into `get()`, the hash is built from `activity.totals` (conversation count, tool call count, error count). Adding entities to bundle apps (CRM rows, tasks, research notes) doesn't change any of those totals. So the cache stays valid for the full TTL even when the underlying app data has been transformed.
3. No auto-invalidation on data-change events
The SSE-event invalidation that `HomeService` was supposed to provide on `data.changed` / `bundle.*` was deleted in PR #219 because `HomeService` had zero runtime consumers (the class existed and was tested but was never wired into the runtime). Today the cache is purely TTL-based, defaults to 5 min, with no escape hatch except a force-refresh.
Symptom
Add entities to your apps, reload the home dashboard — briefing still shows the pre-update state for up to 5 minutes. Operators can't tell whether they're looking at fresh or stale content.
Suggested fixes (one or more)
Context
Surfaced during local testing of PR #219. See PR #219 (commit `d938d29` deleted the unused HomeService) and the discussion thread for more context.