OSS hardening + Trends page & weekly digest - #2
Merged
Conversation
Quality hardening for the public repo: - tests/: 17-test suite via built-in node:test + tsx (no new deps, resolution matches production). Covers confidence rules, the weighted-consensus normalizer against a real throwaway SQLite DB, and seed determinism. - .github/workflows/ci.yml: gates typecheck + lint + test + build on PRs and pushes to main, across Node 20 & 22 (honors engines). - Fix: `npm run db:seed` crashed on a fresh DB with a FOREIGN KEY failure — sleep_sessions/workouts FK daily_summary(date), but children were upserted before normalizeAndUpsert created the parent rows. Insert a parent stub at the top of the day loop; the normalizer fills real values via ON CONFLICT. This restores the QUICKSTART "5-minute fresh start". - Lint: 1 error + 4 warnings -> 0 (prefer-const, unused import, inline import() type annotations). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a sixth nav surface and the weekly digest the weekly-report stub promised. Backend: - services/weekly.ts: computeWeeklySummary — trailing-7-day averages of each consensus metric (HRV, RHR, sleep) vs the prior 7 days, with direction + good/bad tone and best/shortest sleep night. Pure read + arithmetic, no AI provider needed. - GET /api/insights/weekly: computes on demand so the page renders even before the weekly cron runs. - weekly-report.ts: replace the placeholder stub with the real computation, stored as a markdown digest + structured snapshot. - shared: WeeklyMetric / WeeklySummary types. Frontend: - pages/TrendsPage.tsx at /trends: "this week vs last" digest cards (TrendIndicator) + per-metric 30-day consensus sparklines off the existing /api/vitals endpoint. Built from existing PageHeader/Sparkline/Metric so it matches DESIGN.md. - IconTrends + nav entry + route. Tests: tests/weekly.test.ts (3) — week-over-week deltas, empty-week nulls, best/shortest night. Suite now 20 tests. Verified end-to-end over HTTP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two slices of "what's next for Vitals": a quality gate the public repo was missing, and the first net-new feature.
① OSS hardening
tests/, 20 tests). Built-innode:test+ thetsxthe repo already runs on — no new dependencies, resolution matches production.confidence.test.ts— SPEC confidence rules + accuracy-weight decayconsensus.test.ts—normalizeAndUpsertagainst a real throwaway SQLite DB (single→MEDIUM, two-source weighted mean→HIGH, 0h-sleep exclusion, "missing device ≠ anomaly")seed.test.ts— proves the README's deterministic-seed claimweekly.test.ts— week-over-week digest math.github/workflows/ci.yml). Gatestypecheck + lint + test + buildon PRs + pushes tomain, Node 20 & 22.npm run db:seedcrashed on a brand-new DB (FOREIGN KEY constraint failed):sleep_sessions/workoutsFKdaily_summary(date), but the seed upserted children beforenormalizeAndUpsertmade the parent rows. Broke the QUICKSTART "5-minute fresh start". Fixed with a parent-row stub at the top of the day loop.② Consensus framing
Decision: keep it. The multi-source re-add revived it; with Fitbit + Apple it genuinely reconciles two sources. Now test-covered. No code change.
③ Trends page + weekly digest
/trends(new 6th nav tab): "this week vs last" digest cards + per-metric 30-day consensus sparklines, built from existingPageHeader/Sparkline/TrendIndicator(matches DESIGN.md).computeWeeklySummary+GET /api/insights/weekly— deterministic trailing-7d vs prior-7d averages for HRV/RHR/sleep + best/shortest night. No AI provider needed; computed on demand.weekly-report.tsstub ("Phase 3 fills this in…") with the real computation.Verification
typecheck + lint + test + buildgreen locally and in CI on Node 20 & 22. Weekly + vitals endpoints verified end-to-end over HTTP against a seeded DB (weekly: 7 days/3 metrics/best-night; vitals: 25 consensus points + delta).🤖 Generated with Claude Code