Gateway Module — `analytics/`
1. Purpose
The analytics/ module is a read-only reporting layer over the gateway's existing tables. It surfaces four aggregate views — agent performance, context quality, skill usage, and dispatch patterns — computed on demand from agent_dispatch, psychic_cache, context_assembly_log, activity_log, and source_weights. It is the FIP (Fast Improvement Pipeline) Phase 1 read surface (Dispatch 377), with Phase 3 channel-awareness (Dispatch 384) letting every view filter by dispatch origin channel (vscode / hermes / all). It owns no writes and no schema — it is a pure query/aggregation module.
2. File Inventory
| File | Lines | Responsibility |
|---|---|---|
index.ts | 21 | Layer factory createAnalyticsLayer(db) → { router } (vault-index layer pattern) |
repository.ts | 493 | All SQL aggregation queries against the 5 source tables |
routes.ts | 144 | 4 GET endpoints with Zod query-param validation |
types.ts | 148 | WindowQuerySchema + ChannelSchema Zod, 4 response-shape interfaces, repository contract |
| Total | 806 |
3. Public API Surface
REST Endpoints
Mounted at /api/analytics (index.ts line 750). Auth: all four are GET → require a Bearer (post-AK-415; the former GET exemption is closed).
| Method | Path | Auth | Query params | Response |
|---|---|---|---|---|
| GET | /api/analytics/agent-performance | Bearer | window (Nd, 1–90, default 7d), channel (default all) | AgentPerformanceResponse — per-agent dispatch counts, confidence/affinity splits, avg duration, retry + escalation counts |
| GET | /api/analytics/context-quality | Bearer | window (default 7d), channel | ContextQualityResponse — per-caller assembly totals, feedback rate, avg utilisation, per-source effectiveness (assembled vs used, current weight/token-share) |
| GET | /api/analytics/skill-usage | Bearer | window (default 30d), channel | SkillUsageResponse — per-skill invocation counts, distinct agents, first/last used. never_used deferred (empty in Phase 1) |
| GET | /api/analytics/dispatch-patterns | Bearer | window (default 30d), channel | DispatchPatternsResponse — per-agent stall rate + stall-milestone breakdown; escalation targets + reasons |
Invalid query params return 400 with formatZodError output.
MCP Tools
None.
4. Internal API
createAnalyticsLayer(db): AnalyticsLayer— composes repository + router; exports{ router }only.createAnalyticsRepository(db): AnalyticsRepository— 7 query methods:getAgentPerformance,getEscalationCounts,getContextCallerSummary,getContextSourceEffectiveness,getSkillUsage,getStallPatterns,getEscalationPatterns(each takessqlOffset+channel).
5. Background Services
None. All computation is request-driven.
6. Data Contracts
Two Zod query-param schemas (the only validation surface — no body schemas):
WindowQuerySchema— string^\d+d$, refined to 1–90 days, transformed to{ days, sqlOffset: '-N days' }. Default7d. A standalone string schema (raiden advisory: not extended by channel).ChannelSchema—z.enum(['vscode','hermes','all']).default('all'). Parsed independently as a sibling schema. Channel attribution is tag-based:hermes= dispatches carrying asource:hermespsychic-cache tag;vscode= dispatches without it;all= no filter.
Response shapes are TypeScript interfaces (not Zod — outbound): AgentPerformanceResponse, ContextQualityResponse, SkillUsageResponse, DispatchPatternsResponse plus their nested entry types.
7. Dependencies
- Gateway modules consumed:
shared/(formatZodError). Reads (does not write) tables owned by dispatch (agent_dispatch), psychic-cache (psychic_cache), context (context_assembly_log,source_weights), activity (activity_log). - External libraries:
better-sqlite3,express,zod. - Environment variables: none.
8. Test Coverage
| Layer | File | Cases |
|---|---|---|
| Routes + repository | test/analytics-routes.test.ts (475 L) | 28 it blocks |
Covers all 4 endpoints, window validation bounds, channel filtering, and escalation-enrichment merge.
9. Known Limitations
skill-usage.never_usedis a deferred feature — Phase 1 returns an empty array; catalogue cross-reference (skills the registry knows but telemetry has never seen) is not yet implemented.- Channel attribution is a heuristic (presence/absence of a
source:hermestag), not a first-class column — a dispatch that never wrote a tagged cache entry defaults tovscode. - Read-only module: no aggregation is materialised/cached, so each request re-scans the window. Acceptable at current volume; a candidate for a materialised rollup if window scans grow costly.
10. Change History
| Date | Dispatch | Summary |
|---|---|---|
| 2026-07-04 | 2297 | Initial module spec (smoke-clone-3, LisaOS audit campaign Phase 4) |
| — | 384 | Phase 3 channel awareness (vscode/hermes/all) |
| — | 377 | FIP Phase 1 — module created (4 read endpoints) |