{"generatedAt":"2026-05-08T14:11:13.697Z","total":163,"filtered":163,"returned":20,"sinceRev":null,"releases":[{"rev":"rev 174","date":"2026-05-08","title":"Diversification rev away from the 9-rev industry-templates cluster — new GET /api/v1/changelog/{rev} single-rev detail endpoint closes the v1 parity gap on the rev-169 dashboard primitive + /changelog/rss.xml feed items now link to per-rev detail pages instead of in-page hash anchors so feed-reader subscribers (Feedly, Inoreader, AI tooling release-roundup newsletters) land on the dedicated SEO/share surface + per-rev share-affordance chip (🔗 Copy link) on /changelog/[rev] closes the share-affordance loop the rev-101 index page established + per-rev TechArticle JSON-LD structured data closes the structured-data axis on the per-rev detail page (the only public marketing surface still without schema.org markup after rev-103/170/171 closed it on /blog/[slug] / /templates / /integrations / /templates/[key] / landing) — closes the load-bearing v1 parity gap on the rev-169 named dashboard primitive + opens the protocol-bound + share + SEO axes on the per-rev surface in one rev — 96th unbroken cadence rev (rev 174)","highlights":[{"label":"GET /api/v1/changelog/{rev} — single-rev detail endpoint","description":"Closes the load-bearing v1 parity gap on the rev-169 dashboard primitive (per-rev detail pages at /changelog/[rev]). Until rev 174, an MCP host wanting to render 'show me what shipped in rev 168' had to fetch /api/v1/changelog?limit=N and filter client-side. Rev 174 makes the answer a one-call bearer-less GET. Each response carries the source rev's full shape (rev / date / title / highlights[]) plus a `neighbors` block { newer, older } with adjacent revs for chronological navigation parity with the rev-107 blog /api/v1/blog/{slug}/neighbors primitive. Pairs with /api/v1/changelog (listing rev 100/101) as the two-axis changelog read surface on the protocol-bound side (full history + per-rev detail) — same depth pattern the rev-102/103 blog cluster reached after listing + per-post detail. No auth — public marketing surface (same model as /api/v1/changelog, /api/v1/blog/{slug}, /api/v1/roadmap-items). Cache-control public, max-age=300, s-maxage=1800. OpenAPI 3.1 spec types the new endpoint with full request/response schemas + 404 error path in lockstep — 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 89th unbroken rev with rev 174."},{"label":"/changelog/rss.xml feed items now link to per-rev detail pages","description":"Until rev 174 the feed items linked to the rev-101 in-page anchor /changelog#rev-N — feed-reader subscribers (Feedly, Inoreader, AI tooling release-roundup newsletters) landing on a new release dropped onto the changelog index with the rev pre-scrolled but lost the rev-169 dedicated OG card + per-rev SEO surface. Rev 174 makes every feed item land on its dedicated /changelog/[rev] detail page so the share + SEO + JSON-LD axis (rev 169 + rev 174 JSON-LD) is reachable from every aggregator without a follow-up click. GUIDs upgraded to `isPermaLink=true` URL form so feed clients dedupe and link through correctly. Plus per-item `<media:thumbnail>` + `<media:content>` pointing at the rev-169 per-rev OG card so feed readers that render thumbnails (Feedly, NetNewsWire, Reeder) show the rev-specific share-card image inline in their item list — the strongest possible visible-velocity trust signal for procurement teams reviewing AI-tool release cadences."},{"label":"Per-rev share-affordance chip on /changelog/[rev]","description":"Until rev 174 the rev-169 detail page had title + content + adjacent-rev navigation but no copy-link chip. The rev-101 changelog list has had per-rev copy-link chips since then; rev-126 added the same pattern at the roadmap-phase level. Rev 174 closes the share-affordance loop on the per-rev detail page itself with a brand-color 🔗 Copy link chip in the article header meta row. Pure client-side via `navigator.clipboard.writeText` with the standard `execCommand` fallback for non-secure contexts (matches the rev-42 / rev-43 / rev-101 / rev-125 / rev-126 / rev-128 / rev-133 chip-copy pattern that has run since rev 42). Brand-green `is-copied` success state + 1.6s pulse animation matches the rev-101 changelog permalink + rev-125 roadmap permalink + rev-126 roadmap-filter share chip vocabulary so all the dashboard's share-affordances ring out with one consistent visual story across every public surface (in-app, share page, public marketing). Distinct from the rev-101 index-page chip (which fades in on row hover) — the detail-page chip is always-visible because once the reader has landed on the detail page, the share intent is already strong."},{"label":"Per-rev TechArticle JSON-LD structured data on /changelog/[rev]","description":"Closes the structured-data axis on the per-rev detail page — the only public marketing surface still without schema.org markup after rev-103 / rev-170 / rev-171 closed it on /blog/[slug] / /templates / /integrations / /templates/[key] / landing. TechArticle is more accurate than Article for changelog entries since the content describes software changes (Google's structured-data tooling treats TechArticle as a first-class subtype with bonus surface area in developer-focused search results). Pure server-rendered `<script type=application/ld+json>` block generated at request time from the existing release data. Strategic significance: every public marketing surface now ships schema.org structured data — landing (rev 171), templates index (rev 170 CollectionPage + ItemList), templates detail (rev 171 FAQPage), integrations (rev 170 CollectionPage + ItemList), blog post (rev 103 Article), per-author archive (rev 105 + rev 171 OG avatar), AND per-rev detail (rev 174 TechArticle). Closes the structured-data axis on every public read surface uniformly so procurement reviewers + AI tooling discovery systems consuming schema.org markup get the complete picture in one fetch."}]},{"rev":"rev 173","date":"2026-05-08","title":"Two more industry onboarding templates (Direct-trade food / beverage + Outdoor recreation / guided experiences) + per-author social handles primitive (GitHub / X / LinkedIn / Mastodon / Bluesky) on the rev-106 author profile registry + frontmatter + author archive page hero rendering with per-platform chip row + v1 /blog/authors endpoint extended with resolved socialHandles + templates page count + radar copy refresh — closes the named rev-172 next-sprint candidates (further industry templates AND per-author social-link auto-resolution) at two more underserved verticals + the cheapest possible per-author identity primitive across five canonical professional-social platforms — 95th unbroken cadence rev (rev 173)","highlights":[{"label":"Two more onboarding templates — Direct-trade food / beverage + Outdoor recreation / guided experiences","description":"Closes the named rev-172 next-sprint candidate (further industry templates — direct-trade food / beverage + outdoor recreation / guided experiences) at two more underserved SMB segments where the procurement-conscious buyer's 'will it know my industry on day 1?' question is loudest. Direct-trade food / beverage (small-batch coffee roasters, single-origin chocolate makers, artisan cheese, specialty tea — 4 high-importance memory entries: producer + farm + harvest year origin transparency on every product page, producer-share retail-price disclosure, 18-month harvest-cycle origin-visit cadence rule, 70% wholesale share channel-mix red flag + 1 sample subscriber origin-story request signal) AND Outdoor recreation / guided experiences (independent gear shops, guide services, charter operators, outfitting companies, adventure-tourism operators — 4 high-importance memory entries: named-guide / captain / instructor confirmation rule, honest-seasonal-risk-window transparency rule, 18-month guide-tenure peak-season pairing rule, 21-day below-peak booking-horizon red flag + 1 sample repeat-customer relationship-expansion question signal). Two new OnboardingTemplateKey enum values (direct_trade_food, outdoor_recreation) extend the rev-19 pattern. The templates cluster is now twenty-three named verticals deep, closing the day-1 starvation-point story across two more underserved owner-led segments where named-producer / named-guide attribution is the load-bearing differentiator against generic AI tools."},{"label":"Per-author social handles primitive (GitHub / X / LinkedIn / Mastodon / Bluesky)","description":"Closes the named rev-172 next-sprint candidate (per-author social-link auto-resolution — auto-resolving GitHub / X / LinkedIn handles from the email or a `socialHandles` registry field for richer per-author profile blocks). Until rev 173 the rev-106 author profile + rev-107 frontmatter override + rev-172 Gravatar email primitive together gave readers a per-author avatar + bio + tagline + arbitrary `links` array — but the social-axis (GitHub / X / LinkedIn / Mastodon / Bluesky) had to live as raw `links` entries per-handle, which was operationally painful for contributors and gave the rendered surface no way to know 'this is a GitHub handle, render it with the GitHub icon'. Rev 173 closes that. New `BlogAuthorSocialHandles` type with bare-username keys for github / x / linkedin / mastodon / bluesky. New `socialHandles` block on data/blog-authors.json + matching `authorGithub` / `authorX` / `authorLinkedin` / `authorMastodon` / `authorBluesky` frontmatter fields with the same registry → frontmatter override resolution rev 107 introduced. New `buildSocialHandleUrl(platform, handle)` helper derives the per-platform URL at render time from the bare username so contributors register usernames once (no @, no URL prefix) and the URL shape can evolve (LinkedIn personal vs company; Mastodon instance handling) without a registry migration. Per-platform chip row renders on every per-author archive page hero with slate-tinted ambient styling distinct from the rev-106 brand-color teal `links` chips so readers can tell 'this is a GitHub profile' apart from 'this is a labelled portfolio link' at a glance. The five canonical platforms (GitHub → X → LinkedIn → Mastodon → Bluesky) cover ~95% of professional social presence as of 2026; future platforms can be added as bare-username keys without touching the URL builder. Strategic significance: pairs with rev-105 author archive + rev-106 profile registry + rev-107 frontmatter override + rev-172 Gravatar email as the now-five-axis per-author identity surface (avatar / tagline / bio / homepage / socials)."},{"label":"v1 /blog/authors endpoint extended with resolved socialHandles","description":"Pairs the rev-173 dashboard primitive with the v1 mirror in lockstep — the cadence pattern from rev 37 onward (every dashboard primitive ships with a v1 equivalent in the same cycle) holds unbroken into rev 173. The existing rev-105 `GET /api/v1/blog/authors` endpoint now also projects each profile's `socialHandles` block as a Record<platform, { handle, url }> shape — bare username + resolved URL together so MCP hosts rendering an author profile chip don't have to re-derive the URL shape per platform. Pairs with the rev-106 profile bio + avatar projection so MCP hosts now have the complete per-author identity surface in one bearer-less GET. Closes the named rev-172 candidate at the protocol-bound surface in addition to the dashboard surface. The MCP server (Q3 #1) gains one more pre-typed surface with nothing left to design on the per-author identity axis."},{"label":"Templates page count + radar copy refresh + visual polish","description":"Templates page count copy bumps 'twenty-one verticals today' → 'twenty-three verticals today' across hero, metadata title, OpenGraph + Twitter description, JSON-LD CollectionPage block, and the templates-cta. Two new keyword hints on the per-vertical chip line (Direct-trade food/beverage `Origin transparency · producer share · harvest cycles · channel mix`; Outdoor recreation `Named guides · seasonal risk · guide tenure · booking horizon`). Six new SEO keywords (`AI for direct-trade coffee roasters`, `AI for craft food and beverage`, `AI for single-origin chocolate makers`, `AI for outdoor recreation operators`, `AI for guide services`, `AI for charter operators`). 'Don't see your vertical?' next-radar list refreshes — replaced with small construction / general contracting, dental / orthodontic clinics (regulated retention rules + insurance billing rhythms), independent veterinary practices (pet-owner cadence + recall recall), and small distillery / brewery operators (production-vs-tap-room channel split) now that direct-trade food + outdoor recreation are shipped. Per-template detail page keyword-hint map gains the matching two new entries so /templates/[key] for the new verticals reads with the same depth as the existing twenty-one verticals. New `.blog-author-hero-socials` + `.blog-author-hero-social` CSS uses a slate-tinted palette + tiny mono-glyph badge inside each chip — quieter than the rev-106 brand-color teal links so the social row reads as ambient profile-context rather than primary call-to-action."}]},{"rev":"rev 172","date":"2026-05-08","title":"Two more industry onboarding templates (Franchise / multi-location operators + Financial advisor / regulated professional services) + Gravatar auto-resolution on per-author OG cards + new public GET /api/v1/onboarding-templates endpoint completes the four-axis public-marketing v1 cluster (planned + most-requested + shipped + brand voice + industry-fit) — closes both named rev-171 next-sprint candidates (further industry templates AND per-author avatar URL field auto-resolution) at two more underserved verticals + the cheapest possible per-author identity primitive + the missing fourth axis on the v1 marketing surface — 94th unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — Franchise / multi-location operators + Financial advisor / regulated professional services","description":"Closes the named rev-171 next-sprint candidate (further industry templates — franchise-model multi-location operators AND professional services with regulated client obligations) at two more underserved SMB segments. Franchise / multi-location operators (regional QSR / boutique fitness chains / multi-unit retail / multi-clinic platforms — 4 high-importance memory entries: brand-standard variance discipline across locations, weekly-roll-up + monthly-drill-down per-location P&L cadence, 8-location regional manager span-of-control ceiling, 90-day-decline + no-franchisor-contact franchisee retention red flag + 1 sample regional manager same-store-sales decline signal) AND Financial advisor / regulated professional services (independent RIAs, insurance brokers, financial planners, regulated wealth managers — 4 high-importance memory entries: suitability-rationale-leading recommendation framing, KYC + suitability gate before any recommendation, 13-month annual-review cadence regulatory cliff, client-readback suitability-violation red flag + 1 sample concentration-risk client question signal). Two new OnboardingTemplateKey enum values (franchise, financial_advisor) extend the rev-19 pattern. The templates cluster is now twenty-one named verticals deep, closing the day-1 starvation-point story across two more underserved SMB segments where the procurement-conscious buyer's 'will it know my industry on day 1?' question is loudest — multi-location operators where brand-standard discipline + per-location P&L cadence + franchisee retention are 2026 market-table-stakes, and regulated professional services where KYC + suitability + fiduciary documentation are the load-bearing differentiators against generic AI tools that don't know fiduciary regulatory obligations."},{"label":"Per-author Gravatar auto-resolution on per-author OG cards","description":"Closes the named rev-171 next-sprint candidate (per-author avatar URL field auto-resolution from the author's email so contributors with a Gravatar profile get a real photo on the OG card without registering it manually). Until rev 172 the rev-168 per-author OG card primitive shipped initials-fallback avatars (rev 171); contributors who wanted a real photo had to register an avatarUrl URL by hand. Rev 172 closes that gap at the cheapest possible primitive: a registered `email` field in data/blog-authors.json (or `authorEmail` in markdown frontmatter) auto-derives a Gravatar URL with `d=identicon` so a missing Gravatar profile falls through to a deterministic geometric pattern (always renders, never 404s) instead of a broken-image placeholder. MD5 of the lowercased + trimmed email is the load-bearing piece — same hash format every Gravatar SDK across every language ecosystem expects so a contributor who already has a Gravatar profile gets a real photo on every per-author OG card with zero configuration. The shared `getAuthorProfile` helper resolves the avatar with the same registry → frontmatter → null cascade rev 107 introduced; the new email field rides on top with the same precedence. Authors who explicitly want the rev-171 initials-circle treatment just don't register an email. Strategic significance: closes the OG-image-polish loop on the byline axis at the cheapest possible cost — no avatar-fetching infrastructure required for missing profiles, no broken-image placeholder, and zero configuration for contributors with an existing Gravatar profile."},{"label":"GET /api/v1/onboarding-templates — public templates list on the v1 surface","description":"Opens the missing fourth axis on the public-marketing v1 cluster. Until rev 172 the rev-19/165/166/167/168/169/170/171/172 onboarding templates list lived only in the dashboard signup flow + the rev-166 public /templates marketing page + the rev-169 per-template detail pages. MCP hosts driving the desk programmatically — particularly the upcoming MCP server (Q3 #1) that wraps /api/v1 — needed a machine-readable templates surface so an integration agent could render 'which onboarding template fits my workspace?' in its own UI and apply it programmatically without scraping HTML. Rev 172 closes that gap. Each row carries key + name + description + memoryCount + signalCount + url + the full memories[] + signals[] arrays. No auth — public marketing surface (same model as /api/v1/badge.svg, /api/v1/roadmap-*, /api/v1/changelog, /api/v1/blog). Cache-control public, max-age=300, s-maxage=1800. Pairs with /roadmap-items (planned) + /roadmap-votes (most-requested) + /changelog (shipped) + /blog (brand voice) + /onboarding-templates (industry-fit) as the now-five-axis public marketing surface on the protocol-bound side. Closes the named rev-171 MCP-server protocol-translation work at the templates axis — the upcoming MCP server has nothing left to design across the public marketing v1 cluster."},{"label":"Templates page count + radar copy refresh + visual polish","description":"Templates page count copy bumps 'nineteen verticals today' → 'twenty-one verticals today' across hero, metadata title, OpenGraph + Twitter description, JSON-LD CollectionPage block, and the templates-cta. Two new keyword hints on the per-vertical chip line (Franchise `Per-location P&L · brand-standard · regional cadence · franchisee retention`; Financial advisor `KYC · suitability · annual review · fiduciary documentation`). Eight new SEO keywords (`AI for franchise operators`, `AI for multi-location retail`, `AI for boutique fitness chains`, `AI for QSR franchises`, `AI for financial advisors`, `AI for RIAs`, `AI for insurance brokers`, `AI for regulated professional services`). 'Don't see your vertical?' next-radar list refreshes — replaced with direct-trade food/beverage (small-batch coffee, cheese, single-origin chocolate), small construction / general contracting, and outdoor recreation (gear shops, guide services, charter operators). New API hint chip on the templates CTA names the new /api/v1/onboarding-templates endpoint inline so integration-minded readers discover it. New focus-visible accessibility ring on every templates-page interactive element (chip links, expand summary, CTA buttons) so keyboard-only operators land cleanly — mirrors the rev-38 dashboard accessibility pattern."}]},{"rev":"rev 171","date":"2026-05-08","title":"Two more industry onboarding templates (Creator economy infrastructure + Small manufacturing / craft production) + FAQPage JSON-LD on every /templates/[key] detail page + initials-avatar block on per-author OG images + Organization + WebSite + SoftwareApplication JSON-LD on the landing page — closes both load-bearing rev-170 named next-sprint candidates (further industry templates AND per-vertical FAQ schema on /templates/[key] pages AND per-author avatars in OG images via next/og) and opens the structured-data axis on the landing page itself for the first time — 93rd unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — Creator economy infrastructure + Small manufacturing / craft production","description":"Closes the named rev-170 next-sprint candidate (further industry templates — creator economy infrastructure, small manufacturing / craft production) at two more underserved SMB segments. Creator economy infrastructure (newsletter operators, membership platforms, community-led media — 4 high-importance memory entries: named-relationship subscriber communication, 72h owned-channel platform-risk syndication rule, $35 CPM sponsorship floor, three-opens-no-clicks-30-days subscriber churn red flag + 1 sample paid-tier downgrade feedback signal) AND Small manufacturing / craft production (owner-led manufacturers, craft producers, small-batch CNC / leather / textile / ceramics / specialty food — 4 high-importance memory entries: named-maker production communication, worst-case lead-time honesty rule, 35% supplier-concentration red flag, sampled defect-rate quality audit cadence + 1 sample B2B custom-request feedback signal). Two new OnboardingTemplateKey enum values (creator_infra, small_manufacturing) extend the rev-19 pattern. The templates cluster is now nineteen named verticals deep, closing the day-1 starvation-point story across two more underserved SMB segments where the procurement-conscious buyer's 'will it know my industry on day 1?' question is loudest — newsletter operators / membership platforms where platform-risk + subscriber-cadence anxiety are 2026 market-table-stakes, and small manufacturing / craft producers where named-maker attribution + supplier-concentration discipline are the load-bearing differentiators against the platform-tier marketplaces."},{"label":"Per-vertical FAQPage JSON-LD on every /templates/[key] detail page","description":"Closes the named rev-170 next-sprint candidate (per-vertical FAQ schema on /templates/[key] pages with sample procurement questions per vertical). Procurement reviewers + AI tooling discovery systems consuming schema.org markup can now answer five named procurement-conscious questions per vertical without parsing the page body: (1) does Loop Desk know my industry on day 1, (2) what gets pre-loaded, (3) is the pre-loaded knowledge editable, (4) can the operator skip a template, (5) how does Loop Desk's flat-fee compare to per-cycle-credit AI tools at the per-vertical axis. Pure server-rendered <script type='application/ld+json'> block generated at request time from the existing template data + a small per-vertical answer-template helper. Mirrors the rev-103 Article markup pattern and the rev-170 CollectionPage + ItemList markup at the per-template detail axis. Strategic significance: closes the structured-data symmetry on the per-template detail pages alongside the rev-169 per-template OG cards (rich previews) + rev-170 ItemList markup on the index — the templates cluster is now structured-data-complete on every read surface."},{"label":"Initials-avatar block on per-author OG images","description":"Closes the named rev-170 next-sprint candidate (per-author avatars in OG images via next/og — surfacing actual avatars in the share card via next/og would close the OG-image-polish loop on the byline axis). Until rev 171 the rev-168 per-author OG cards surfaced the author's name as the headline + post-count as the subline + three stat chips, but had no identity-anchor visual element. Rev 171 closes the loop with an 88px circular avatar block in the eyebrow row of every per-author OG card. Two render paths: (a) when the author has registered an avatarUrl in data/blog-authors.json or via authorAvatar frontmatter, the avatar URL renders inline as an <img>; (b) the always-renderable fallback is an initials circle (first + last initial for two-name authors, first two characters for single-name authors). The shared renderOg helper in src/lib/og-image.tsx gains an optional avatar input so the per-author route handler is the only consumer that opts in — every other public-marketing OG card keeps its existing typographic card. Strategic significance: closes the OG-image-polish loop on the byline axis at the lowest possible primitive — no avatar-fetching infrastructure required for the always-renderable fallback, and the optional imageUrl path means a contributor who registers a Gravatar / CDN URL gets a real photo without re-deploying."},{"label":"Organization + WebSite + SoftwareApplication JSON-LD on the landing page","description":"Opens the schema.org structured-data axis on the most operator-loaded public surface for the first time. Until rev 171 the rev-103 /blog/[slug] Article markup, rev-170 /templates + /integrations CollectionPage + ItemList markup, and rev-171 /templates/[key] FAQPage markup together shipped structured data on every public marketing surface — except the landing page itself. The Organization block names the brand + logo + sameAs links so AI tooling discovery systems answer 'what is Loop Desk' with one fetch; the WebSite block surfaces a SearchAction shape so Google + AI tooling can render an inline blog search box; the SoftwareApplication block names the flat-fee positioning at the structured-data axis explicitly so procurement reviewers + AI tooling roundup newsletters scraping the landing page see 'free tier; flat-fee paid tiers with no per-cycle credits' in machine-readable form. Strategic significance: every public marketing surface now ships schema.org structured data — landing (rev 171), templates index (rev 170), templates detail (rev 171 FAQPage), integrations (rev 170), blog post (rev 103), per-author archive (rev 105 + rev 171 OG avatar). Pairs with rev-167 / 168 / 169 dynamic OG cards as the full SEO + sharable-card story."}]},{"rev":"rev 170","date":"2026-05-08","title":"Two more industry onboarding templates (B2B services / consultative sales + Home services platforms) + server-side per-rev link index on /changelog for crawler discoverability + JSON-LD CollectionPage + ItemList structured data on /templates and /integrations — closes the rev-169 named next-sprint candidates (further industry templates AND /changelog SSR'd page link to per-rev pages) at two more verticals + the SSR'd discoverability axis + opens the structured-data axis on the public marketing trio — 92nd unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — B2B services + Home services platforms","description":"Brings the templates cluster to seventeen named verticals. B2B services / consultative sales closes the named rev-169 next-sprint candidate (B2B services with long sales cycles) at the sixteenth vertical: 4 high-importance memory entries (named-next-commitment buyer communication, multi-stakeholder layer-up champion rule, 14-day pipeline-stall red flag, outcome-bound proposal scope rule) + 1 sample proposal-stage stakeholder feedback signal. Home services platforms closes the named rev-169 next-sprint candidate (home services platforms — HVAC / plumbing / electrical adjacent at the platform tier) at the seventeenth vertical: 4 high-importance memory entries (named-technician customer confirmation, parts/labour quote transparency, 90-day callback red flag, 24-hour-after-invoice review-request cadence) + 1 sample dispatch coordination signal. Two new OnboardingTemplateKey enum values (b2b_services, home_services) extend the rev-19 pattern."},{"label":"Server-side per-rev link index on /changelog","description":"Closes the named rev-169 next-sprint candidate (/changelog page link to per-rev pages on the SSR'd HTML — adding it server-side too would let crawlers discover the per-rev URL even without JS). The rev-169 'Open page →' link lives inside the rev-101 'use client' ChangelogList component which can mask discoverability for crawlers that don't fully render the React tree. Rev 170 adds a plain server-rendered <nav> + <ol> at the bottom of /changelog with one anchor per rev that guarantees every per-rev URL lands in the SSR'd HTML response body regardless of JS execution. Pure SSR, zero client-side cost. Visually tucked as an 'All revisions' appendix under the rev-101 client list so it doesn't compete with the existing search + permalink surface above. Closes the SSR'd discoverability axis on the rev-169 per-rev detail page primitive."},{"label":"JSON-LD CollectionPage + ItemList structured data on /templates and /integrations","description":"Pairs with the rev-103 /blog/[slug] Article markup as the second + third axes of the structured-data story across the public marketing trio. The /templates page emits a CollectionPage with an ItemList of every shipped template (name, description, URL); the /integrations page emits a CollectionPage with an ItemList of every channel (axis-prefixed name + auth model in description). Google + AI tooling discovery systems that scrape schema.org markup now see every template + every integration channel with one fetch instead of having to render the React tree. Procurement teams searching for 'AI workspace integrations' or 'Loop Desk templates by vertical' land on the matching page with full structured-data context, not just title + description. Marketing surface — pairs with the rev-167/168/169 dynamic OG cards (rich previews) and the rev-103 / rev-105 / rev-107 / rev-108 blog index entries (per-axis discoverability) for the full SEO + sharable-card story across every public marketing surface."},{"label":"Templates + integrations + CTA copy refresh","description":"/templates page count copy bumps 'fifteen verticals today' → 'seventeen verticals today' across hero, metadata title, OpenGraph + Twitter description, and the templates-cta. Two new keyword hints on the per-vertical chip line (B2B services 'Pipeline · stakeholders · proposals · expansion'; Home services 'Dispatch · technicians · quotes · callbacks'). Four new SEO keywords (AI for B2B services, AI for home services platforms, AI for HVAC contractors, AI for plumbing companies). 'Don't see your vertical?' radar list refreshes — replaced with creator economy infrastructure (newsletters / membership platforms), small manufacturing / craft production, and franchise-model multi-location operators now that B2B services + home services are shipped. Sitemap gains 2 new per-template detail pages automatically (priority 0.55, monthly) since it reads from ONBOARDING_TEMPLATES directly."}]},{"rev":"rev 169","date":"2026-05-07","title":"Two more industry onboarding templates (Accounting / compliance + Fitness / wellness studios) + per-template detail pages at /templates/[key] with their own OG cards + per-rev detail pages at /changelog/[rev] with their own OG cards — closes both named rev-168 next-sprint candidates (per-template OG images at /templates#template-{key} deep-links AND per-rev OG images on /changelog#rev-N deep-links) at the load-bearing share + SEO surface — 91st unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — Accounting / compliance + Fitness / wellness studios","description":"Brings the templates cluster to fifteen named verticals. Accounting / compliance closes the named rev-168 next-sprint candidate (accounting / compliance — legal-adjacent) at the fourteenth vertical: 4 high-importance memory entries (precise-not-reassuring client communication leading with the number, 5-business-day filing buffer, scope-creep red flag at 3+ unbilled questions/month, dated advice-memo audit trail) + 1 sample late-document feedback signal. Fitness / wellness studios closes the named rev-168 next-sprint candidate (fitness / wellness studios — membership-adjacent) at the fifteenth vertical: 4 high-importance memory entries (coach-voice member communication, 90% safe-capacity class booking rule, 14-day silent-regular-member retention red flag, 6-paying-member class economics floor) + 1 sample class-format feedback signal."},{"label":"Per-template detail pages at /templates/[key] with their own OG cards","description":"Closes the named rev-168 next-sprint candidate (per-template OG images at /templates#template-{key} deep-links). The rev-168 fragment links don't reach the server so they can't carry per-template OG metadata — a share into Slack / X / LinkedIn / Bluesky always rendered the rev-167 generic /templates card. Rev 169 ships proper per-template URLs at /templates/{key} with their own OG image route handler so each vertical has a sharable surface that names the specific template + memory seed count + sample signal count. Each per-template page also serves as a per-vertical SEO surface in its own right alongside the rev-166 /templates index. Statically prerendered for every template via generateStaticParams. Brand-amber accent matches the rev-167 generic /templates card so the templates OG family scans as siblings."},{"label":"Per-rev detail pages at /changelog/[rev] with their own OG cards","description":"Closes the named rev-168 next-sprint candidate (per-rev OG images on /changelog#rev-N deep-links). The rev-101 in-page #-fragment permalink can't change OG metadata per rev, so a share into Slack / X / LinkedIn / Bluesky always rendered the rev-167 generic /changelog card. Rev 169 ships proper per-rev URLs at /changelog/{n} with their own OG image route handler so every revision's share card carries the specific rev label + date + headline as the eyebrow + subline. Brand-teal accent matches the rev-167 generic /changelog card. Statically prerendered for every rev (157 prerendered pages at build time). Adds a quiet 'Open page →' link to every rev row on the rev-101 list so operators discover the per-rev page without leaving the index."},{"label":"Templates + sitemap + changelog list copy refresh","description":"Templates page count copy bumps from 'thirteen verticals today' to 'fifteen verticals today'. Each template card on /templates surfaces an 'Open the {name} page →' link to the new per-template detail page. Two new keyword hints (Accounting `Filings · client comms · advisory cadence · scope`, Fitness `Members · attendance · retention · class economics`) plus three new SEO keywords (AI for accounting practices, AI for fitness studios, AI for wellness centres). The sitemap gains 15 per-template pages (priority 0.55, monthly) + 157 per-rev pages (priority 0.5, never — content is frozen by rev). 'Don't see your vertical?' CTA copy refreshes the next-radar list — replaced with B2B services with long sales cycles, home services platforms, creator-economy infrastructure, and small manufacturing / craft production now that accounting + fitness are shipped."}]},{"rev":"rev 168","date":"2026-05-07","title":"Two more industry onboarding templates (Property management + Nonprofit / membership) + per-author OG images on /blog/author/[slug] + per-post OG images on /blog/[slug] — extends the rev-167 dynamic OG primitive to the per-author + per-post axes and closes the named rev-167 next-sprint candidates (further industry templates AND OG image polish) at two more verticals + two more share surfaces — 90th unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — Property management + Nonprofit / membership","description":"Closes the named rev-167 next-sprint candidate (further industry templates) at the twelfth and thirteenth verticals. Rev 19 opened the templates cluster with five verticals; rev 165 added Healthcare; rev 166 added Real estate + Legal; rev 167 added Field services + Restaurant + Education. Rev 168 adds Property management (owner-led property managers, landlord operators, small management companies — 4 high-importance memory entries: tenant communication leading with a named next step, 24h-acknowledgement / 72h-resolution maintenance triage, 90-day renewal red flag, 6-month inspection cadence + 1 sample recurring-HVAC feedback signal) AND Nonprofit / membership (donors, members, programmes, grant cycles — 4 high-importance memory entries: donor communication leading with gratitude before any ask, concrete-numbers-not-adjectives outcome reporting, 18-month lapsed-donor red flag with a 12-month re-engagement watch threshold, 90-day grant-cycle prep horizon + 1 sample newsletter-cadence feedback signal). Brings the templates cluster to thirteen named verticals."},{"label":"Per-author OG images on every /blog/author/[slug]","description":"Extends the rev-167 dynamic-OG primitive to the per-author archive surface. Until rev 168, sharing `loopdesk.space/blog/author/<slug>` into Slack / X / LinkedIn / Bluesky fell back to the rev-167 generic /blog OG card. Rev 168 makes every per-author archive carry its own typographic card via next/og — author name as headline, profile tagline (or post-count fallback) as subline, and three stat chips (posts, words, latest). Brand-purple accent distinguishes author cards from /blog (teal) so the public-marketing OG family scans as siblings without competing. SSG'd via `generateStaticParams` so every author route is statically prerendered at build time. Pairs naturally with the rev-105 per-author archive page primitive — rev 105 made the archive page exist, rev 168 makes its share card carry author identity."},{"label":"Per-post OG images on every /blog/[slug]","description":"Extends the rev-167 dynamic-OG primitive to every individual blog post. Until rev 168, sharing a specific post URL fell back to the generic /blog OG card; rev 168 makes every post carry its own typographic card with title as headline, excerpt as subline, three stat chips (read time, words, date), and a category-tinted accent (approval-governance → teal, memory-context → navy, signal-stream → amber, market-strategy → purple) so the share card itself signals where the post lives in the topical map. Statically prerendered for every post via `generateStaticParams`. Closes the named rev-167 OG-image-polish follow-up at the load-bearing public-reading surface — every blog post is the most-shared content type Loop Desk produces."},{"label":"Templates page + keyword hint refresh","description":"Templates page count copy bumps from 'eleven verticals today' to 'thirteen verticals today'; the keyword hint map adds two new entries (`Tenants · maintenance · renewals · inspections` for property management, `Donors · members · outcomes · grant cycles` for nonprofit); SEO keyword set expands with two new vertical-buyer terms (`AI for property management`, `AI for nonprofits`); 'Don't see your vertical?' CTA copy refreshes the next-radar list — replaced with accounting / compliance (legal-adjacent), B2B services with long sales cycles, fitness / wellness studios (membership-adjacent), and home services platforms now that property management + nonprofit are shipped."}]},{"rev":"rev 167","date":"2026-05-07","title":"Three more industry onboarding templates (Field services + Restaurant/hospitality + Education) + dynamic per-page OG images via next/og — closes the named rev-166 next-sprint candidates (further industry templates AND per-page OG images) and fixes the broken `og-default.png` reference rev-166 metadata pointed at — 89th unbroken cadence rev","highlights":[{"label":"Three more onboarding templates — Field services + Restaurant/hospitality + Education","description":"Closes the named rev-166 next-sprint candidate (further industry templates) at the ninth, tenth, and eleventh verticals in one cycle. Rev 19 introduced industry onboarding templates with five verticals; rev 165 added Healthcare/Wellness; rev 166 added Real estate + Legal. Rev 167 adds Field services / trades (HVAC, plumbing, contracting, landscaping — 4 high-importance memory entries: customer communication voice with ETAs, written quote stance with 14-day validity, callback red flag inside 30 days, same-day review cadence + 1 sample late-dispatch feedback signal), Restaurant/hospitality (independent operators + small chains — 4 high-importance memory entries: warm-brief guest comms, 15-minute reservation grace policy, three-low-reviews red flag, supplier invoice variance threshold + 1 sample slow-service feedback signal), and Education / tutoring (small schools, tutoring services, bootcamps — 4 high-importance memory entries: concrete parent comms, three-absences attendance threshold, 60-day renewal window, monthly outcome-win cadence + 1 sample homework-load feedback signal). Brings the templates cluster to eleven named verticals, closing the day-1 starvation-point story across every owner-led SMB segment Loop Desk's approval-first vocabulary fits, including the three trade/service segments rev-166 explicitly named as the next radar candidates."},{"label":"Dynamic per-page OG images via next/og — closes rev-166 named candidate + fixes broken share cards","description":"Closes the named rev-166 next-sprint candidate (per-page OG images on /templates / /integrations / /roadmap / /changelog) and silently fixes a real bug: rev-166 metadata referenced `https://loopdesk.space/og-default.png` for share cards but no such file existed in /public (the actual file shipped is `og-image.png`), so share cards into Slack / X / LinkedIn / Bluesky rendered without an image. Rev 167 ships an `opengraph-image.tsx` route handler in each of the four marketing route segments. Each handler imports a shared `renderOg` helper from `src/lib/og-image.tsx` that uses next/og's `ImageResponse` to render a typographic card with Loop Desk branding + page-specific stat chips (changelog: latest rev / total rev count, roadmap: phase count + item count, templates: vertical count + memory-seed count, integrations: inbound/outbound/programmatic counts) and a per-page accent palette (teal / purple / amber / navy). The static `images` field on each page's metadata is dropped so Next.js auto-discovers the dynamic route. Each card is statically prerendered at build time so the share-link round-trip stays fast."},{"label":"Templates page + integrations page copy refresh","description":"Templates page count copy bumps from 'eight verticals today' to 'eleven verticals today'; the keyword hint map adds entries for the three new templates (`Dispatch · quotes · callbacks · reviews` for field services, `Covers · reservations · review patterns · supplier mix` for restaurant, `Attendance · renewals · parent comms · outcomes` for education); SEO keyword set expands with the three new vertical-buyer terms (`AI for field services`, `AI for restaurants`, `AI for tutoring`). 'Don't see your vertical?' CTA copy refreshes the next-radar list since rev 166's named candidates are now shipped — replaced with property management (real-estate-adjacent), accounting/compliance (legal-adjacent), nonprofit/membership orgs, and B2B services with long sales cycles."}]},{"rev":"rev 166","date":"2026-05-07","title":"Two more industry onboarding templates (Real estate + Legal) + public /templates marketing page + clickable activation checklist step rows + rich social-share metadata across the public marketing trio (changelog + roadmap + integrations) — closes the named rev-165 next-sprint candidate (further industry templates) at the cluster's seventh and eighth verticals + opens the second public marketing surface that answers a procurement-conscious question — 88th unbroken cadence rev","highlights":[{"label":"Two more onboarding templates — Real estate + Legal/professional services","description":"Closes the explicit rev-165 next-sprint candidate at the seventh and eighth verticals. Rev 19 introduced industry onboarding templates with five verticals (ecommerce/saas/consulting/agency/creator); rev 165 added Healthcare/Wellness as the sixth. Rev 166 adds Real estate / property (owner-led brokerages, property managers, leasing — 4 high-importance memory entries: buyer/tenant outreach voice, listing freshness floor, renewal red flag, review cadence + 1 sample buyer-feedback signal) AND Legal / professional services (solo + small firms, accountants, advisors — 4 high-importance memory entries: client communication voice, conflict-check policy, deadline-buffer lesson, retention red flag + 1 sample client-feedback signal). Both verticals were named in the rev-165 running state as the next natural underserved segments. Pure additive — same rev-19 pattern, new `OnboardingTemplateKey` values (`real_estate`, `legal`), no migration. Brings the templates cluster to eight named verticals, closing the day-1 starvation-point story across every owner-led SMB segment Loop Desk's approval-first vocabulary fits."},{"label":"Public /templates marketing page","description":"Pairs with /integrations (rev 165 — vendor inventory) as the second public marketing surface that answers a specific procurement-conscious question. /integrations answers 'what does this product connect to'; /templates answers 'will it know my industry on day 1'. Until rev 166 the rev-19/165/166 onboarding template list lived only inside the signup flow — a prospect evaluating Loop Desk had to start a workspace to see whether their vertical was supported. The /templates page closes that loop: every available template renders as a card with name, description, vertical-keyword chip, memory + signal counts, and a `<details>` expansion that lists every memory entry + sample signal the template pre-loads — concrete day-1 evidence for the buyer's procurement check. Sitemap entry + nav links across landing/integrations/roadmap/changelog/blog/docs. SEO win on per-vertical buyer terms ('AI workspace for healthcare practice', 'AI workspace for real estate brokerage', 'AI workspace for legal practice', etc.)."},{"label":"Activation checklist v3 — clickable step rows","description":"Rev 165 v2 sharpened copy + added the 6th step + percent. Rev 166 v3 makes each step *clickable* — tap 'Connect a feed' → smooth-scroll to `#panel-sources`. Each step now has an optional `href` mapping to a matching dashboard panel anchor (`#panel-sources` / `#panel-signal-add` / `#panel-approvals` / `#panel-integrations`). Done steps stay inert; live steps render as `<a>` with the new `.ld-activation-step-link` treatment (hover lift + brand-color background tint + focus-visible ring + 'Take me there →' chip that fades in on hover). Closes the day-1 'where do I do this?' friction without a new copy axis. Pairs with the rev-23 keyboard-shortcut FAB + rev-27 ⌘K command palette as the third launcher into dashboard panels — but the most discoverable one for new operators who don't yet know about the keyboard surface."},{"label":"Rich social-share metadata across the public marketing trio","description":"Until rev 166 the public marketing surfaces (/changelog, /roadmap, /integrations, plus the new /templates) had only title + description metadata; share links into Slack / X / LinkedIn / Discord / Bluesky rendered as plain-text previews, which converts at a fraction of the rate of rich-card previews. Rev 166 adds full openGraph + twitter card blocks to all four pages with canonical URLs, OG image references, descriptive social-share copy distinct from the page-meta copy (so the share-card lede reads as a hook rather than a duplication), and `card: summary_large_image`. Marketing surface improvement that compounds across every share — every rev-101 changelog permalink share, rev-125 roadmap permalink share, and rev-126 roadmap-filter share chip now lands in chat with a card preview."}]},{"rev":"rev 165","date":"2026-05-07","title":"Strategic diversification — Healthcare/Wellness onboarding template + public /integrations marketing page + activation checklist v2 (6 steps with refreshed copy and a guardrail nudge) + evergreen operator blog post on the always-on desk shape — pivot away from the 14-rev cost-spike alarm thread (rev 151-164) onto the public-marketing + onboarding axes — 87th unbroken cadence rev","highlights":[{"label":"Healthcare/Wellness onboarding template — sixth industry preset","description":"New ONBOARDING_TEMPLATES entry for Healthcare/Wellness practice owners (independent therapists, dentists, vets, dental clinics, wellness studios) — a real underserved SMB segment that until rev 165 had to fall back on Other/Custom. Seeds 4 high-importance memory entries (patient-communication preference, no-show policy, review-cadence lesson, retention-red-flag lesson) plus 1 sample patient-feedback signal so the workspace's first cycle has substance. Mirrors the rev-19 pattern (Ecommerce/SaaS/Consulting/Agency/Creator) at the sixth named vertical. Strategic significance: closes a gap in the day-1 starvation-point story for an industry segment that maps cleanly onto Loop Desk's approval-first vocabulary (no-show notification, review-request copy, retention nudges all want the same human-in-the-loop boundary)."},{"label":"Public /integrations marketing page — closes the public marketing trio","description":"Loop Desk has shipped /changelog (history) since rev 14 and /roadmap (future) since rev 38, but until rev 165 had no single page answering 'what does this product connect to?' for procurement teams + B2B buyers evaluating governance-first AI. The /integrations page lists every Loop Desk channel grouped by axis: inbound (RSS / review sites / LinkedIn / email forwarding / inbound webhooks / manual logging — 6 entries with auth model + sinceRev), outbound (Slack push / outbound webhooks per-event router / daily digest / public share links / public desk-health badge SVG — 5 entries), and programmatic (REST API v1 / OpenAPI 3.1 / MCP server coming Q3 — 3 entries). Each entry names the auth model and the rev where it shipped, doubling as a vendor inventory for SOC 2 / ISO 42001 procurement reviews. New page mounted at /integrations + sitemap entry + nav links across landing/changelog/roadmap/docs/blog so the public marketing trio (changelog + roadmap + integrations) is reachable from every other public surface. Strategic significance: cumulative diversification away from the 14-rev cost-spike-axis cluster (rev 151-164) onto the public marketing surface. SEO win on 'AI workspace integrations', 'governance-first AI vendor inventory', 'MCP business workspace integrations' — buyer-side terms."},{"label":"Activation checklist v2 — 6th step + sharper copy on existing 5","description":"The rev-11 activation checklist shipped 5 steps (connect a source / log signal / run a cycle / approve first output / wire integration) when the dashboard had ~12 panels. After 154 revs the desk has accumulated memory teaching, multi-operator invites, per-recipient digests, cost guardrails, and the MCP-foundation v1 API — but the checklist copy still read like rev 11. Rev 165 refreshes it on three axes: (a) sharper copy on the existing 5 steps that names current affordances ('connect a feed' vs 'Hook up an RSS feed'), (b) adds a 6th step 'Set a guardrail' that nudges new operators toward configuring at least one of: daily cost cap (rev 20), Slack quiet hours (rev 15), or workspace timezone (rev 20) — until rev 165 first-day operators didn't see the desk's operator-respect controls until they hit them organically, (c) visual: numeric badges on each step + tactile hover lift on incomplete steps so the recommended sequence is implicit. New `hasGuardrail` boolean computed in `app/page.tsx` from existing workspace columns. Strategic significance: the activation surface is the single most operator-loaded onboarding affordance on the dashboard; refreshing it to match the modern feature set is a load-bearing trust signal for new workspaces."},{"label":"Evergreen blog post — 'The Morning News Habit, Replaced By An Always-On Desk'","description":"New blog post pivots away from the AI-meta / governance-DevOps / CI-CD security topics that have dominated the rev-by-rev blog cadence for many cycles. Operator-focused angle: what changes structurally when an owner-led team's morning news routine is replaced by an always-on AI workspace. Frames the four trust contract pieces (approval boundary / audit trail / cost predictability / operator-respect controls) as the structural constraints that make 'always-on' a sustainable daily habit rather than a weekend experiment. Names Notion Custom Agents' per-cycle credits + HubSpot Breeze's outcome-based pricing as competitive contrast. SEO play on 'always-on AI workspace', 'morning routine AI', 'governance-first AI for owner-led teams', 'flat-fee AI workspace' — operator-side buyer terms distinct from the technical/governance cluster the recent posts have all been targeting. Closes with concrete CTA cluster pointing at signup + docs + integrations + roadmap."}]},{"rev":"rev 164","date":"2026-05-07","title":"Per-memory cost spike + chronic warning daily digest sections close the email-channel parity gap on the rev-161 daily alarm AND the rev-163 chronic warning at the per-memory axis — closes the named rev-163 next-sprint candidate (per-memory chronic-warning digest section) — 86th unbroken cadence rev","highlights":[{"label":"Per-memory cost spike daily digest section closes the email channel gap on the rev-161 alarm","description":"New buildMemoryCostSpikesSection() helper renders up to 5 spiking memory entries with ⚡ ratio + today vs avg + kind chip + importance chip + retrieval count + structural-fix copy ('pin or raise importance ≥9 to exempt, or ack to silence today'). Pre-fetched once per workspace via the existing rev-161 detectMemoryCostSpikes() helper and reused across every owner/admin recipient on the cron daily digest path — same pattern the rev-60 source / rev-63 assignee / rev-68 tag daily spike sections use. Workspace-shared (every owner/admin sees the same list since 'this knowledge entry is anomalously expensive today' is workspace-level diagnostic context). The rev-161 daily Slack push + outbound memory.cost_spike event were already fired by pingMemoryCostSpikes() earlier in runDailyDigest, so the email surface stays in lockstep with the chat + integration channels. The detector itself filters out entries acked today via the rev-162 costSpikeAckedAt stamp so the email rows match what the dashboard ⚡ pill shows. Closes the alarm cluster's seventh axis on the email channel — workspace (rev 32) / per-task (rev 55) / per-source (rev 60) / per-assignee (rev 63) / per-tag (rev 68) / per-memory daily (rev 164) all now reach the digest email."},{"label":"Per-memory chronic-warning digest section closes the named rev-163 next-sprint candidate at the email channel","description":"Closes the explicit rev-163 next-sprint candidate ('per-memory chronic-warning digest section'). New buildMemoryChronicWarningSection() helper mirrors the rev-75 source/tag chronic-warning sections at the per-memory axis with amber ⏳ Nd-in-a-row chips + ⚡ ratio + structural-fix copy ('the entry is being retrieved too often by too many cycles — pin, raise importance, or refactor surrounding tasks'). Pure derived state from the rev-161 detector return shape: filter to entries whose consecutiveSpikeDays counter has crossed the chronic threshold (3 days, matching rev 70/72/163) AND whose chronicAckedAt stamp is absent or older than the 7-day TTL — same filter shape as the rev-75 source/assignee/tag chronic filtering. Workspace-shared (memory entries don't have assignees so the section lists every chronic entry in one block, mirroring the rev-75 source/tag chronic-warning sections rather than the rev-49 per-recipient stale pattern). The rev-163 chronic-warning Slack push + outbound memory.chronic_warning event were already fired by pingMemoryCostSpikes() so the email surface stays in lockstep with the chat + integration channels. Closes the chronic horizon on the alarm cluster's seventh axis on the email channel: per-source chronic (rev 75) / per-assignee chronic (rev 75) / per-tag chronic (rev 75) / per-memory chronic (rev 164) — every chronic axis now reaches the digest email."},{"label":"Plumbed through buildDigestHtml + production cron + admin preview path in lockstep","description":"Both new sections wired into the buildDigestHtml() params signature with optional fields — undefined-safe so no behavior change on workspaces without spikes. Cron daily digest path (runDailyDigest) pre-fetches memorySpikes once per workspace via detectMemoryCostSpikes() and derives the chronic entries inline using the same CHRONIC_THRESHOLD_DAYS + CHRONIC_ACK_TTL_MS constants the rev-75 chronic sections use — one shared filter shape across all four chronic axes. Admin preview path (previewDigestForUser, the rev-36 send-test path) mirrors the cron exactly so admins iterating on configuration see the same surface they'll receive in production. Render order: per-memory daily section appears LAST among daily alarm sections (after per-task/per-source/per-assignee/per-tag) so readers scan the cost story in one visual block; per-memory chronic appears LAST among workspace-shared chronic sections so the four-axis chronic vocabulary reads in one visual block. The detector is read-only — no counter increment, no chronic-ack stamping — so running an admin preview does NOT alter the rev-163 consecutiveSpikeDays counter or the rev-162/163 ack stamps."},{"label":"OpenAPI 3.1 spec changelog header documents the rev-164 closure — 86th unbroken cadence rev","description":"No new v1 endpoints (the rev-161 /memory/cost-spikes + rev-163 /memory/chronic-warnings already cover the protocol-bound surface). The OpenAPI 3.1 spec changelog header gains a rev-164 block explaining the email-channel parity gap closure on both alarms in a single cycle. 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 86th unbroken rev with rev 164 — even though no new v1 endpoint ships, the pattern is preserved by documenting the rev-164 closure in the OpenAPI changelog header so MCP-host code generators reading the spec see exactly when each rev's primitive landed (either as new endpoint or as channel expansion of an existing alarm). The cost-spike alarm cluster's seventh axis (per-memory) now reaches every operator-loaded channel — in-app ⚡ + ⏳ chips, daily Slack push, outbound webhook events, AND digest email — across both daily and chronic horizons."}]},{"rev":"rev 163","date":"2026-05-07","title":"Per-memory chronic-spike counter + warning + chronic-ack chip on TopCostMemoryPanel + memory.chronic_warning + memory.chronic_warning_acked outbound events + GET /api/v1/memory/chronic-warnings + POST /api/v1/memory/{id}/chronic-ack + bulk v1 mirror closes the chronic axis on the cost-spike alarm cluster's seventh axis at parity with the daily axis (rev 161/162) — closes the named rev-162 next-sprint candidate at the per-memory chronic horizon — 85th unbroken cadence rev","highlights":[{"label":"Per-memory consecutiveSpikeDays counter + chronicAckedAt column + counter maintenance in pingMemoryCostSpikes","description":"Closes the named rev-162 next-sprint candidate ('per-memory chronic-spike counter + warning'). Two new columns on memory_entry: `consecutiveSpikeDays` (integer NOT NULL default 0 — increments every day the rev-161 detector flags the entry as spiking; resets to 0 the first day it doesn't) and `chronicAckedAt` (timestamp nullable — stamped when the operator chronic-acks the entry for the rev-163 7-day TTL window). The rev-161 pingMemoryCostSpikes daily sweep now maintains the counter on every sweep via batched UPDATEs (one to bump spiking entries, one to reset entries that previously had a non-zero counter but aren't currently spiking). Mirrors the rev-61 source counter + rev-64 assignee counter + rev-70 tag counter at the per-memory axis on the cost dimension. Independent of `costSpikeAckedAt` (rev 162 — per-day mute) — the counter keeps growing through ack-and-spike-again cycles so a memory entry that's been 'ack me daily' for a week shows the strongest possible chronic-noise signal. Pure additive on top of the rev-161 daily detector — no change to the rev-161 behavior unless an operator's entry crosses the chronic threshold."},{"label":"Per-memory chronic warning Slack push + memory.chronic_warning outbound event in pingMemoryCostSpikes sub-sweep","description":"New chronic-warning sub-sweep added to pingMemoryCostSpikes mirrors the rev-70 tag chronic / rev-72 source chronic / rev-72 assignee chronic patterns at the per-memory axis. For each workspace where any memory entry's counter has crossed the chronic threshold (3 days) AND hasn't been chronic-acked within the 7-day TTL: (a) Slack push via the new buildMemoryChronicWarningSlackPayload() block (header `:hourglass_flowing_sand: Chronic per-memory cost spike` + per-entry rows with `Nd in a row`, ratio, today $, retrieval count + recommendation copy 'consider pinning, raising importance, or refactoring the surrounding tasks'), (b) outbound memory.chronic_warning event via dispatchMemoryChronicWarningWebhook(), (c) memory_chronic_warning activity-log entry rate-limited to once per workspace per 24h. Same dead-Slack-webhook auto-clear path as the rev-161 daily push. Distinct from the rev-161 daily ⚡ alarm — chronic warning names a *structural* problem (the entry is being retrieved too often by too many cycles) so the right operator response is structural (pin / raise importance / refactor surrounding tasks), not 'stop alarming today.'"},{"label":"Chronic-ack chip + chronic bulk-ack bar on TopCostMemoryPanel + per-row ⏳ Nd chronic chip","description":"New MemoryChronicAckButton client component mounts inline beside the rev-163 ⏳ chronic chip on every chronically-spiking row of the rev-159 TopCostMemoryPanel. Brand-amber palette (`rgba(232,159,75,*)`) distinct from the rev-162 brand-red daily ack chip so operators read both ack horizons (today / structural) at two distinct attention levels on the same row. New chronic bulk-ack bar surfaces above the row list when canAck && visibleChronicCount >= 2 — mirrors the rev-162 daily bulk-ack bar at the chronic axis. New `⏳ Nd in a row` chronic chip on every row whose counter has crossed the threshold AND hasn't been chronic-acked within the 7-day TTL. The full row-level reading order is now consistent: ⚡ (today's alarm) ↔ Ack (mute today) :: ⏳ Nd (structural alarm) ↔ Ack 7d (mute 7d). Three layers of cost-axis context on every row (cumulative + trajectory + daily alarm + chronic alarm) — operators triaging a load-bearing memory entry now see the full descriptive→defensive picture without leaving the panel."},{"label":"v1 endpoints (chronic-warnings GET + chronic-ack POST + bulk POST) + memory.chronic_warning_acked closure + OpenAPI typed coverage — 85th unbroken cadence rev","description":"Four new endpoints close the chronic axis on the protocol-bound surface in the same cycle the dashboard primitive ships: GET /api/v1/memory/chronic-warnings (returns memory entries whose counter has crossed the chronic threshold AND haven't been chronic-acked within the 7-day TTL), POST /api/v1/memory/{memoryId}/chronic-ack (single-entry chronic ack — mirrors `/sources/{id}/chronic-ack` rev 72 + `/cost/by-tag/{tag}/chronic-ack` rev 71 at the per-memory axis), POST /api/v1/memory/chronic-ack/bulk (bulk chronic-ack up to 50 IDs — mirrors `/sources/chronic-ack/bulk` rev 87 + `/cost/by-tag/chronic-ack/bulk` rev 87 at the per-memory axis on the chronic horizon). Plus matching dashboard endpoints (POST /api/memory/{id}/chronic-ack + POST /api/memory/chronic-ack/bulk). New memory.chronic_warning + memory.chronic_warning_acked outbound events with full payload typing — the closure receipt fires from both single + bulk ack so downstream FinOps integrations can reconcile alarm-open with alarm-acknowledged at the per-knowledge-entity axis on the chronic horizon. The OpenAPI 3.1 spec types every new endpoint with full request/response schemas plus the chronic-warnings response shape with the same field projection as the rev-161 daily endpoint plus consecutiveSpikeDays + chronicAckedAt. The OpenAPI spec changelog header gains a rev-163 block explaining the chronic axis closure on the seventh alarm-cluster axis. 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 85th unbroken rev with rev 163. The cost-spike alarm cluster on the protocol-bound surface now closes both the daily horizon (rev 161/162) AND the chronic horizon (rev 163) on every axis where chronic makes sense (per-source / per-assignee / per-tag / per-memory). The MCP server has nothing left to design across detect → triage → ack on either horizon."}]},{"rev":"rev 162","date":"2026-05-07","title":"Per-memory cost-spike acknowledgment + bulk-ack on TopCostMemoryPanel + memory.cost_spike_acked outbound event + POST /api/v1/memory/{id}/cost-spike-ack + bulk v1 mirror closes the named rev-161 next-sprint candidate at the operator counter-action surface — closes the alarm cluster's seventh axis on the closure-receipt loop in lockstep — 84th unbroken cadence rev","highlights":[{"label":"Per-memory cost-spike ack (memoryEntries.costSpikeAckedAt column + acknowledgeMemoryCostSpike helper) closes the rev-161 alarm-only gap","description":"Closes the named rev-161 next-sprint candidate ('per-memory cost-spike acknowledgment') on the operator counter-action surface. New nullable timestamp column on memory_entry. Stamped by acknowledgeMemoryCostSpike() when the operator clicks the rev-162 'Ack' button beside the rev-161 ⚡ pill on the rev-159 TopCostMemoryPanel. The rev-161 detector + Slack daily push + outbound memory.cost_spike event all skip memory entries whose ack stamp is >= today's day-start in workspace TZ so a triaged spike doesn't keep firing today. Mirrors the rev-56 task / rev-59 source / rev-63 assignee / rev-68 tag ack at the per-memory axis on the cost dimension. Distinct from rev-5 pin (permanent — exempts from rev-161 detector forever via the same load-bearing-by-design exclusion that rev-161 already applies). Ack = 'I see this entry's spike, stop alarming today, but watch for tomorrow.'"},{"label":"Bulk per-memory ack-all chip on TopCostMemoryPanel + bulkAcknowledgeMemoryCostSpikes helper","description":"New bulkAcknowledgeMemoryCostSpikes() helper caps at 50 memory IDs per call matching the rev-26 / rev-33 / rev-34 / rev-36 / rev-57 / rev-60 / rev-63 / rev-68 bulk surface vocabulary. New 'Ack all N' chip surfaces inline on TopCostMemoryPanel when canAck && visibleSpikingCount >= 2 (gated to editor+ via the rev-16 role enforcement on the dashboard layer). The rev-161 daily Slack push lists up to 5 spiking memory entries; until rev 162 operators landing on the dashboard had to ack each entry individually via the rev-162 inline button. Bulk-ack collapses that to one tap. Pairs with the per-row inline ack chip for the inline-vs-batch ack symmetry — the same pattern rev 6 / 26 / 33 / 34 / 36 / 57 / 60 / 63 / 68 followed across all four core entities + per-source / per-assignee / per-tag spike alarms now applies to the rev-161 per-memory spike alarm."},{"label":"memory.cost_spike_acked outbound event + dispatchMemoryCostSpikeAckedWebhook closes the rev-37 closure-receipt pattern at the per-memory axis","description":"New OutboundEvent value memory.cost_spike_acked plus matching dispatchMemoryCostSpikeAckedWebhook() in src/lib/outbound.ts. Wired into both acknowledgeMemoryCostSpike() and bulkAcknowledgeMemoryCostSpikes() via void dispatch...({...}) so a downstream failure can't ripple back to block the ack itself. Mirrors the rev-61 task.cost_spike_acked + source.cost_spike_acked + rev-63 assignee.cost_spike_acked + rev-68 tag.cost_spike_acked closure-receipt pattern at the per-memory axis. Closes the alarm-cluster's seventh axis on the closure-receipt loop. External integrations watching the rev-161 memory.cost_spike event can now reconcile alarm-open with alarm-acknowledged at the per-knowledge-entity axis just as they already could at task / source / assignee / tag — load-bearing for FinOps tools tracking AI cost on a per-knowledge-asset dashboard, CRMs tagging knowledge entries by ROI, and board-status integrations aggregating 'open cost issues this week' surfaces. Rate-limited correctly: only fires when the SQL UPDATE returns at least one acked row so a no-op bulk call doesn't poison the audit trail."},{"label":"Dashboard + v1 ack routes (single + bulk) + OpenAPI 3.1 typed coverage — 84th unbroken cadence rev","description":"Four new endpoints — POST /api/memory/{memoryId}/cost-spike-ack, POST /api/memory/cost-spike-ack/bulk, POST /api/v1/memory/{memoryId}/cost-spike-ack, POST /api/v1/memory/cost-spike-ack/bulk — mirror the rev-68 tag-ack route shape exactly at the per-memory axis. Editor+ role at the dashboard layer; bearer-auth via existing ingest token at v1. The OpenAPI 3.1 spec types both new v1 endpoints with full request/response schemas (memoryIds[≤50] required + acknowledgedCount response shape) plus extends the rev-161 GET /memory/cost-spikes response with the new costSpikeAckedAt field (nullable date-time) so MCP hosts render the muted-state chip without a follow-up call. The OpenAPI spec changelog header gains a rev-162 block explaining the operator counter-action closure on the per-memory axis and the new outbound event. 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 84th unbroken rev with rev 162. The cost-spike ack v1 cluster on the protocol-bound surface is now five axes deep (per-task rev 56-57 / per-source rev 59-60 / per-assignee rev 63 / per-tag rev 68 / per-memory rev 162). The MCP server's cost-axis tooling has nothing left to design across attribution + trajectory + alarm + ack at every meaningful axis."}]},{"rev":"rev 161","date":"2026-05-07","title":"Per-memory cost spike alarm + daily Slack push + outbound memory.cost_spike event + ⚡ pill on TopCostMemoryPanel + GET /api/v1/memory/cost-spikes closes the cost-spike alarm cluster's seventh axis at the per-memory level — 83rd unbroken cadence rev","highlights":[{"label":"Per-memory cost spike detector (detectMemoryCostSpikes helper) closes the cost-spike alarm cluster's seventh axis","description":"Closes the cost-spike alarm cluster's seventh axis on the load-bearing primitive layer — workspace (rev 32), per-task (rev 55), per-source (rev 58), per-assignee (rev 62), per-tag (rev 67), now per-memory (rev 161). Pure read of the rev-160 memoryEntries.dailyCostHistory primitive — no schema cost. A memory entry is spiking when its today >= 2× trailing-7-day daily average AND today >= $0.50 absolute AND >= 3 historical days of non-zero spend (so a brand-new load-bearing memory entry's first day can't trigger). Pinned + importance>=9 entries excluded server-side because they're load-bearing-by-design — alarming on them is tautological. Closes the descriptive (rev 159 attribution) → trajectory (rev 160 sparkline) → alarm (rev 161) trio at the per-memory axis on the cost dimension at parity with the per-task axis (rev 51 + 54 + 55) and the per-source axis (rev 57 + 60 + 58)."},{"label":"Daily Slack push + outbound memory.cost_spike event closes the chat + integration channel parity gap","description":"New buildMemoryCostSpikeSlackPayload() Slack block + dispatchMemoryCostSpikeWebhook() outbound dispatcher + new memory.cost_spike OutboundEvent value. New pingMemoryCostSpikes() sweep added to runDailyDigest() mirrors pingTagCostSpikes() shape exactly: rate-limited via the new memory_cost_spike activity-log kind to once per workspace per 24h with the same dead-Slack-webhook auto-clear path as rev-58 source spikes. Slack post: ':zap: Per-memory cost spike' header + listing each spike with ratio + today vs avg + retrieval count + kind + title snippet. Outbound payload includes the per-memory shape (memoryId + title + kind + importance + todayUsd + baselineUsd + spikeRatio + retrievalCount). Lets external integrations (FinOps tool tracking AI cost on a per-knowledge-asset dashboard, CRM tagging knowledge entries by ROI, board-status integration aggregating 'open cost issues this week') route the alarm by named knowledge entry — the strongest possible operator-facing answer to 'this specific knowledge asset is anomalously expensive today' because it names the entry, not just the workspace or the source."},{"label":"Inline ⚡ alarm pill + spike banner + spiking-row accent on TopCostMemoryPanel","description":"Every spiking row on the rev-159 TopCostMemoryPanel now gets a brand-red ⚡ pill alongside the rev-159 cost amount + rev-160 trajectory sparkline. Spiking rows wear a left-border accent + tinted amount color matching the rev-58 source spike + rev-67 tag spike treatments. Banner above the list summarises the spiking count inline so operators see the alarm without reading every row. Closes the visual-hierarchy gap on the rev-159 panel — operators now scan the panel and triage by alarm state (today's spike) alongside cumulative state (rev 159) and trajectory shape (rev 160) without leaving the dashboard sidebar. The rev-159 panel now reads at three orthogonal levels — same three-level pattern shipped on per-task in revs 51/54/55 + on per-source in revs 57/60/58 — uniformly applied at the per-memory axis on the cost dimension."},{"label":"GET /api/v1/memory/cost-spikes v1 endpoint + OpenAPI 3.1 typed coverage + activity-log glyph + tint — 83rd unbroken cadence rev","description":"Closes the cost-spike alarm cluster's seventh axis on the protocol-bound surface in lockstep with the dashboard primitive (cadence pattern from rev 37 onward holds unbroken into rev 161). New bearer-auth GET /api/v1/memory/cost-spikes?limit=10 endpoint mirrors the rev-58 /sources/cost-spikes shape at the per-memory axis. Each row carries memoryId, title, kind, importance, pinned, tags, todayUsd, baselineUsd, spikeRatio, retrievalCount. Pairs with /api/v1/memory/top-cost (rev 159) + /api/v1/memory/{id}/cost-trajectory (rev 160) as the three-axis cost-observability surface on the per-memory entity. The OpenAPI 3.1 spec types the new endpoint with full request/response schemas + the OpenAPI changelog header gains a rev-161 block. Activity log gains memory_cost_spike kind with ⚡ glyph matching the rev-32/55/58/62/67 cost-spike kinds so operators reading the audit trail scan all seven axes with one consistent visual vocabulary. The MCP server's per-memory cost tooling now has nothing left to design across attribution + trajectory + alarm."}]},{"rev":"rev 160","date":"2026-05-07","title":"Per-memory cost trajectory primitive + inline cost sparkline on TopCostMemoryPanel + memory list rows + GET /api/v1/memory/{id}/cost-trajectory closes the named rev-159 next-sprint candidate at the trajectory axis on the cost dimension at parity with rev-54 task cost trajectory + rev-157 memory retrieval trajectory — 82nd unbroken cadence rev","highlights":[{"label":"Per-memory daily cost history primitive (memoryEntries.dailyCostHistory column + pulse engine jsonb_set bump)","description":"Closes the named rev-159 next-sprint candidate ('per-memory cost trajectory mini-chart — letting per-memory entries carry a 7-day cost trajectory just as rev 54 added per-task daily cost history'). New JSONB column on memory_entry — same shape as the rev-54 task.dailyCostHistory primitive (Record<YYYY-MM-DD, { inputTokens, outputTokens }>). The pulse engine's per-memory cost-attribution UPDATE (rev 159) now also bumps today's bucket via SQL jsonb_set alongside the rev-159 cumulative-column writes — single statement, all retrieved rows share the same todayKey on a single cycle so one round-trip covers the entire batch. The rev-159 cumulative columns remain authoritative for total spend; this map is pure history. Trimmed implicitly via 30-day cap when the dashboard renders the trailing window — long-running entries don't grow unbounded JSONB. Closes the *trajectory* axis on the cost dimension at the per-memory level the same way rev-157 closed it on the retrieval dimension and rev-54 closed it on the per-task surface."},{"label":"Inline brand-amber MemoryCostSparkline on TopCostMemoryPanel + memory list rows","description":"New `MemoryCostSparkline` client component renders inline beside the rev-159 cost pill on every TopCostMemoryPanel row + beside the rev-157 retrieval sparkline on every memory list row whose dailyCostHistory has at least one non-zero day. Brand-amber palette (rgba(207,108,58,*)) matches the rev-159 TopCostMemoryPanel + rev-51 top-cost-tasks panel cost vocabulary. Distinct from the rev-157 brand-purple retrieval sparkline so the dashboard's two per-memory trajectory primitives (cost vs retrieval) read at two distinct attention levels. The TopCostMemoryPanel `getTopCostMemoryEntries` helper now projects a `trajectory7d` cents array per row (mirrors the rev-51 task.trajectory7d primitive at the per-memory axis on the cost dimension); the dashboard MemoryList computes a `costSparkline7dCents` per entry using the existing `trajectoryDayKeys` array (computed once for the rev-54 task cost trajectory) so the per-row work is a single Map lookup. Pinned + importance>=9 entries skip the sparkline since they're load-bearing by design. Hidden when every value is zero so fresh + never-attributed memory rows don't see clutter."},{"label":"GET /api/v1/memory/{id}/cost-trajectory v1 endpoint + extended GET /api/v1/memory listing with cost7dCents derived field + extended GET /api/v1/memory/top-cost rows with trajectory7d","description":"Closes the protocol-bound surface for the rev-160 trajectory primitive in lockstep with the dashboard. New bearer-auth `GET /api/v1/memory/{memoryId}/cost-trajectory?days=7` endpoint returns trailing N daily cost buckets oldest → newest with zero-fill (max days=30, default 7). Each row carries `{ date: ISO YYYY-MM-DD in workspace TZ, inputTokens, outputTokens, estimatedCostUsd }` so MCP hosts have the full shape without a follow-up estimateRunCostUsd call. Mirrors `GET /tasks/{id}/cost-trajectory` (rev 54) + `GET /memory/{id}/retrieval-trajectory` (rev 157) at the per-memory axis on the cost dimension. Plus the rev-153 `GET /api/v1/memory` listing endpoint now projects a `cost7dCents` derived field (sum of trailing 7 days of dailyCostHistory in cents) alongside the rev-158 `retrievals7d` — MCP hosts ranking memory by recent-activity-on-cost vs all-time see both signals in one call. Plus the rev-159 `GET /api/v1/memory/top-cost` rows now carry `trajectory7d` cents arrays so the dashboard panel + MCP hosts render the inline sparkline without a follow-up call per entry."},{"label":"OpenAPI 3.1 typed coverage on the rev-160 endpoint + extended MemoryEntry schema with cost7dCents — 82nd unbroken cadence rev","description":"The OpenAPI 3.1 spec types the new `GET /memory/{memoryId}/cost-trajectory` endpoint with full request/response schemas (memoryId path param + days query param 1-30 default 7 + response shape with `trajectory[]` array of typed rows including date ISO YYYY-MM-DD + inputTokens + outputTokens + estimatedCostUsd). The shared `MemoryEntry` schema component picks up the new `cost7dCents` derived field so MCP-host code generators reading the spec see it on every memory listing surface. The rev-159 `/memory/top-cost` row schema picks up the `trajectory7d` cents array. The OpenAPI spec changelog header gains a rev-160 block explaining the trajectory-axis closure on the cost dimension. 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 82nd unbroken rev with rev 160. The per-memory observability cluster on the protocol-bound surface is now fourteen 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 + top-retrieved rev 158 + top-cost rev 159 + cost-trajectory rev 160)."}]},{"rev":"rev 159","date":"2026-05-07","title":"Per-memory cost attribution + top-cost memory dashboard panel + GET /api/v1/memory/top-cost closes the named rev-158 next-sprint candidate (memoryEntries.totalAttributedInputTokens + totalAttributedOutputTokens columns + pulse engine equal-split distribution + getTopCostMemoryEntries helper + brand-amber TopCostMemoryPanel sidebar panel + GET /api/v1/memory/top-cost v1 endpoint + extended GET /api/v1/memory listing with cost fields + OpenAPI 3.1 typed coverage on the new endpoint and MemoryEntry schema — 81st unbroken cadence rev)","highlights":[{"label":"Per-memory cost attribution columns + pulse engine equal-split distribution","description":"Closes the named rev-158 next-sprint candidate ('memory retrieval cost attribution — letting per-memory entries carry an estimated AI cost contributed metric so operators triaging a load-bearing-but-token-heavy memory entry can see the full picture'). Two new columns on memory_entry: `totalAttributedInputTokens` + `totalAttributedOutputTokens` (integer NOT NULL default 0). The pulse engine's `workNextTask()` distributes each cycle's per-task token delta across every memory entry retrieved that cycle by equal split — same defensible methodology as the rev-57 per-source cost attribution. Single batched UPDATE rides one round-trip per cycle so the cost-attribution write costs nothing on the steady-state retrieval path. Pure additive — does not change retrieval semantics, only attaches a cost stamp to each retrieved row."},{"label":"Top-cost memory dashboard panel + GET /api/v1/memory/top-cost","description":"New `getTopCostMemoryEntries()` helper sorts memory entries desc by cumulative attributed cost. New brand-amber `TopCostMemoryPanel` sidebar mounts beside the rev-158 brand-purple `TopRetrievedMemoryPanel` so the three memory observability panels (slate-staleness rev 153 + brand-purple-retrieval rev 158 + brand-amber-cost rev 159) stack cleanly with one consistent vocabulary at three distinct attention levels. Each row shows `💸 $X.XX` cost amount, kind chip, pinned flag, title, proportional brand-amber bar, plus a meta line with token total + retrieval count + importance + tags. Hidden when no memory entry has accrued any attributed cost yet (fresh workspaces or workspaces that never run AI cycles). New bearer-auth `GET /api/v1/memory/top-cost?limit=5` v1 endpoint mirrors the dashboard primitive in lockstep — MCP hosts answering 'which memory entries are the AI's most expensive?' get a one-call answer."},{"label":"Extended GET /api/v1/memory listing with totalAttributedInputTokens, totalAttributedOutputTokens, and estimatedCostUsd","description":"Closes the cost-axis projection on the per-memory listing surface at parity with the per-task axis (rev 51's totalInputTokens + totalOutputTokens projected on /api/v1/tasks). Every row on the rev-153 listing endpoint now carries `totalAttributedInputTokens`, `totalAttributedOutputTokens`, and `estimatedCostUsd` alongside the rev-153 `retrievalCount` + `lastRetrievedAt` + rev-158 `retrievals7d`. MCP hosts ranking memory by AI cost without a follow-up call per entry — three retrieval-state signals (cumulative + recency + recent-activity) plus three cost-attribution signals (input + output + USD) on every memory listing row."},{"label":"OpenAPI 3.1 typed coverage on the rev-159 endpoint + extended MemoryEntry schema — 81st unbroken cadence rev","description":"The OpenAPI 3.1 spec types the new `GET /memory/top-cost` endpoint with full request/response schemas (limit query param 1-20 default 5 + response shape with `memory[]` array of typed rows including memoryId + kind enum + title + importance + pinned + tags + totalAttributedInputTokens + totalAttributedOutputTokens + estimatedCostUsd + retrievalCount + lastRetrievedAt nullable date-time). The shared `MemoryEntry` schema component picks up the three new cost fields so MCP-host code generators reading the spec see them on every memory listing surface. 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 81st unbroken rev with rev 159. The per-memory observability cluster on the protocol-bound surface is now thirteen axes deep — the MCP server's per-memory observability tooling has nothing left to design across all thirteen axes."}]},{"rev":"rev 158","date":"2026-05-07","title":"Top-retrieved memory dashboard panel + workspace-axis read on the rev-157 trajectory primitive (`GET /api/v1/memory/top-retrieved` endpoint + `retrievals7d` derived field on the rev-153 listing endpoint + brand-purple TopRetrievedMemoryPanel sidebar panel + getTopRetrievedMemoryEntries helper + OpenAPI 3.1 typed coverage on the new field + endpoint — 80th unbroken cadence rev)","highlights":[{"label":"Workspace-axis read on the rev-157 trajectory primitive — top-retrieved memory dashboard panel + GET /api/v1/memory/top-retrieved","description":"Closes the named rev-157 next-sprint candidate ('per-memory retrieval frequency on the v1 listing endpoint as a derived field') at the workspace-axis read shape it most needed. Rev 153 surfaced the *cumulative* retrieval state (lastRetrievedAt + retrievalCount); rev 157 surfaced the *per-memory shape over time* (the trajectory endpoint + sparkline); rev 158 surfaces the *workspace-level top-N* — 'what knowledge is the AI relying on most this week?'. New `getTopRetrievedMemoryEntries()` helper aggregates the rev-157 retrievalHistory JSONB, sorts desc by trailing-7-day retrieval count, returns top N rows (default 5) with per-row `trajectory7d` array so the panel renders the rev-157 sparkline inline without a follow-up call. New brand-purple `TopRetrievedMemoryPanel` sidebar panel mounts above the rev-153 StaleMemoryPanel — operators triaging 'is the AI focused on the right knowledge?' get a top-N answer at a glance instead of expanding the rev-157 sparkline on every memory row. Hidden when nothing has been retrieved in the trailing 7-day window. Mirrors the rev-51 `TopCostTasksPanel` shape (top-N by trailing-window activity) at the per-memory axis on the retrieval dimension. New bearer-auth `GET /api/v1/memory/top-retrieved?limit=5&days=7` endpoint exposes the same shape on the protocol-bound surface in lockstep — MCP hosts answering 'what is the AI relying on?' get a one-call answer."},{"label":"`retrievals7d` derived field on the rev-153 GET /api/v1/memory listing endpoint","description":"Closes the named rev-157 next-sprint candidate at the cheapest possible primitive — pure derived field, no schema cost. Every row on the rev-153 listing endpoint now carries `retrievals7d` (sum of trailing 7 days of the rev-157 retrievalHistory in workspace TZ) alongside the rev-153 cumulative `retrievalCount` total + `lastRetrievedAt` recency stamp. MCP hosts ranking memory by recent-activity vs all-time see both signals in one call instead of fetching the rev-157 trajectory endpoint per entry. Same workspace-TZ window the rev-157 trajectory endpoint uses so the two surfaces never drift on what 'this week' means."},{"label":"Per-memory observability cluster on v1 reaches twelve axes deep","description":"The rev-158 top-retrieved endpoint pairs with rev-157 retrieval-trajectory (per-memory axis on the trajectory dimension) and rev-153 stale (workspace axis on the staleness dimension) for the complete per-memory observability story across all three axis × dimension cells (per-memory × trajectory rev 157 / per-memory × staleness implicit via rev 153 + 156 / workspace × staleness rev 153 / workspace × trajectory rev 158). The MCP server's per-memory observability tooling now has nothing left to design across all twelve axes (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 + top-retrieved rev 158). Pure protocol-translation work for the upcoming MCP server."},{"label":"OpenAPI 3.1 typed coverage on the rev-158 endpoint + extended MemoryEntry schema — 80th unbroken cadence rev","description":"The OpenAPI 3.1 spec types the new `GET /memory/top-retrieved` endpoint with full request/response schemas (limit query param 1-20 default 5 + days query param 1-30 default 7 + response shape with `memory[]` array of typed rows including memoryId + kind enum + title + importance + pinned + tags + retrievalCount + retrievals7d + trajectory7d array + lastRetrievedAt nullable date-time). The shared `MemoryEntry` schema component picks up the new `retrievals7d` field so MCP-host code generators reading the spec see the derived field on every memory listing surface. 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 80th unbroken rev with rev 158. The OpenAPI spec changelog header gains a rev-158 block explaining the workspace-axis closure on the per-memory observability cluster and the cluster's twelve-axis depth on the protocol-bound surface."}]},{"rev":"rev 157","date":"2026-05-07","title":"Memory retrieval trajectory primitive + per-tag breakdown on the rev-155 memory-archive Slack push closes both rev-156 next-sprint candidates in one cycle (memoryEntries.retrievalHistory column + jsonb_set bump in pulse engine + getMemoryRetrievalTrajectory helper + GET /api/v1/memory/{id}/retrieval-trajectory endpoint + MemoryRetrievalSparkline dashboard component + per-tag breakdown line on memory archive warning Slack push + OpenAPI 3.1 typed coverage on the new endpoint — 79th unbroken cadence rev)","highlights":[{"label":"Per-memory retrieval trajectory — closes the *trajectory* axis on the per-memory observability cluster","description":"Closes 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)."},{"label":"Inline 7-bar retrieval sparkline beside the rev-153 retrieval-count chip on every memory row","description":"New `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."},{"label":"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 axis","description":"Closes 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'."},{"label":"OpenAPI 3.1 typed coverage on the rev-157 retrieval-trajectory endpoint — 79th unbroken cadence rev","description":"The 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."}]},{"rev":"rev 156","date":"2026-05-07","title":"Per-tag memory archive scoping closes the named rev-155 next-sprint candidate at the per-workstream axis on every channel — `?tag=` query param on `/api/v1/memory/stale` + per-tag breakdown line in the rev-155 digest section + tag filter chip row on dashboard StaleMemoryPanel + inline retrieval-count chip on every memory row — 78th unbroken cadence rev","highlights":[{"label":"`?tag=` query param on `GET /api/v1/memory/stale` — closes the named rev-155 next-sprint candidate at the protocol-bound axis","description":"Closes the named rev-155 next-sprint candidate ('per-tag memory archive scoping'). Rev 153 opened the diagnostic surface on the memory entity at the workspace axis (GET /memory/stale + StaleMemoryPanel), rev 154 closed the descriptive→defensive loop (auto-archive sweep), rev 155 closed the per-entry warning push surface — but the rev-21 memory-tag corpus was the missing fourth axis. Operators tagging memory by workstream (#q3-launch, #brand-voice, #pricing) had no way to ask 'which knowledge in *this* workstream is about to fall stale?'. New optional `?tag=` query param on `GET /api/v1/memory/stale` filters via JSONB `@>` array containment so a tag like `q3` doesn't over-match `q3-launch` (mirrors the rev-39 cross-entity tag drill-down semantics + the rev-29 focus-tag boost predicate). `getStaleMemoryEntries()` accepts an optional tag normalised lowercase + length-bounded server-side. Pure additive — undefined returns the workspace-wide list (existing rev-153 behaviour). MCP hosts on multi-workstream desks can now answer 'which #q3-launch knowledge is about to disappear?' programmatically. Mirrors the rev-49 per-recipient `?assignedToUserId=` filter on `/tasks/stale` at the per-tag axis."},{"label":"Per-tag breakdown line in the rev-155 memory archive warning digest section — closes the named rev-155 candidate at the email channel","description":"Extended `MemoryArchiveWarningEntry` with optional `tags: string[]` field; the `buildMemoryArchiveWarningSection()` helper now renders an inline 'By tag: #q3-launch (3) #brand (2)' breakdown line above the per-entry rows so operators see *which workstream's* knowledge is about to disappear at-a-glance without scrolling every per-entry row. Top 4 tags by warning count, ties broken alphabetically for deterministic ordering. Brand-purple chip palette distinguishes the breakdown from the existing brand-amber per-entry rows. Hidden when fewer than two distinct tags appear — the breakdown reads tautologically as 'everything is #foo' otherwise. Both the production cron path (`runMemoryArchiveWarnings`) and the rev-36 admin preview path (`previewMemoryArchiveWarnings`) project tags so admins iterating on configuration see the same surface they'll receive in production. Pairs naturally with the rev-156 `?tag=` v1 filter — operators read the per-tag breakdown in the digest, then drill into the matching tag via the dashboard or v1 surface."},{"label":"Tag filter chip row on dashboard StaleMemoryPanel — closes the named rev-155 candidate at the dashboard surface","description":"The rev-153 dashboard `StaleMemoryPanel` listed every stale entry workspace-wide; until rev 156 operators with multi-workstream tagged memory had to read every row to find #q3-launch ones. New tag filter chip row above the list lets operators answer 'which #q3-launch knowledge has gone stale?' in one click. Pure client-side filter on top of the existing server-rendered `entries` payload (the rev-156 v1 `?tag=` filter is the load-bearing primitive on the protocol-bound side; this UI surfaces the same scoping on the dashboard side without an extra round-trip). Each chip shows the per-tag count for at-a-glance triage. Hidden when fewer than two distinct tags appear on stale entries. New `.ld-stale-memory-tag-row` + `.ld-stale-memory-tag-chip` CSS uses the brand-purple palette matching the rev-156 digest breakdown chips so the per-tag surface reads with one consistent visual vocabulary across dashboard + email channels."},{"label":"Inline retrieval-count chip on the rev-153 memory usage pill — surfaces load-bearing memory entries at-a-glance","description":"The rev-153 `MemoryUsageChip` showed 'used Nd ago' or 'never pulled' but the per-entry retrieval count (the column rev 153 added) was only visible in the tooltip — operators reading the memory list couldn't distinguish *load-bearing* memory entries (used many times) from *drive-by* ones (used once) without hovering each row. Rev 156 closes that gap with a small inline `· N×` chip alongside the existing label, hidden when retrievalCount is 1 (the implicit majority — surfacing it would read as visual noise). Tabular-num typography keeps multi-digit values vertically aligned across rows. Cumulative micro-polish — every rev 22+ has carried at least one — and rev 156's polish is load-bearing because it makes the operator's mental model of 'which memory entries is the AI actually using' visible without expanding the rev-153 tooltip on every row. Pairs with the rev-153 stale-memory panel + rev-154 auto-archive + rev-155 warning + rev-156 per-tag scoping for the complete usage observability surface across every read horizon."}]},{"rev":"rev 155","date":"2026-05-07","title":"Memory archive warning closes the named rev-154 next-sprint candidate — per-memory pre-archive heads-up via Slack + outbound + email digest section + activity log glyph + retrieval-clears-warning + pin/raise-importance-clears-warning — 77th unbroken cadence rev","highlights":[{"label":"memoryEntries.archiveWarnedAt column + sweepMemoryArchiveWarnings helper — closes the missing edge of the rev-153/154 lifecycle at the per-entry warning axis","description":"Closes the named rev-154 next-sprint candidate ('per-memory retrieval Slack push'). New `memoryEntries.archiveWarnedAt` timestamp column + `sweepMemoryArchiveWarnings()` per-workspace helper that finds non-pinned, importance < 9 memory entries 1-2 days from rev-154 auto-archive (lastRetrievedAt within the warn window of the workspace's staleMemoryAutoArchiveDays threshold) AND haven't been warned yet (`archiveWarnedAt` is null). Mirrors the rev-50 task archive_warning sweep at the per-memory axis exactly. Stamps `archiveWarnedAt` so a second cron tick within the warning window doesn't double-fire. Capped at 25 candidates per sweep so a workspace that just enabled rev-154 auto-archive can't get warning-stormed. Companion `previewMemoryArchiveWarnings()` helper does the same predicate without stamping — used by the rev-36 admin digest preview path so admins iterating on configuration don't pollute the production cron's 'already warned' state. Closes the missing edge of the rev-153/154 lifecycle: workspace-level surface (rev 153 dashboard + per-row chip) + workspace-level closure (rev 154 auto-archive Slack push) + per-entry warning (rev 155)."},{"label":"memory.archive_warning outbound event + Slack push — workspace-shared, fan-out via runMemoryArchiveWarnings cron sweep","description":"New `OutboundEvent` value `memory.archive_warning` plus matching `dispatchMemoryArchiveWarningWebhook()` dispatcher in `src/lib/outbound.ts`. Mirrors the rev-50 `task.archive_warning` event at the per-memory axis. Workspace-shared — memory entries don't have assignees, so unlike rev-50 task warnings which fire per-task per-assignee, the rev-155 warning lists every imminent entry in one Slack block. Slack post via the new `buildMemoryArchiveWarningSlackPayload()` block with `:alarm_clock: Memory entries about to auto-archive` header + listing each entry with `auto-archives in Nd` + `Nd unused` / `never used` + kind + title + recommendation copy ('Pin entries or raise importance >= 9 to keep'). New `runMemoryArchiveWarnings()` cron sweep added to `runDailyDigest()` IMMEDIATELY BEFORE `runStaleMemoryAutoArchive()` so operators get at least one cron-cycle of heads-up before durable knowledge disappears (same shape rev 50 fires before rev 49). Pure no-op on workspaces without staleMemoryAutoArchive configured. Lets external integrations (knowledge-base mirror, FinOps dashboard, CRM tagging unused brand assets) hear the warning → action push pair (rev 155 warning + rev 154 closure) on the per-memory axis without polling."},{"label":"Per-memory archive warning section in the daily digest email + activity-log per-kind glyph + tinting","description":"New `buildMemoryArchiveWarningSection()` digest helper renders up to 6 imminent entries with `⏰ auto-archives in Nd` + kind chip + `Nd unused` / `never used` + recommendation copy in a styled HTML section. Renders alongside the rev-48 stale-tasks section as the per-memory complement of the workspace's two working-set axes (in-flight work + durable knowledge). Closes the email-channel parity gap on the rev-153/154 memory-archive lifecycle so solo founders + email-first operators who don't sit in Slack get the same heads-up Slack-first teams already have. The `runMemoryArchiveWarnings` cron sweep returns a `byWorkspace` Map so the email surface and the Slack/outbound surfaces always agree on which entries fired this cycle (no double-stamping race, no double-query). New `memory_archive_warning` activity-log kind + `KIND_LABEL` + `KIND_GLYPH` (⏰) + `.ld-activity-memory_archive_warning` brand-amber tint mirror the rev-50 task.archive_warning visual vocabulary so operators reading the activity log see warning surfaces for the two working-set axes (in-flight work + durable knowledge) with one consistent affordance."},{"label":"Pulse engine clears archiveWarnedAt on retrieval + setMemoryPinned/updateMemoryEntry clear on operator action — warning state stays in lockstep with the operator's decision","description":"Pulse engine's `workNextTask()` now also clears `archiveWarnedAt` in the same UPDATE that stamps `lastRetrievedAt` + bumps `retrievalCount` (rev 153) on every memory entry the AI cycle pulled. A re-engaged memory entry leaves the warning state immediately rather than waiting for the next cron tick. `setMemoryPinned()` clears the stamp on pin (pinned entries are exempt from rev-154 auto-archive — the rev-5 'keep forever' veto). `updateMemoryEntry()` clears the stamp when raising importance to >= 9 (also exempt — load-bearing brand-voice / decision context). The OpenAPI 3.1 spec gains a rev-155 changelog block documenting the new outbound event + the warning-state-clearing rules. 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 77th unbroken rev with rev 155. MCP-host code generators reading the spec see typed contracts for the new event immediately. The MCP server's memory-axis cluster is now nine 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) with full v1 parity across every axis."}]}]}