|
30 | 30 | | **v0.7.3** | Hotfix — detect GitHub organizations + helpful 422 (was: silent 500 on `apache`, `microsoft`, etc.) | ✅ shipped | |
31 | 31 | | **v0.7.4** | Hotfix — badge evidence reachable on mobile (Tooltip → Popover with hover + tap) | ✅ shipped | |
32 | 32 | | **v0.7.5** | Hotfix — Roast/Mentor toggle symmetric on mobile (flex-1 split 50/50) | ✅ shipped | |
33 | | -| **v0.8.0** | Polish + observability — Sentry, analytics, cron re-ingestion, manual "Force refresh" | pending | |
34 | | -| **v0.9.0** | Beta hardening — security review, abuse mitigation, load test | pending | |
| 33 | +| **v0.8.0** | Polish + observability — Sentry (FE+BE), PostHog (events + web-vitals), structured logging, axe a11y pass, on-voice 404/500, error-budget doc | ✅ shipped | |
| 34 | +| **v0.8.1** | Cron daily re-ingestion of saved analyses (paired with Sentry so failures aren't silent) | deferred from v0.8.0 | |
| 35 | +| **v0.8.2** | Manual "Force refresh" on `/me` + `DELETE /me/cache/{username}` (Layer A invalidation) | deferred from v0.8.0 | |
| 36 | +| **v0.8.3** | On-demand `revalidateTag` for `/share/[slug]` ISR (closes v0.7.1's deferred share-page caching) | deferred from v0.7.1 | |
| 37 | +| **v0.8.4** | `vercel.json` → `vercel.ts` migration (Vercel 2026-02-27 knowledge update) | deferred from pre-v0.7.1 | |
| 38 | +| **v0.9.0** | Beta hardening — security review, abuse mitigation, load test, legal | pending | |
35 | 39 | | **v1.0.0** | Public launch | pending | |
36 | 40 |
|
37 | 41 | --- |
|
296 | 300 |
|
297 | 301 | ## v0.8.0 — Polish + observability |
298 | 302 |
|
299 | | -**Goal:** The product feels finished. We can see what users do and what breaks. |
| 303 | +**Goal:** By the end of this slice we can answer three questions in production: what broke (Sentry), what did users actually do (PostHog + web vitals), and is the page accessible (axe = 0 critical). Nothing else. |
300 | 304 |
|
301 | | -**Slice scope:** |
302 | | -- Sentry (frontend + backend) |
303 | | -- PostHog or Plausible analytics |
304 | | -- Structured logging on every backend route |
305 | | -- 404 / 500 / rate-limit pages with on-voice copy |
306 | | -- Accessibility audit (axe): zero criticals |
307 | | -- Empty states and skeleton loaders everywhere |
308 | | -- **Cron re-ingestion** for saved analyses (daily refresh) — paired with Sentry so cron failures aren't silent |
309 | | -- **Manual "Force refresh"** button on `/me` and `DELETE /me/cache/{username}` backend route — invalidates the Layer A Report cache from v0.7.0 |
| 305 | +**Design spec:** [`docs/superpowers/specs/2026-05-22-v0.8.0-polish-observability-design.md`](./docs/superpowers/specs/2026-05-22-v0.8.0-polish-observability-design.md). |
| 306 | + |
| 307 | +**Slice scope (locked 2026-05-22):** |
| 308 | +- **Backend observability** — `structlog` JSON logging + request-ID middleware + Sentry FE/BE init with PII scrub hook. |
| 309 | +- **Frontend observability** — Sentry browser SDK via `instrumentation.ts`; PostHog browser SDK with auto-pageviews + web-vitals capture (RUM, replaces the deferred Speed Insights idea — free-free 12-month retention vs Speed Insights' 30-day Hobby cap). |
| 310 | +- **Named PostHog events** — `analyze_submitted`, `share_toggled`, `share_card_copied`, `mode_toggled`, `sign_in_clicked`. |
| 311 | +- **On-voice failure pages** — new `app/not-found.tsx`; refresh `app/error.tsx` copy + add `Sentry.captureException` hook. |
| 312 | +- **Empty-state + skeleton audit** — verify `/me`, `/u/[username]/card`, `/share/[slug]` already have appropriate states (most do post-v0.7.2). |
| 313 | +- **Accessibility pass** — `@axe-core/cli` against `/`, `/u/octocat`, `/u/octocat/card`, `/me`, `/share/<slug>`; fix all criticals. |
| 314 | +- **Error budget doc** — `docs/OBSERVABILITY.md` defining critical-vs-acceptable classes + alert intent (rules wired later in a v0.8.x patch). |
| 315 | + |
| 316 | +**Deferred to v0.8.x patches:** |
| 317 | +- Cron daily re-ingestion → v0.8.1 |
| 318 | +- Manual "Force refresh" + `DELETE /me/cache/{username}` → v0.8.2 |
| 319 | +- On-demand `revalidateTag` for `/share/[slug]` ISR → v0.8.3 |
| 320 | +- `vercel.json` → `vercel.ts` migration → v0.8.4 |
| 321 | +- Sentry alert-rule wiring → v0.8.x once real error rates are known |
| 322 | +- CI integration of `@axe-core/cli` → v0.8.x |
| 323 | + |
| 324 | +Each deferred item is independent and earns its own patch release, matching the v0.7.x cadence. |
310 | 325 |
|
311 | 326 | **Exit criteria:** |
312 | | -- [ ] Error budget defined; dashboards live |
313 | | -- [ ] Axe critical issues = 0 |
314 | | -- [ ] `CHANGELOG.md` + `docs/PROGRESS_LOG.md` updated; version `0.8.0` |
| 327 | +- [x] Backend Sentry catches a deliberate test exception with `request_id` tag attached; no PII in the event body. |
| 328 | +- [x] Frontend Sentry catches a deliberate client throw with source-mapped stack. |
| 329 | +- [x] PostHog dashboard shows all 5 named events flowing from prod within 24h of deploy. |
| 330 | +- [x] PostHog web-vitals capture identifies the prod LCP element on `/u/[username]` (closes v0.7.2's open gap). |
| 331 | +- [x] `npx @axe-core/cli` returns zero critical issues on all 5 audited routes. |
| 332 | +- [x] `docs/OBSERVABILITY.md` exists; defines critical vs acceptable error classes + alert intent. |
| 333 | +- [x] PII contract (spec §6) verified by test for every listed field. |
| 334 | +- [x] `CHANGELOG.md` + `docs/PROGRESS_LOG.md` updated; version `0.8.0` tagged + released. |
| 335 | + |
| 336 | +--- |
| 337 | + |
| 338 | +## v0.8.1 — Cron daily re-ingestion (deferred from v0.8.0) |
| 339 | + |
| 340 | +**Goal:** Saved analyses refresh themselves overnight so a user who comes back tomorrow doesn't see stale data. Failures are visible because v0.8.0's Sentry is already in place. |
| 341 | + |
| 342 | +**Slice scope:** |
| 343 | +- Vercel Cron entry (likely `vercel.json` for now; folds into v0.8.4's `vercel.ts` migration later) hitting a new authenticated backend route `POST /cron/refresh-saved-analyses`. |
| 344 | +- Chunking: respect Vercel function timeout (300s) by processing N analyses per invocation; resume tokens persisted in Postgres if the queue is larger than one chunk. |
| 345 | +- Sentry breadcrumb / structured log for every refresh attempt; one Sentry capture per chunk failure. |
| 346 | + |
| 347 | +**Exit criteria:** TBD when the slice begins. |
| 348 | + |
| 349 | +--- |
| 350 | + |
| 351 | +## v0.8.2 — Manual "Force refresh" (deferred from v0.8.0) |
| 352 | + |
| 353 | +**Goal:** Signed-in users can invalidate the Layer A Report cache for any of their saved analyses from `/me`. |
| 354 | + |
| 355 | +**Slice scope:** |
| 356 | +- Backend: `DELETE /me/cache/{username}` route — auth-required, deletes the `report:` key from Upstash. Logs the action. |
| 357 | +- Frontend: small "Force refresh" affordance on each `/me` grid item; tracked via PostHog `force_refresh_clicked`. |
| 358 | + |
| 359 | +**Exit criteria:** TBD when the slice begins. |
| 360 | + |
| 361 | +--- |
| 362 | + |
| 363 | +## v0.8.3 — On-demand `revalidateTag` for `/share/[slug]` ISR (deferred from v0.7.1) |
| 364 | + |
| 365 | +**Goal:** Public share pages can be ISR-cached safely because revocation immediately busts the tag. |
| 366 | + |
| 367 | +**Slice scope:** |
| 368 | +- `/share/[slug]` route gets `unstable_cache` (or Next 16 Cache Components equivalent) with a per-slug tag. |
| 369 | +- Backend share-toggle endpoints (`POST` + `DELETE`) call a small frontend webhook (`POST /api/revalidate?tag=share:<slug>`) authenticated with a shared secret. |
| 370 | +- Both sides covered by tests including the "revoked slug renders 404 immediately" assertion. |
| 371 | + |
| 372 | +**Exit criteria:** TBD when the slice begins. |
| 373 | + |
| 374 | +--- |
| 375 | + |
| 376 | +## v0.8.4 — `vercel.json` → `vercel.ts` migration |
| 377 | + |
| 378 | +**Goal:** Track the 2026-02-27 Vercel knowledge update by moving the project config to typed TypeScript. |
| 379 | + |
| 380 | +**Slice scope:** |
| 381 | +- Replace `vercel.json` with `vercel.ts` using `@vercel/config/v1`. |
| 382 | +- Move the `experimentalServices` declarations + any cron entries shipped in v0.8.1 to the typed config. |
| 383 | + |
| 384 | +**Exit criteria:** TBD when the slice begins. |
315 | 385 |
|
316 | 386 | --- |
317 | 387 |
|
|
0 commit comments