- Per-memory retrieval trajectory — closes the *trajectory* axis on the per-memory observability clusterCloses the named rev-156 next-sprint candidate ('memory retrieval frequency sparkline'). Rev 153 surfaced the *cumulative* retrieval state (lastRetrievedAt + retrievalCount); rev 157 surfaces the *shape over time*. New `memoryEntries.retrievalHistory` JSONB column (`Record<YYYY-MM-DD, number>` keyed by ISO date in workspace timezone — same shape as the rev-54 task.dailyCostHistory primitive). Pulse engine's `workNextTask()` now bumps today's per-memory bucket via SQL `jsonb_set` alongside the existing rev-153 lastRetrievedAt + retrievalCount writes — single UPDATE covers the entire batch of retrieved memories on each cycle (all rows share the same todayKey), so the rev-157 trajectory primitive ships with zero extra round-trip cost on the retrieval path. New `getMemoryRetrievalTrajectory()` helper in `src/lib/workspaces.ts` returns the trailing N daily counts (default 7, max 30) oldest → newest with zero-fill. New bearer-auth `GET /api/v1/memory/{id}/retrieval-trajectory?days=7` endpoint mirrors the rev-54 `/tasks/{id}/cost-trajectory` shape at the per-memory axis exactly. Pairs with the rev-153 GET /api/v1/memory + GET /api/v1/memory/stale + rev-156 per-tag filter for the full per-memory observability story on the protocol-bound surface — eleven axes deep (read rev 12 + write rev 12 + bulk-update rev 35 + reactions rev 33 + tags rev 21 + export rev 125 + stale rev 153 + auto-archive rev 154 + archive-warning rev 155 + per-tag-stale rev 156 + retrieval-trajectory rev 157).
- Inline 7-bar retrieval sparkline beside the rev-153 retrieval-count chip on every memory rowNew `MemoryRetrievalSparkline` client component renders a 48×14px 7-bar mini-chart inline beside the rev-153 `MemoryUsageChip` on every memory row whose `retrievalHistory` JSONB has at least one non-zero day. Today is rightmost with a brand-purple highlight; older days fade so the eye reads the trajectory shape, not individual values. Brand-purple palette (`rgba(107, 78, 214, *)`) distinguishes the retrieval sparkline from the rev-54 brand-amber cost sparkline so the dashboard's two trajectory primitives (cost on per-task axis, retrieval on per-memory axis) read at two distinct attention levels. The dashboard server component reuses the existing `trajectoryDayKeys` array (computed once for the rev-54 task cost trajectory) so the per-row work on every memory row is a single Map lookup — pure derived state from the rev-157 column with no extra query. Hidden when every value is zero so fresh + never-pulled memory rows don't see clutter. Pinned + importance>=9 entries skip the sparkline since they're load-bearing by design (matching the rev-153 chip exclusion rules). Closes the *trajectory* axis on the per-memory observability cluster the same way rev-54 closed it on the per-task cost surface — operators triaging a load-bearing memory entry now see both the *cumulative* count (rev 153) and the *shape over time* (rev 157) without leaving the memory list.
- Per-tag breakdown line on the rev-155 memory archive warning Slack push — closes the named rev-156 next-sprint candidate at the chat-channel axisCloses the named rev-156 next-sprint candidate ('per-tag memory archive warning Slack push scoping'). Rev 156 shipped the per-tag breakdown line on the digest email section + the dashboard StaleMemoryPanel filter; the rev-155 daily Slack push had no equivalent — Slack-first operators saw the workspace-wide warning list but couldn't tell at a glance which workstream's knowledge was about to disappear. Rev 157 closes that. The `buildMemoryArchiveWarningSlackPayload()` helper now accepts optional per-warning `tags: string[]` and surfaces an inline 'by tag: `#q3-launch` (3) `#brand-voice` (2) `#pricing` (1)' breakdown below the per-entry rows when 2+ distinct tags appear in the warning set. Top 4 tags by warning count, ties broken alphabetically for deterministic ordering. Mirrors the rev-156 digest section breakdown logic exactly so dashboard ↔ email ↔ Slack speak one consistent per-tag vocabulary across all three operator-loaded channels. The `pingMemoryArchiveWarnings()` cron sweep now plumbs per-entry tags through to the Slack payload — zero-cost projection because `sweepMemoryArchiveWarnings` already projects tags off the rev-21 `memoryEntries.tags` column. Hidden when fewer than 2 distinct tags appear so the breakdown never reads tautologically as 'everything is #foo'.
- OpenAPI 3.1 typed coverage on the rev-157 retrieval-trajectory endpoint — 79th unbroken cadence revThe OpenAPI 3.1 spec types the new `GET /memory/{memoryId}/retrieval-trajectory` endpoint with full request/response schemas (memoryId path param + days query param 1-30 default 7 + response shape with `memoryId` + `days` + `trajectory[]` array of `{ date: ISO YYYY-MM-DD in workspace TZ, retrievals: integer }` rows). The cadence pattern from rev 78 onward (every dashboard primitive gets typed in the OpenAPI 3.1 spec in the same cycle it ships) reaches its 79th unbroken rev with rev 157. The `/api/v1` self-describing endpoint index documents the new endpoint inline + extends the rev-153 `/memory/stale` description to mention the rev-156 `?tag=` parameter. MCP-host code generators reading the spec see typed contracts for the rev-157 trajectory primitive immediately. The per-memory observability cluster on v1 is now eleven axes deep (read rev 12 + write rev 12 + bulk-update rev 35 + reactions rev 33 + tags rev 21 + export rev 125 + stale rev 153 + auto-archive rev 154 + archive-warning rev 155 + per-tag-stale rev 156 + retrieval-trajectory rev 157). The MCP server's per-memory observability tooling has nothing left to design across the eleven axes.