Skip to content

[DQ-02] Add epistemic status labels - #2405

Merged
Asherlc merged 6 commits into
mainfrom
codex/issue-2075
Aug 2, 2026
Merged

Asherlc merged 6 commits into
mainfrom
codex/issue-2075

Conversation

@Asherlc

@Asherlc Asherlc commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary\n- add a shared epistemic-status contract for observed, estimated, and inferred values\n- expose the server-authored status on web and mobile health surfaces\n- add contract and platform regression coverage\n\nCloses #2075

Summary by Sourcery

Introduce a shared epistemic-status vocabulary and propagate server-authored status labels across analytics contracts and UI surfaces for sleep need, weight, correlations, and today plan.

New Features:

  • Add a shared epistemic-status module in the scoring package and a corresponding server contract schema for observed, estimated, associated, suggested, and unavailable states.
  • Attach epistemicStatus fields to sleep-need, correlation, today-plan, and smoothed-weight results in server outputs and API schemas, and surface these labels in web and mobile UI components.

Enhancements:

  • Update web and mobile health, recovery, dashboard, and correlation views to display epistemic status labels alongside key metrics such as trend weight, sleep need, correlations, and today plan actions.

Tests:

  • Extend server, scoring, web, and mobile test suites and stories to cover epistemic-status vocabulary, contract validation, and the new status propagation for analytics results.

Summary by cubic

Adds a shared epistemic status system and surfaces it across server, web, and mobile so users can see if values are Observed, Estimated, Associated, Suggested, or Unavailable. Aligns with DQ-02 (#2075) and versions caches to avoid stale data.

  • New Features

    • Added @dofek/scoring/epistemic-status with kinds, labels, and getEpistemicStatus.
    • Introduced server epistemic-status Zod contract and wired it into Sleep Need V2, Today Plan, Correlation (v1/v2), and Body Analytics.
    • Sleep Need: Estimated when available; Unavailable when insufficient/missing.
    • Today Plan: Suggested when ready; Unavailable when insufficient.
    • Correlation: Associated when available; Unavailable when insufficient.
    • Body weight rows now include rawWeightStatus (Observed or null if interpolated) and smoothedWeightStatus (Estimated).
    • Web/mobile UIs show labels in SleepNeedCard, TodayPlanCard, SmoothedWeightChart (Estimated Trend Weight; Observed scale), Recovery, and Correlation.
  • Bug Fixes

    • Mobile tolerates legacy cached data without epistemicStatus (Today sleep need, Recovery weight, TodayPlanCard, Correlation).
    • Cache versions updated to invalidate old contracts: mobile query cache MOBILE_QUERY_CACHE_CONTRACT_VERSION = 7; API cache keys sleep-need-metadata-v2, today-plan-evidence-v2, correlation.compute:v2, correlation.computeV2:v2, health-status-evidence-v4.

Written for commit e042bab. Summary will update on new commits.

Review in cubic

Copilot AI review requested due to automatic review settings August 2, 2026 12:03
@Asherlc Asherlc linked an issue Aug 2, 2026 that may be closed by this pull request
@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@codereviewbot-ai

codereviewbot-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown

PR Review Summary

This PR successfully introduces standard epistemic status metadata across domain scoring, server contract schemas, and mobile UI rendering.

Highlights

  1. Domain & Contract Typing (packages/scoring & packages/server): Solid implementation of the shared epistemic status vocabulary (observed, estimated, associated, suggested, unavailable) and corresponding Zod schemas with strict kind-label alignment tests.
  2. Test & Storybook Coverage: Comprehensive updates across contract tests, scoring unit tests, screen/component unit tests, and Storybook stories.

Key Recommendation

  • Defensive UI Rendering on Mobile: In index.tsx, recovery.tsx, correlation.tsx, and TodayPlanCard.tsx, directly accessing .epistemicStatus.label or .smoothedWeightStatus.label can throw a TypeError if a user has cached query data stored locally from prior versions. Using optional chaining (?.label) ensures smooth backward compatibility and avoids runtime crashes. Inline comments with suggestions have been added.

🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Asherlc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6c078390-f241-430e-ab0f-c5136c04d5bc

📥 Commits

Reviewing files that changed from the base of the PR and between 766114d and e042bab.

📒 Files selected for processing (59)
  • packages/mobile/app/(tabs)/index.stories.tsx
  • packages/mobile/app/(tabs)/index.test.tsx
  • packages/mobile/app/(tabs)/index.tsx
  • packages/mobile/app/(tabs)/recovery.stories.tsx
  • packages/mobile/app/(tabs)/recovery.test.tsx
  • packages/mobile/app/(tabs)/recovery.tsx
  • packages/mobile/app/correlation.stories.tsx
  • packages/mobile/app/correlation.test.tsx
  • packages/mobile/app/correlation.tsx
  • packages/mobile/components/TodayPlanCard.stories.tsx
  • packages/mobile/components/TodayPlanCard.test.tsx
  • packages/mobile/components/TodayPlanCard.tsx
  • packages/mobile/lib/mobile-query-persistence.test.tsx
  • packages/mobile/lib/mobile-query-persistence.ts
  • packages/scoring/README.md
  • packages/scoring/package.json
  • packages/scoring/src/epistemic-status.test.ts
  • packages/scoring/src/epistemic-status.ts
  • packages/scoring/src/today-plan.test.ts
  • packages/scoring/src/today-plan.ts
  • packages/server/src/contracts/epistemic-status-contract.test.ts
  • packages/server/src/contracts/epistemic-status-contract.ts
  • packages/server/src/contracts/mobile-dashboard-contracts.test.ts
  • packages/server/src/contracts/mobile-dashboard-contracts.ts
  • packages/server/src/contracts/sleep-need-contract.test.ts
  • packages/server/src/contracts/sleep-need-contract.ts
  • packages/server/src/repositories/body-analytics-repository.test.ts
  • packages/server/src/repositories/body-analytics-repository.ts
  • packages/server/src/repositories/correlation-repository.ts
  • packages/server/src/routers/body-analytics.test.ts
  • packages/server/src/routers/body-analytics.ts
  • packages/server/src/routers/correlation.test.ts
  • packages/server/src/routers/correlation.ts
  • packages/server/src/routers/mobile-dashboard.test.ts
  • packages/server/src/routers/mobile-dashboard.ts
  • packages/server/src/routers/sleep-need.integration.test.ts
  • packages/server/src/routers/sleep-need.test.ts
  • packages/server/src/routers/sleep-need.ts
  • packages/server/src/routers/today-plan.test.ts
  • packages/server/src/routers/today-plan.ts
  • packages/server/src/services/dashboard-overview.test.ts
  • packages/server/src/services/health-status.ts
  • packages/server/src/services/mobile-recovery-tab.test.ts
  • packages/web/src/components/SleepNeedCard.stories.tsx
  • packages/web/src/components/SleepNeedCard.test.tsx
  • packages/web/src/components/SleepNeedCard.tsx
  • packages/web/src/components/SleepOverviewCards.stories.tsx
  • packages/web/src/components/SleepOverviewCards.test.tsx
  • packages/web/src/components/SmoothedWeightChart.stories.tsx
  • packages/web/src/components/SmoothedWeightChart.test.tsx
  • packages/web/src/components/SmoothedWeightChart.tsx
  • packages/web/src/components/TodayPlanCard.stories.tsx
  • packages/web/src/components/TodayPlanCard.test.tsx
  • packages/web/src/components/TodayPlanCard.tsx
  • packages/web/src/pages/BodyPage.test.tsx
  • packages/web/src/pages/CorrelationExplorerPage.stories.tsx
  • packages/web/src/pages/CorrelationExplorerPage.test.tsx
  • packages/web/src/pages/CorrelationExplorerPage.tsx
  • packages/web/src/pages/Dashboard.test.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Introduces a shared epistemic status vocabulary (Observed / Estimated / Associated / Suggested / Unavailable), wires it through key scoring and server contracts, exposes it on web and mobile surfaces for weight, sleep need, today plan, and correlation, and adds schema plus regression coverage to enforce canonical labels end-to-end.

File-Level Changes

Change Details Files
Add a shared epistemic status vocabulary and helper API in the scoring package, with contract validation on the server.
  • Create EpistemicStatus types, canonical status constants, and a getEpistemicStatus helper in scoring.
  • Add unit tests verifying the vocabulary, labels, and helper behavior.
  • Define a server-side epistemic-status zod contract that only accepts canonical kind/label pairs and rejects mismatches.
  • Add tests ensuring the contract accepts all shared statuses and rejects invalid label/kind combinations.
  • Expose the new epistemic-status module in scoring’s package exports and document it in the README.
packages/scoring/src/epistemic-status.ts
packages/scoring/src/epistemic-status.test.ts
packages/scoring/package.json
packages/scoring/README.md
packages/server/src/contracts/epistemic-status-contract.ts
packages/server/src/contracts/epistemic-status-contract.test.ts
Propagate epistemic status through sleep need computation, contracts, routers, and UI on web and mobile.
  • Extend sleepNeedV2 schemas to include epistemicStatus for all availability variants using the shared contract schema.
  • Set epistemicStatus in toSleepNeedV2 based on computation state (unavailable for missing/insufficient, estimated for available).
  • Update server services and routers (dashboard overview, sleep-need, mobile dashboard, mobile dashboard contracts) to include epistemicStatus in returned sleepNeed data.
  • Update web SleepNeedCard and SleepOverviewCards to display epistemicStatus labels for both available and unavailable states.
  • Update mobile TodayScreen sleep-need sections to render epistemicStatus labels in available, missing, and insufficient-data cases.
  • Adjust tests and stories across server, web, and mobile to expect epistemicStatus objects and new copy (e.g., “Estimated sleep need tonight”, “Unavailable”).
packages/server/src/contracts/sleep-need-contract.ts
packages/server/src/contracts/sleep-need-contract.test.ts
packages/server/src/services/dashboard-overview.test.ts
packages/server/src/routers/sleep-need.test.ts
packages/server/src/services/mobile-recovery-tab.test.ts
packages/server/src/contracts/mobile-dashboard-contracts.ts
packages/server/src/contracts/mobile-dashboard-contracts.test.ts
packages/server/src/routers/mobile-dashboard.test.ts
packages/web/src/components/SleepNeedCard.tsx
packages/web/src/components/SleepNeedCard.test.tsx
packages/web/src/components/SleepNeedCard.stories.tsx
packages/web/src/components/SleepOverviewCards.tsx
packages/web/src/components/SleepOverviewCards.test.tsx
packages/web/src/components/SleepOverviewCards.stories.tsx
packages/mobile/app/(tabs)/index.tsx
packages/mobile/app/(tabs)/index.test.tsx
packages/mobile/app/(tabs)/index.stories.tsx
Attach epistemic status to smoothed body weight data and surface it on web and mobile charts.
  • Extend SmoothedWeightRow and related output schemas to carry rawWeightStatus (nullable) and smoothedWeightStatus using the EpistemicStatus type/contract.
  • Populate rawWeightStatus as observed for actual measurements and null for interpolated days; set smoothedWeightStatus as estimated for all smoothed values in BodyAnalyticsRepository.
  • Update SmoothedWeightChart (web) to read smoothedWeightStatus/rawWeightStatus, change headings to “Estimated Trend Weight”, and render latest scale line as “Observed: …” only when both weight and status exist.
  • Update mobile RecoveryScreen weight card to render smoothedWeightStatus label and rawWeightStatus-labeled scale value.
  • Adjust tests, stories, and body page fixtures to include and assert the new status fields and updated text expectations.
packages/server/src/repositories/body-analytics-repository.ts
packages/server/src/repositories/body-analytics-repository.test.ts
packages/server/src/routers/body-analytics.ts
packages/server/src/contracts/mobile-dashboard-contracts.ts
packages/server/src/contracts/mobile-dashboard-contracts.test.ts
packages/web/src/components/SmoothedWeightChart.tsx
packages/web/src/components/SmoothedWeightChart.test.tsx
packages/web/src/components/SmoothedWeightChart.stories.tsx
packages/web/src/pages/BodyPage.test.tsx
packages/mobile/app/(tabs)/recovery.tsx
packages/mobile/app/(tabs)/recovery.test.tsx
packages/mobile/app/(tabs)/recovery.stories.tsx
Add epistemic status to correlation analysis results and present it in web and mobile correlation UIs.
  • Update correlation repository outputs (v1 and v2) to include epistemicStatus using getEpistemicStatus, with unavailable for insufficient data and associated for available analyses.
  • Extend correlation router schemas (base shape and v2) to require epistemicStatus via the shared contract schema.
  • Update web CorrelationExplorerPage and mobile CorrelationScreen to display data.epistemicStatus.label in their evidence/stat sections.
  • Modify correlation tests and stories on both platforms to set and assert epistemicStatus values (e.g., Unavailable, Associated) and ensure schemas validate repository output.
packages/server/src/repositories/correlation-repository.ts
packages/server/src/routers/correlation.ts
packages/server/src/routers/correlation.test.ts
packages/mobile/app/correlation.tsx
packages/mobile/app/correlation.test.tsx
packages/mobile/app/correlation.stories.tsx
packages/web/src/pages/CorrelationExplorerPage.tsx
packages/web/src/pages/CorrelationExplorerPage.test.tsx
packages/web/src/pages/CorrelationExplorerPage.stories.tsx
Add epistemic status to Today Plan results and render it in web and mobile cards.
  • Extend TodayPlanResult type to include epistemicStatus for both ready and insufficient_data variants, using the shared EpistemicStatus type.
  • Set epistemicStatus in buildTodayPlan based on data availability (unavailable when strainTarget missing, suggested when ready).
  • Update server today-plan router schema to require epistemicStatus in all variants.
  • Render epistemicStatus.label in TodayPlanCard components for web and mobile in both ready and insufficient_data states.
  • Update dashboard and TodayScreen tests to include epistemicStatus in mocked TodayPlan data and assert “Suggested” / “Unavailable” labels in cards.
  • Adjust TodayPlanCard tests and stories for web and mobile to include epistemicStatus in fixtures and validate display.
packages/scoring/src/today-plan.ts
packages/scoring/src/today-plan.test.ts
packages/server/src/routers/today-plan.ts
packages/web/src/components/TodayPlanCard.tsx
packages/web/src/components/TodayPlanCard.test.tsx
packages/web/src/components/TodayPlanCard.stories.tsx
packages/web/src/pages/Dashboard.test.tsx
packages/mobile/components/TodayPlanCard.tsx
packages/mobile/components/TodayPlanCard.test.tsx
packages/mobile/components/TodayPlanCard.stories.tsx
packages/mobile/app/(tabs)/index.test.tsx

Assessment against linked issues

Issue Objective Addressed Explanation
#2075 Introduce a shared epistemic status vocabulary and contract (Observed / Estimated / Associated / Suggested / Unavailable) and plumb it through server-side types and APIs.
#2075 Apply the epistemic status labels to relevant web and mobile UI surfaces so that observed, estimated, associated, suggested, and unavailable values are visually and textually distinguished.
#2075 Add tests and documentation to ensure the epistemic status vocabulary is consistently enforced and correctly displayed across the system.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add shared epistemic status labels across server contracts and health UI

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Introduce a shared epistemic-status vocabulary and contract-validated schema.
• Propagate epistemicStatus through sleep need, today plan, correlations, and weight outputs.
• Surface status labels in web/mobile UI and expand regression tests/stories.
Diagram

graph TD
  Scoring["scoring: epistemic-status"] --> Contracts["server: epistemicStatusSchema"] --> Logic["server: analytics logic"] --> Routers["tRPC routers"] --> Web["web UI"] & Mobile["mobile UI"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Send only `kind`, map labels on clients
  • ➕ Smaller payloads and fewer schema updates when changing label text
  • ➕ UI can localize labels independently per platform
  • ➖ Risk of label drift across web/mobile and over time
  • ➖ Harder to enforce canonical wording in contracts/tests
  • ➖ Requires every client to keep a mapping in sync with server semantics
2. Derive label mechanically (e.g., `capitalize(kind)`) and validate only `kind`
  • ➕ Avoids duplicating label in payload while keeping deterministic display text
  • ➕ Simplifies contract schema
  • ➖ Locks formatting to a simplistic rule (breaks for future non-trivial labels)
  • ➖ Still pushes presentation decisions into clients if formatting differs

Recommendation: Keep the PR’s approach (server-authored {kind,label} validated via a discriminated-union schema). It guarantees a single canonical vocabulary across server and clients, and the contract tests make any drift explicit. The minor payload overhead is justified by consistency across multiple surfaces.

Files changed (51) +315 / -10

Enhancement (18) +132 / -7
index.tsxRender sleepNeed epistemic status label on Today screen +3/-0

Render sleepNeed epistemic status label on Today screen

• Displays 'sleepNeed.epistemicStatus.label' in the missing/available/insufficient UI states. Makes the provenance/confidence of sleep need visible to users.

packages/mobile/app/(tabs)/index.tsx

recovery.tsxShow trend and scale epistemic labels in Recovery weight card +4/-2

Show trend and scale epistemic labels in Recovery weight card

• Renders 'smoothedWeightStatus.label' for trend weight and prefixes the scale weight with 'rawWeightStatus.label' when present. Avoids showing the scale line unless both value and status exist.

packages/mobile/app/(tabs)/recovery.tsx

correlation.tsxDisplay correlation epistemic status label in the evidence card +1/-0

Display correlation epistemic status label in the evidence card

• Renders 'data.epistemicStatus.label' near the correlation evidence header. Exposes whether results are associated vs unavailable.

packages/mobile/app/correlation.tsx

TodayPlanCard.tsxRender epistemicStatus label in TodayPlanCard meta section +2/-0

Render epistemicStatus label in TodayPlanCard meta section

• Displays 'plan.epistemicStatus.label' in both ready and insufficient plan layouts. Ensures status is visible alongside confidence/freshness metadata.

packages/mobile/components/TodayPlanCard.tsx

epistemic-status.tsIntroduce shared EpistemicStatus kinds, types, and lookup helper +27/-0

Introduce shared EpistemicStatus kinds, types, and lookup helper

• Defines the canonical kinds (observed/estimated/associated/suggested/unavailable) and their labels. Exposes 'getEpistemicStatus' for server-authored, type-safe status descriptors.

packages/scoring/src/epistemic-status.ts

today-plan.tsAdd epistemicStatus to TodayPlanResult and set values in builder +6/-0

Add epistemicStatus to TodayPlanResult and set values in builder

• Adds 'epistemicStatus' to both today plan result variants and populates it via 'getEpistemicStatus'. Encodes suggested vs unavailable at the source of truth for the result.

packages/scoring/src/today-plan.ts

epistemic-status-contract.tsAdd Zod discriminated-union schema for epistemicStatus +37/-0

Add Zod discriminated-union schema for epistemicStatus

• Defines a strict Zod 'discriminatedUnion' keyed by 'kind' with label literals sourced from scoring. Ensures server contracts enforce canonical presentation labels.

packages/server/src/contracts/epistemic-status-contract.ts

mobile-dashboard-contracts.tsAdd weight epistemic status fields to mobile recovery output schema +3/-0

Add weight epistemic status fields to mobile recovery output schema

• Imports and applies 'epistemicStatusSchema' to 'rawWeightStatus' (nullable) and 'smoothedWeightStatus' (required). Tightens API guarantees for weight provenance in mobile recovery outputs.

packages/server/src/contracts/mobile-dashboard-contracts.ts

sleep-need-contract.tsAdd epistemicStatus to sleep need contract schema and conversions +10/-0

Add epistemicStatus to sleep need contract schema and conversions

• Extends all V2 sleep need variants to include 'epistemicStatus' and populates it via 'getEpistemicStatus'. Ensures contract validation and output semantics match across availability states.

packages/server/src/contracts/sleep-need-contract.ts

body-analytics-repository.tsAttach epistemic statuses to smoothed weight rows +7/-0

Attach epistemic statuses to smoothed weight rows

• Extends 'SmoothedWeightRow' with 'rawWeightStatus' and 'smoothedWeightStatus'. Populates observed status for non-interpolated raw measurements and estimated status for trend values.

packages/server/src/repositories/body-analytics-repository.ts

correlation-repository.tsAttach epistemicStatus to correlation results +5/-0

Attach epistemicStatus to correlation results

• Adds 'epistemicStatus' to correlation outputs for both V1 and V2 computations. Marks insufficient results as unavailable and available results as associated.

packages/server/src/repositories/correlation-repository.ts

body-analytics.tsExtend smoothed weight router schema with epistemic status fields +3/-0

Extend smoothed weight router schema with epistemic status fields

• Adds 'rawWeightStatus' (nullable) and 'smoothedWeightStatus' (required) to the router output schema. Enforces contract validation at the API boundary.

packages/server/src/routers/body-analytics.ts

correlation.tsRequire epistemicStatus in correlation API schemas +3/-0

Require epistemicStatus in correlation API schemas

• Imports 'epistemicStatusSchema' and adds it to base shapes for correlation outputs (including V2). Makes 'epistemicStatus' a first-class, validated part of the API contract.

packages/server/src/routers/correlation.ts

today-plan.tsRequire epistemicStatus in today-plan API schema +3/-0

Require epistemicStatus in today-plan API schema

• Adds 'epistemicStatus' to both branches of the today plan discriminated union. Ensures today plan responses always include a validated status label.

packages/server/src/routers/today-plan.ts

SleepNeedCard.tsxDisplay epistemicStatus label in SleepNeedCard headings and missing state +4/-1

Display epistemicStatus label in SleepNeedCard headings and missing state

• Shows the status label in the unavailable card and uses it to prefix the 'sleep need tonight' heading in the available state. Aligns copy with server-authored epistemic labeling.

packages/web/src/components/SleepNeedCard.tsx

SmoothedWeightChart.tsxUse epistemic status labels for Trend Weight and Scale display +11/-4

Use epistemic status labels for Trend Weight and Scale display

• Tracks the latest non-null raw weight status label and uses it to prefix the scale line. Updates the header to include 'smoothedWeightStatus.label' for the trend value.

packages/web/src/components/SmoothedWeightChart.tsx

TodayPlanCard.tsxRender today plan epistemicStatus label in web TodayPlanCard +2/-0

Render today plan epistemicStatus label in web TodayPlanCard

• Displays 'plan.epistemicStatus.label' alongside confidence/freshness metadata in both ready and insufficient layouts. Makes server-authored status visible in the dashboard card.

packages/web/src/components/TodayPlanCard.tsx

CorrelationExplorerPage.tsxDisplay correlation epistemicStatus label in the evidence section +1/-0

Display correlation epistemicStatus label in the evidence section

• Renders 'data.epistemicStatus.label' near the 'Correlation Evidence' header. Makes the epistemic framing visible without changing the underlying statistics display.

packages/web/src/pages/CorrelationExplorerPage.tsx

Tests (31) +177 / -3
index.stories.tsxSeed Today tab story data with sleepNeed/todayPlan epistemicStatus +3/-0

Seed Today tab story data with sleepNeed/todayPlan epistemicStatus

• Updates seeded story fixtures to include 'epistemicStatus' on sleep need (available/unavailable) and today plan (suggested). Ensures Storybook data matches the updated API contract.

packages/mobile/app/(tabs)/index.stories.tsx

index.test.tsxUpdate Today screen tests for epistemicStatus fields +4/-0

Update Today screen tests for epistemicStatus fields

• Adds 'epistemicStatus' to mocked today plan and sleep need results across multiple availability scenarios. Keeps UI tests aligned with new contract requirements.

packages/mobile/app/(tabs)/index.test.tsx

recovery.stories.tsxAdd weight status labels to Recovery tab story fixtures +2/-0

Add weight status labels to Recovery tab story fixtures

• Extends weight rows to include 'rawWeightStatus' (observed) and 'smoothedWeightStatus' (estimated). Aligns story data with the updated weight contract.

packages/mobile/app/(tabs)/recovery.stories.tsx

recovery.test.tsxAdjust Recovery screen tests for weight status labels +8/-1

Adjust Recovery screen tests for weight status labels

• Updates mocked weight data to carry raw/smoothed status fields. Changes assertions to expect the new status-prefixed scale weight and the trend status label.

packages/mobile/app/(tabs)/recovery.test.tsx

correlation.stories.tsxAdd epistemicStatus to correlation story data +2/-0

Add epistemicStatus to correlation story data

• Adds 'epistemicStatus' to available (associated) and insufficient (unavailable) correlation fixtures. Keeps stories consistent with the new API shape.

packages/mobile/app/correlation.stories.tsx

correlation.test.tsxUpdate correlation screen tests to cover epistemicStatus labels +6/-0

Update correlation screen tests to cover epistemicStatus labels

• Adds 'epistemicStatus' to correlation test state and asserts the label is rendered for both available and insufficient cases. Ensures UI displays the server-provided status.

packages/mobile/app/correlation.test.tsx

TodayPlanCard.stories.tsxAdd epistemicStatus to TodayPlanCard story fixtures +2/-0

Add epistemicStatus to TodayPlanCard story fixtures

• Updates ready and insufficient today plan story data to include suggested/unavailable status labels. Aligns story fixtures with updated today plan contract.

packages/mobile/components/TodayPlanCard.stories.tsx

TodayPlanCard.test.tsxAssert TodayPlanCard renders epistemicStatus labels +4/-0

Assert TodayPlanCard renders epistemicStatus labels

• Adds 'epistemicStatus' to plan fixtures and checks that Suggested/Unavailable labels appear in ready/insufficient states. Strengthens regression coverage for the new display element.

packages/mobile/components/TodayPlanCard.test.tsx

epistemic-status.test.tsAdd unit tests for shared epistemic status vocabulary +28/-0

Add unit tests for shared epistemic status vocabulary

• Verifies the full set of kinds and exact display labels, and validates 'getEpistemicStatus' behavior. Locks the shared vocabulary contract in scoring.

packages/scoring/src/epistemic-status.test.ts

today-plan.test.tsUpdate today-plan scoring tests to include epistemicStatus +2/-0

Update today-plan scoring tests to include epistemicStatus

• Extends expected TodayPlanResult shapes to include unavailable/suggested statuses for insufficient/ready outcomes. Ensures scoring result types match new contract fields.

packages/scoring/src/today-plan.test.ts

epistemic-status-contract.test.tsAdd server contract tests for epistemicStatus schema +17/-0

Add server contract tests for epistemicStatus schema

• Validates that every shared scoring status is accepted with canonical labels. Adds a negative test to reject mismatched kind/label combinations.

packages/server/src/contracts/epistemic-status-contract.test.ts

mobile-dashboard-contracts.test.tsUpdate mobile dashboard contract fixtures for weight statuses +2/-0

Update mobile dashboard contract fixtures for weight statuses

• Extends the valid recovery fixture with 'rawWeightStatus' and 'smoothedWeightStatus'. Keeps contract tests passing with new required fields.

packages/server/src/contracts/mobile-dashboard-contracts.test.ts

sleep-need-contract.test.tsUpdate sleep need contract tests for epistemicStatus +5/-0

Update sleep need contract tests for epistemicStatus

• Adds expected 'epistemicStatus' values to available and unavailable sleep need cases and schema parse tests. Confirms server emits estimated vs unavailable consistently across scenarios.

packages/server/src/contracts/sleep-need-contract.test.ts

body-analytics-repository.test.tsAssert repository outputs include raw/smoothed weight epistemic statuses +10/-0

Assert repository outputs include raw/smoothed weight epistemic statuses

• Adds expectations for observed raw weight and estimated smoothed weight statuses, including interpolated-day behavior (raw status null). Strengthens correctness of server-authored status propagation.

packages/server/src/repositories/body-analytics-repository.test.ts

correlation.test.tsUpdate correlation router tests to include epistemicStatus in outputs +2/-0

Update correlation router tests to include epistemicStatus in outputs

• Adds 'epistemicStatus' to repository result fixtures used by router validation tests. Ensures the router schema accepts/strips fields correctly with the new required property.

packages/server/src/routers/correlation.test.ts

mobile-dashboard.test.tsUpdate mobile dashboard tests for sleepNeed epistemicStatus +2/-0

Update mobile dashboard tests for sleepNeed epistemicStatus

• Adds 'epistemicStatus' assertions for sleep need responses in missing/insufficient scenarios. Ensures dashboard aggregation returns the enriched sleep need contract.

packages/server/src/routers/mobile-dashboard.test.ts

sleep-need.test.tsUpdate sleep need router tests for epistemicStatus propagation +5/-0

Update sleep need router tests for epistemicStatus propagation

• Extends expected responses to include unavailable/estimated 'epistemicStatus' for multiple cases. Confirms router returns the contract-enforced status descriptor.

packages/server/src/routers/sleep-need.test.ts

dashboard-overview.test.tsUpdate dashboard overview tests for sleepNeedV2 epistemicStatus +8/-0

Update dashboard overview tests for sleepNeedV2 epistemicStatus

• Adds 'epistemicStatus' expectations across missing/insufficient/available sleep need paths. Ensures dashboard overview service returns consistent enriched sleep need output.

packages/server/src/services/dashboard-overview.test.ts

mobile-recovery-tab.test.tsUpdate mobile recovery tab tests for weight status fields +4/-0

Update mobile recovery tab tests for weight status fields

• Adds observed/estimated status fields to expected weight results. Confirms the recovery tab service returns contract-compliant status metadata.

packages/server/src/services/mobile-recovery-tab.test.ts

SleepNeedCard.stories.tsxAdd epistemicStatus to SleepNeedCard story fixtures +2/-0

Add epistemicStatus to SleepNeedCard story fixtures

• Updates sample sleep need fixtures to include estimated/unavailable status labels. Ensures Storybook examples match new contract shape.

packages/web/src/components/SleepNeedCard.stories.tsx

SleepNeedCard.test.tsxUpdate SleepNeedCard tests for epistemicStatus-driven titles and labels +5/-0

Update SleepNeedCard tests for epistemicStatus-driven titles and labels

• Adds 'epistemicStatus' to test data and asserts the title uses the status label (e.g., 'Estimated sleep need tonight'). Also checks the Unavailable label is shown for unavailable cases.

packages/web/src/components/SleepNeedCard.test.tsx

SleepOverviewCards.stories.tsxAdd epistemicStatus to SleepOverviewCards story fixtures +2/-0

Add epistemicStatus to SleepOverviewCards story fixtures

• Includes 'epistemicStatus' for available and missing sleep need fixtures. Keeps Storybook data compatible with updated sleep need schema.

packages/web/src/components/SleepOverviewCards.stories.tsx

SleepOverviewCards.test.tsxUpdate SleepOverviewCards tests to include sleep need epistemicStatus +3/-0

Update SleepOverviewCards tests to include sleep need epistemicStatus

• Adds required 'epistemicStatus' field to all sleepNeed props in tests. Ensures component test coverage remains valid under the new contract.

packages/web/src/components/SleepOverviewCards.test.tsx

SmoothedWeightChart.stories.tsxAdd raw/smoothed weight status fields to chart stories +2/-0

Add raw/smoothed weight status fields to chart stories

• Extends generated weight rows with observed raw and estimated smoothed statuses. Enables Storybook to display the new status-driven labels.

packages/web/src/components/SmoothedWeightChart.stories.tsx

SmoothedWeightChart.test.tsxUpdate SmoothedWeightChart tests for status-labeled headings and scale line +30/-2

Update SmoothedWeightChart tests for status-labeled headings and scale line

• Adds status fields to all sample rows and updates assertions to expect 'Estimated Trend Weight' and 'Observed: …' for scale. Covers null raw status behavior for interpolated days.

packages/web/src/components/SmoothedWeightChart.test.tsx

TodayPlanCard.stories.tsxAdd epistemicStatus to TodayPlanCard web story fixtures +2/-0

Add epistemicStatus to TodayPlanCard web story fixtures

• Updates today plan story data for ready and insufficient cases to include suggested/unavailable statuses. Keeps Storybook aligned with the new result schema.

packages/web/src/components/TodayPlanCard.stories.tsx

TodayPlanCard.test.tsxUpdate TodayPlanCard web tests to render epistemicStatus labels +4/-0

Update TodayPlanCard web tests to render epistemicStatus labels

• Adds 'epistemicStatus' to fixtures and asserts Suggested/Unavailable are visible in relevant states. Ensures UI regression coverage for the new metadata line.

packages/web/src/components/TodayPlanCard.test.tsx

BodyPage.test.tsxUpdate Body page tests for weight rows including epistemic statuses +2/-0

Update Body page tests for weight rows including epistemic statuses

• Adds required raw/smoothed weight status fields to test overview fixtures. Ensures page-level tests remain consistent with the updated weight row contract.

packages/web/src/pages/BodyPage.test.tsx

CorrelationExplorerPage.stories.tsxAdd epistemicStatus to correlation explorer story fixtures +2/-0

Add epistemicStatus to correlation explorer story fixtures

• Adds associated/unavailable 'epistemicStatus' to available/insufficient correlation fixtures. Keeps Storybook examples aligned with updated correlation schema.

packages/web/src/pages/CorrelationExplorerPage.stories.tsx

CorrelationExplorerPage.test.tsxUpdate correlation explorer tests to include and display epistemicStatus +6/-0

Update correlation explorer tests to include and display epistemicStatus

• Adds 'epistemicStatus' to test state and asserts labels appear in both insufficient and available renders. Ensures the page surfaces server-authored status text.

packages/web/src/pages/CorrelationExplorerPage.test.tsx

Dashboard.test.tsxUpdate dashboard tests for today plan epistemicStatus +1/-0

Update dashboard tests for today plan epistemicStatus

• Adds 'epistemicStatus' to mocked today plan query data. Keeps dashboard tests compatible with the updated today plan result contract.

packages/web/src/pages/Dashboard.test.tsx

Documentation (1) +1 / -0
README.mdDocument new scoring export for epistemic-status +1/-0

Document new scoring export for epistemic-status

• Adds '@dofek/scoring/epistemic-status' to the public package/module list. Makes the shared vocabulary discoverable for downstream usage.

packages/scoring/README.md

Other (1) +5 / -0
package.jsonExport epistemic-status entrypoint from scoring package +5/-0

Export epistemic-status entrypoint from scoring package

• Adds './epistemic-status' to exports and types/import mappings. Enables consumers (server and others) to import the shared vocabulary module.

packages/scoring/package.json

Comment thread packages/mobile/app/(tabs)/index.tsx Outdated
Comment thread packages/mobile/app/(tabs)/recovery.tsx Outdated
Comment thread packages/mobile/app/correlation.tsx Outdated
Comment thread packages/mobile/components/TodayPlanCard.tsx Outdated
Comment thread packages/mobile/components/TodayPlanCard.tsx Outdated
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Mobile Preview

Scan to open on device:

QR code for dofek://preview/pr-2405

Channel pr-2405
Deep Link dofek://preview/pr-2405
Commit aeb0d2a

To test on device:

  1. Build and install the preview client: PREVIEW_CHANNEL=pr-2405 pnpm expo prebuild --clean -p ios
  2. Or tap deep link on an existing preview build: dofek://preview/pr-2405

Each PR gets its own channel. Build a preview client with PREVIEW_CHANNEL=pr-{N} to test.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for aeb0d2a5 are ready:

This comment updates automatically on each PR push.

@qodo-code-review

qodo-code-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 197 rules

Grey Divider


Action required

1. Server cache keys not bumped ✓ Resolved 🐞 Bug ☼ Reliability
Description
Multiple server endpoints are cached via queryCache, but their cache keys/keyVersions were not
bumped even though this PR adds new required fields (e.g. epistemicStatus) that clients now
render. After deploy, cache hits can still return older cached payloads missing the new fields until
TTL expiry, which can break new clients (missing labels or runtime errors) and/or cause
output-schema mismatches.
Code

packages/server/src/routers/correlation.ts[R85-86]

+  epistemicStatus: epistemicStatusSchema,
  dataPoints: z.array(correlationDataPointSchema),
Relevance

●●● Strong

Multiple accepted reviews require bumping queryCache keyVersion when cached endpoint adds required
fields to avoid stale payloads.

PR-#2384
PR-#2346
PR-#2388

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Server-side caching can serve old payloads because cache hits short-circuit recomputation. Several
procedures that now require the new status fields are cached without a bumped keyVersion (or without
any keyVersion), while clients now render these fields directly (e.g. correlation and weight UI).

packages/server/src/trpc.ts[302-317]
packages/server/src/routers/correlation.ts[238-272]
packages/server/src/routers/body-analytics.ts[99-105]
packages/server/src/routers/body-analytics.ts[107-110]
packages/server/src/routers/sleep-need.ts[309-317]
packages/server/src/routers/mobile-dashboard.ts[148-154]
packages/server/src/routers/today-plan.ts[48-55]
packages/web/src/components/SmoothedWeightChart.tsx[208-219]
packages/mobile/app/correlation.tsx[683-694]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
This PR expands multiple cached tRPC outputs by adding required status fields (`epistemicStatus`, `rawWeightStatus`, `smoothedWeightStatus`). Several affected procedures either:
- have no `keyVersion` at all, or
- keep an existing `keyVersion` value.

As a result, after deployment the server may serve older cached payloads (written before this PR) that do not include the new fields, until the cache entries expire. Clients updated in this PR now render these fields (e.g. `data.epistemicStatus.label`) and can fail.

### Issue Context
- The caching middleware returns a cache hit directly.
- Correlation/body-analytics/sleep-need/today-plan/mobile-dashboard procedures are cached.

### Fix
Bump or introduce cache key versions for each cached procedure whose response contract changed in this PR, for example:
- `correlation.compute` and `correlation.computeV2` (pass `keyVersion` via `selectedChartCustomRangeQuery(..., options)`)
- `bodyAnalytics.smoothedWeight` and `bodyAnalytics.weightOverview` (add `keyVersion`; consider also adding an explicit `.output(...)` schema to ensure cached payloads match)
- `sleepNeed.calculateV2` (bump `sleep-need-metadata-v1` -> `v2`)
- `mobileDashboard.dashboardV2` (bump matching `sleep-need-metadata-*` version)
- `todayPlan.get` (bump `today-plan-evidence-v1` -> `v2`)
- `mobileDashboard.recovery` if its cached payload includes the new weight status fields but its `keyVersion` isn’t bumped.

### Fix Focus Areas
- packages/server/src/trpc.ts[302-317]
- packages/server/src/routers/correlation.ts[238-272]
- packages/server/src/routers/body-analytics.ts[99-105]
- packages/server/src/routers/body-analytics.ts[107-110]
- packages/server/src/routers/sleep-need.ts[309-317]
- packages/server/src/routers/mobile-dashboard.ts[148-154]
- packages/server/src/routers/today-plan.ts[48-55]
- packages/web/src/components/SmoothedWeightChart.tsx[208-219]
- packages/mobile/app/correlation.tsx[683-694]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Mobile cache not busted ✓ Resolved 🐞 Bug ☼ Reliability
Description
Mobile persists React Query results across app upgrades, but the cache buster version was not
incremented while the UI now unconditionally reads *.epistemicStatus.label /
*.smoothedWeightStatus.label. Restoring a pre-PR persisted cache (missing these new fields) will
throw at render time on common screens like Today/Recovery/Correlation.
Code

packages/mobile/components/TodayPlanCard.tsx[R61-62]

+        <Text style={styles.meta}>{plan.epistemicStatus.label}</Text>
        <Text style={styles.meta}>{formatTodayPlanConfidence(plan.confidence)}</Text>
Relevance

●●● Strong

Team previously bumped MOBILE_QUERY_CACHE_CONTRACT_VERSION / added guards for new required fields
(persisted cache crash risk).

PR-#2317
PR-#2280

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The app persists query cache across launches using a buster derived from
MOBILE_QUERY_CACHE_CONTRACT_VERSION (currently still 6). The new UI code added in this PR
dereferences epistemicStatus.label / smoothedWeightStatus.label directly; if hydrated cached
objects are from before this PR (and thus lack the new fields), these property reads will throw.

packages/mobile/lib/mobile-query-persistence.ts[9-14]
packages/mobile/lib/mobile-query-persistence.ts[64-72]
packages/mobile/components/TodayPlanCard.tsx[55-63]
packages/mobile/app/(tabs)/index.tsx[82-85]
packages/mobile/app/(tabs)/index.tsx[278-287]
packages/mobile/app/(tabs)/recovery.tsx[615-629]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Mobile uses persisted React Query cache across releases. This PR adds new required fields (e.g. `plan.epistemicStatus.label`) and reads them without null/undefined guards. If an existing user upgrades with an old persisted cache, hydrated query data can lack these fields and cause a runtime exception during render.

### Issue Context
- Cache persistence is controlled by `MOBILE_QUERY_CACHE_CONTRACT_VERSION` which is used as a `buster` value.
- This PR adds several new `.label` reads on `epistemicStatus` / weight status objects.

### Fix
1. Increment `MOBILE_QUERY_CACHE_CONTRACT_VERSION` to invalidate existing persisted caches.
2. (Optional but recommended) Add defensive rendering fallbacks for `epistemicStatus`/status objects (e.g. optional chaining or default label) so future additive contract changes don’t hard-crash the UI.

### Fix Focus Areas
- packages/mobile/lib/mobile-query-persistence.ts[9-14]
- packages/mobile/lib/mobile-query-persistence.ts[64-72]
- packages/mobile/components/TodayPlanCard.tsx[55-63]
- packages/mobile/app/(tabs)/index.tsx[82-85]
- packages/mobile/app/(tabs)/index.tsx[278-287]
- packages/mobile/app/(tabs)/recovery.tsx[615-629]
- packages/mobile/app/correlation.tsx[683-694]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread packages/mobile/components/TodayPlanCard.tsx Outdated
Comment thread packages/server/src/routers/correlation.ts
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@Asherlc
Asherlc merged commit 3966318 into main Aug 2, 2026
112 checks passed
@Asherlc
Asherlc deleted the codex/issue-2075 branch August 2, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DQ-02] No consistent epistemic status for observed vs estimated values

2 participants