analytics-step2
Analytics, step 2 of the errors-and-analytics spec: counting at the edge. An account that turns analytics on gets page views, daily visitors, bytes, top pages, top referers and named events for every app, with no JavaScript and no cookie.
Spec: docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md §3.3, §3.6, §7 step 2, §8 rulings 1 and 4. Plan: docs/superpowers/plans/2026-09-07-analytics-step2-edge-counting.md. Branch cut from main 1a99060 (step 1 merged).
What lands:
- New leaf package
internal/analytics: HyperLogLog (2¹¹ registers, versioned base64), Misra–Gries top-500 summaries with_other, the vendored bot list, the per-day salt file (0600 beside the registry, atomic publish, rotation), the day-file wire shape with per-boxseqidempotent CAS merge, the in-memory meter the edge feeds (pageview rule, salted visitor hash, event-time buckets, requeue-once withdropped.flush), and the cross-box range read. - The edge observes every response for a switched-on app inside the existing observer defer: no new wrapper, nothing moves; client IP from the verified-hop chain only; Chrome prerender excluded.
- The agent resolves the switch per (account, app) on every serial-triggered pass and every five minutes, pushes a fresh map into the edge, and flushes analytics on the usage tick as a second CAS write to the unprefixed store.
- Console: Analytics tab (range today/7d/30d, headline, Go-computed SVG bars, three tables, off-state paragraph with the privacy reading),
GET /api/cli/apps/{account}/{app}/analytics(Instance, Operate), the switch on the app and account Settings pages,PUT …/telemetryacceptsanalyticsand bumps the serial. carlos analytics --app X [--range] [--set-count edge|off] [--set-door on|off]and its docs heading.
Defaults per Paul's rulings: analytics OFF until an account or app turns it on; door on; the door switch is accepted by the API and handlers but not rendered until step 3.
Review record: fresh implementer plus reviewer per task; fix rounds on Tasks 2 (atomic salt file, corrupt sketch replaced), 3 (requeue keyed per delta — the plan's design was dead under the real call order; malformed events counted), 5 (switch map copied, prerender), 8 (JSON tags), 9 (count_from, combined set flags). Sonnet and Opus hit session limits during the final tasks; Task 8's re-review was a two-file diff read by the controller, Task 9 was reviewed on Haiku. The whole-branch final review (Sonnet) returned approve-after-fixes: the restart caveat was scoped per process rather than per app; fixed in 62873a1 with a per-app test, re-reviewed clean. Gate green on that head.
Gate: go build/vet/test ./... green, gofmt clean, darwin/arm64 and windows/amd64 cross-builds clean.
Follow-up outside this repo: the getting-started skill in carlosframework/website should ask "Do you want analytics on for this account? It counts HTML page views and daily visitors at the edge — no JavaScript, no cookie, no stored IP; off by default" and run carlos analytics --app <app> --set-count edge (or the account-level switch on the Settings page) when the answer is yes.
Deferred minors (ledger): TopK's n≤min branch is a conservative variant; salt rename fallback on non-hardlink filesystems; orphaned salt temp files after a crash; the throttle test asserts nothing the throttle changes; {"analytics":{}} is 400; tab reads the whole range per view.
Discussions
- No discussions on this branch yet.
Tasks
- No tasks yet.
Activity
- No activity yet.