Skip to content

fix(sync): tailor recovery guidance - #2507

Merged
Asherlc merged 46 commits into
mainfrom
clarify-activities-sync-error-data-source
Aug 12, 2026
Merged

Asherlc merged 46 commits into
mainfrom
clarify-activities-sync-error-data-source

Conversation

@Asherlc

@Asherlc Asherlc commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Classify provider sync failures as authentication vs. transient service failures.
  • Direct reconnection only for authentication failures; service outages prompt retry instead.
  • Link reconnect actions from web and mobile status cards to the affected provider page.

Validation

  • pnpm lint (repository checks passed; unrelated SQLFluff LT08 internal exceptions remain in existing analytics models)
  • pnpm tsc --noEmit
  • pnpm --dir packages/server tsc --noEmit
  • pnpm --dir packages/web tsc --noEmit
  • pnpm test

Summary by Sourcery

Classify provider sync failures as authentication vs transient service errors, tailor recovery messaging/actions across web and mobile, and ship Hangboarding and body-fat analytics surfaces while tightening Apple Health import, calendar visibility, and analytics performance.

New Features:

  • Add Hangboarding activity detail routes and repositories, exposing Hang Ten plan/board metadata and interval segments on web and mobile.
  • Expose Hangboarding training summaries (sessions, durations, intervals, heart rate, daily trend) in the climbing tab and mobile training dashboard.
  • Add a body-fat percentage trend chart to the web Body page and surface body-fat history on the mobile Recovery tab.

Bug Fixes:

  • Ensure provider sync alerts identify the affected data source and distinguish authentication failures from provider service outages, prescribing reconnect or retry appropriately.
  • Normalize empty cycling modality values to null at the serving boundary so enum validation and analytics tolerate legacy rows.
  • Prevent transient network transport errors from being reported to Sentry by the mobile query client.
  • Keep Hang Ten interval replacement atomic in Apple Health imports so activity rows are not advanced when interval writes fail.
  • Restrict sleep heart-rate sample reads and existing-state checks to current dirty windows/dates to avoid timeouts on large historical datasets.

Enhancements:

  • Group processing failures by operation, surface newest failure timestamps and last-success times, and add durable dismissal with provider reconnection links from status widgets on web and mobile.
  • Optimize activity visibility checks for calendar lookups by filtering canonical activity IDs directly instead of expanding the recursive visibility view.
  • Extend processing event indexing to support efficient latest-event lookups for scoped processing history.
  • Refine training and activity labels so the hangboard canonical type is consistently presented as Hangboarding across clients.

Documentation:

  • Document Hangboarding import/UI implementation details and incident baselines for stale analytics data, CI failures, Dependabot Python/Expo incompatibilities, and provider sync alerts in the production-incident and superpowers plan/spec files.

Tests:

  • Add extensive unit and integration coverage for Hangboarding repositories, routers, Apple Health parsing/upsert behavior, processing status widgets, mobile/web activity detail gating, cycling analytics modality normalization, sleep heart-rate sample SQL, and new body-fat/chart contracts.

Summary by cubic

Tailors provider sync recovery so users reconnect only for authentication failures and otherwise retry. Previously all failures prompted reconnect; now auth failures show “needs to reconnect” with a deep link, while service/sync failures show retry-only guidance and a “Retry sync” action.

  • Worker and alerts: emit provider-specific errorCode/errorMessage; map provider_auth_failed to “needs to reconnect” with a reconnect action; map provider_sync_failed or ingest failures to “couldn’t sync” with a retry_sync action and “Try the sync again later” messaging.
  • @dofek/providers/processing-status: add providerId, propagate errorCode, and derive a requiresReconnect flag to drive UI actions.
  • Web and mobile widgets: show “Reconnect ” only when requiresReconnect is true, deep-linking to /providers/<id> via @tanstack/react-router (web) and expo-router (mobile); keep Dismiss.
  • Misc: export Hangboarding contracts from @dofek/providers/hangboarding; update the production-incident baseline with the CI orphaned-component incident outcome.

Written for commit 4a06f45. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added reconnect actions for provider authentication failures in web and mobile processing status views.
    • Added a mobile climbing-entry breakdown showing grades, routes, locations, attempts, outcomes, and session details.
    • Added shared hangboarding data support for training summaries and interval details.
  • Bug Fixes

    • Improved processing alerts to distinguish authentication failures from retryable sync failures.
    • Added provider-specific error messages and clearer retry or reconnect guidance.
    • Improved failure selection and timestamps for processing activity across multiple datasets.

Asherlc added 30 commits August 7, 2026 12:07
* chore: configure Paseo workspace workflows

* fix: allow alertable in spell check

* fix: scope mutation checks to pull request changes

* test: align mobile tRPC mocks

* test: align web tRPC mocks

* fix: sync mobile Expo dependencies

* docs: record CI incident findings
* docs: specify body fat percentage chart

* docs: plan body fat percentage chart

* feat: expose mobile body fat history

* feat: add web body fat chart

* feat: show body fat chart on web body page

* feat: show body fat trend on mobile recovery

* test: cover mobile recovery body fat response

* test: type recovery body fat fixture

* fix: close body fat chart review findings

* fix: preserve body fat chart layout

* fix: restore CI checks

* test: strengthen processing mutations
Copilot AI lite review requested due to automatic review settings August 12, 2026 18:16
@cursor

cursor Bot commented Aug 12, 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 12, 2026

Copy link
Copy Markdown

LGTM! 🚀

Review Summary:

  1. Analytics Read Models:
    • cycling_activity.sql: Correctly normalizes empty string modality values using nullIf.
    • sleep_heart_rate_sample.sql: Optimizes query execution in ClickHouse by replacing subqueries with INNER JOIN dirty_sleep_dates and scoping existing state checks to current windows.
  2. Database Migration:
    • 0073_processing_stage_event_latest_lookup.sql: Adds processing_stage_event_latest_idx matching the Drizzle schema to accelerate stage event lookups ordered by DISTINCT ON keys.
  3. Mobile Features & UI Components:
    • HangboardingSummary & HangboardingDetail: Clean React Native components with proper handling for loading states, empty states, error fallbacks, and nullable metrics.
    • ProcessingStatusWidget: Adds inline provider reconnect action and navigation routing.
    • RecoveryScreen & StrainScreen: Correctly displays body fat trend card and hangboarding summary section.
  4. Test Coverage:
    • Comprehensive test coverage added across SQL query assertions, component tests, and screen integration tests.

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

@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, your pull request is larger than the review limit of 150000 diff characters

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

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 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR refines provider sync failure classification and recovery guidance, and adds end‑to‑end Hangboarding import, storage, and training UI across server, web, and mobile, along with a new body‑fat trend surface and several performance and robustness improvements for analytics and processing alerts.

Sequence diagram for provider sync failure classification and recovery actions

sequenceDiagram
  participant Worker as processSyncJob
  participant DB as processing_stage_event
  participant Repo as ProcessingRepository
  participant Meta as processingFailureGroups
  participant Web as Web_ProcessingStatusWidget
  participant Mobile as Mobile_ProcessingStatusWidget

  Worker->>DB: appendProcessingStageEvent(authFailureReason)
  Note over Worker,DB: errorCode = provider_auth_failed or provider_sync_failed

  Repo->>DB: listScopedProcessingOperations
  Repo->>Repo: buildProcessingAlert(failedEvent)
  Note over Repo: action = reconnect when errorCode = provider_auth_failed
  Note over Repo: action = retry_sync when errorCode = provider_sync_failed

  Web->>Repo: alerts()
  Repo-->>Web: ProcessingAlert{action,actionLabel,providerId}
  Web->>Web: processingFailureGroups(input)
  Web->>Web: render Reconnect or Retry button

  Mobile->>Repo: alerts()
  Repo-->>Mobile: ProcessingAlert{action,actionLabel,providerId}
  Mobile->>Mobile: processingFailureGroups(input)
  Mobile->>Mobile: render Reconnect or Retry button

  Mobile->>Mobile: useRouter.push(/providers/providerId)
  Web->>Web: Link to /providers/$id
Loading

File-Level Changes

Change Details Files
Processing and provider sync failures now carry structured error codes, are grouped by operation, and drive tailored reconnect vs retry guidance wired through web and mobile status widgets.
  • ProcessingRepository enriches operations with errorCode, derives lastFailedAt from the newest failure event (with sequence tie‑break), and builds provider alerts that distinguish authentication failures (reconnect) from service outages (retry).
  • processSyncJob maps provider sync results/errors into standardized event errorCode/errorMessage, classifies provider_auth_failed vs provider_sync_failed, and preserves authFailureReason for metrics.
  • Shared processing-status metadata groups failed datasets by operation, computes failure/last-ready timestamps, and exposes requiresReconnect; web and mobile ProcessingStatusWidget components render reconnect buttons that deep-link into provider pages plus durable dismiss actions.
  • Tests across server, web, and mobile validate provider auth vs service failure messaging, Oxford-comma dataset alert formatting, reconnect navigation, and failure grouping semantics.
packages/server/src/repositories/processing-repository.ts
src/jobs/process-sync-job.ts
packages/providers-meta/src/processing-status.ts
packages/providers-meta/src/processing-status.test.ts
packages/mobile/components/ProcessingStatusWidget.tsx
packages/mobile/components/ProcessingStatusWidget.test.tsx
packages/web/src/components/ProcessingStatusWidget.tsx
packages/web/src/components/ProcessingStatusWidget.test.tsx
packages/server/src/repositories/processing-repository.test.ts
packages/server/src/repositories/processing-repository.test.ts
Apple Health Hang Ten workouts are now imported as canonical Hangboarding activities with transactional interval replacement, and surfaced via dedicated server repositories and activity/climbing routes.
  • Apple Health parsing collects Hang Ten metadata and typed activity segments, uses Hang Ten SessionID for the workout external ID, tolerates empty segment arrays, and reports malformed segment JSON via activitySegmentsError.
  • hang-ten-intervals builds labeled work/rest intervals from Hang Ten segments and upsertWorkoutBatch requires a transactional database, upserts Hang Ten activities with plan-based names and raw payload, then atomically replaces intervals within a transaction.
  • New HangboardingRepository exposes getDetail (plan/board/session metadata plus ordered intervals) and getSummary (server-computed totals, heart-rate aggregates, and daily rows) with limited-window access predicates and Zod validation; integration tests seed activities/intervals and verify exact totals.
  • Activity and climbing routers add hangboardDetails and hangboardingSummary procedures, with NOT_FOUND semantics for non-hangboard or non-owned activities and long-lived cached summaries; associated unit/integration tests cover contracts and errors.
src/providers/apple-health/workouts.ts
src/providers/apple-health/streaming.ts
src/providers/apple-health/hang-ten-intervals.ts
src/providers/apple-health/hang-ten-intervals.test.ts
src/providers/apple-health/db-insertion.ts
src/providers/apple-health/db-insertion.test.ts
src/providers/apple-health/db-insertion.integration.test.ts
src/providers/apple-health/parsing.test.ts
src/providers/apple-health/parsing-extra.test.ts
packages/server/src/repositories/hangboarding-repository.ts
packages/server/src/repositories/hangboarding-repository.test.ts
packages/server/src/repositories/hangboarding-repository.integration.test.ts
packages/server/src/routers/activity.ts
packages/server/src/routers/activity.test.ts
packages/server/src/routers/activity.integration.test.ts
packages/server/src/routers/climbing.ts
packages/server/src/routers/climbing.test.ts
packages/server/src/routers/climbing.integration.test.ts
Web and mobile UIs gain Hangboarding detail views on activity pages and Hangboarding summary metrics/trends on climbing/training screens, backed by the new server contracts.
  • Web ActivityDetailPage gates hangboardDetails queries on canonical hangboard activities and renders a Hangboarding section using HangboardingDetail plus a link to the latest session; tests verify query gating, labels, and navigation.
  • Web climbing tab queries climbing.hangboardingSummary and renders HangboardingSummary with metrics, daily duration chart, and error/empty states; tests assert tRPC wiring and section presence.
  • Mobile ActivityDetailScreen adds HangboardingDetail under activity stats, with query enablement only for hangboard activities and cache invalidation on recompute/delete; tests cover gating, labeling, and plan rendering.
  • Mobile StrainScreen parses a new hangboarding block from the training tab payload, surfaces it via ClimbingSectionModel, and renders HangboardingSummary with metrics and a SparkLine duration trend, plus empty/malformed/failed-refresh behaviors that preserve cached data and report Zod errors to Sentry.
  • Storybook stories for HangboardingDetail and HangboardingSummary are added for both web and mobile to aid visual verification.
packages/web/src/pages/ActivityDetailPage.tsx
packages/web/src/pages/ActivityDetailPage.test.tsx
packages/web/src/routes/training/climbing.tsx
packages/web/src/routes/training/climbing.test.tsx
packages/web/src/components/HangboardingDetail.tsx
packages/web/src/components/HangboardingDetail.test.tsx
packages/web/src/components/HangboardingDetail.stories.tsx
packages/web/src/components/HangboardingSummary.tsx
packages/web/src/components/HangboardingSummary.test.tsx
packages/web/src/components/HangboardingSummary.stories.tsx
packages/mobile/app/activity/[id].tsx
packages/mobile/app-tests/activity/[id].test.tsx
packages/mobile/app/(tabs)/strain.tsx
packages/mobile/app-tests/(tabs)/strain.test.tsx
packages/mobile/components/HangboardingDetail.tsx
packages/mobile/components/HangboardingDetail.test.tsx
packages/mobile/components/HangboardingDetail.stories.tsx
packages/mobile/components/HangboardingSummary.tsx
packages/mobile/components/HangboardingSummary.test.tsx
packages/mobile/components/HangboardingSummary.stories.tsx
Training and recovery mobile dashboard contracts are extended with Hangboarding and body-fat series, and server services hydrate these from existing repositories.
  • mobile-training-tab output schema adds climbing.hangboarding, and loadMobileTrainingTab concurrently fetches HangboardingRepository.getSummary to populate it alongside climbing grade/volume/session data; tests assert the summary wiring and presence in the training result.
  • mobile-recovery-tab output schema gains bodyFat[], and loadMobileRecoveryTab derives this from BodyAnalyticsRepository.getRecomposition over the selected range; tests verify the series and repository call parameters.
  • Mobile RecoveryScreen renders a Body Fat % card when bodyFat has data, with latest value and a SparkLine trend using server-provided percentages; tests inspect SparkLine props and accessibility labeling.
  • Mobile training and recovery fixtures/tests are updated so empty-state payloads contain hangboarding/bodyFat fields and timing logs reflect the new repository calls.
packages/server/src/contracts/mobile-dashboard-contracts.ts
packages/server/src/contracts/mobile-dashboard-contracts.test.ts
packages/server/src/services/mobile-training-tab.ts
packages/server/src/services/mobile-training-tab.test.ts
packages/server/src/services/mobile-recovery-tab.ts
packages/server/src/services/mobile-recovery-tab.test.ts
packages/mobile/app/(tabs)/recovery.tsx
packages/mobile/app-tests/(tabs)/recovery.test.tsx
packages/server/src/routers/mobile-dashboard.test.ts
Web body page now shows a dedicated Body Fat Percentage chart based on recomposition data, and analytics/serving boundaries normalize cycling modalities and bound sleep HR sample reads for performance.
  • New BodyFatPercentageChart component builds a single-series ECharts line chart over BodyRecompositionRow.bodyFatPct, with percentage axis/tooltip formatting and explicit insufficient-data messaging; tests validate series, axis, tooltip, and empty behavior.
  • BodyPage wires BodyFatPercentageChart into the body-composition grid alongside Trend Weight and Recomposition, and tests assert body-fat point counts and layout.
  • Cycling ClickHouse model and CyclingAnalyticsRepository normalize empty modality strings to NULL at both SQL and TypeScript boundaries, with tests verifying empty vs non-empty behavior.
  • sleep_heart_rate_sample ClickHouse model constrains existing state and sensor reads to current dirty keys via JOINs instead of IN predicates, with SQL tests checking the new WHERE/JOIN clauses.
packages/web/src/components/BodyFatPercentageChart.tsx
packages/web/src/components/BodyFatPercentageChart.test.tsx
packages/web/src/components/BodyFatPercentageChart.stories.tsx
packages/web/src/pages/BodyPage.tsx
packages/web/src/pages/BodyPage.test.tsx
analytics/models/read_models/cycling_activity.sql
analytics/models/read_models/cycling_activity.sql.test.ts
packages/server/src/repositories/cycling-analytics-repository.ts
packages/server/src/repositories/cycling-analytics-repository.test.ts
analytics/models/read_models/sleep_heart_rate_sample.sql
analytics/models/read_models/sleep_heart_rate_sample.sql.test.ts
Apple Health Apple provider workout insertion is hardened with transactional requirements and Hang Ten interval replacement tests, plus minor training/meta updates (hangboard type/label, enum migration, PNPM audit config).
  • upsertWorkoutBatch now requires a SyncDatabase that supports transaction(), rejecting non-transactional or misconfigured DBs; tests assert the behavior and that workouts run inside one transaction.
  • Apple Health db-insertion integration tests verify Hang Ten interval replacement after reimport, preservation of existing intervals on malformed reimport, and atomicity when interval replacement violates a NOT VALID test constraint.
  • Training activity-type metadata registers canonical hangboard and maps it to the Hangboarding label, with tests confirming resolveProviderActivityType and formatActivityTypeLabel.
  • A dedicated hangboard activity-type migration integration test verifies the Postgres enum is extended with hangboard after climbing, and PNPM workspace audit config ignores two GHSA advisories to keep CI passing without blocking on upstream fixes.
src/providers/apple-health/db-insertion.ts
src/providers/apple-health/db-insertion.test.ts
src/providers/apple-health/db-insertion.integration.test.ts
packages/training/src/activity-types.ts
packages/training/src/activity-types.test.ts
packages/training/src/training.ts
packages/training/src/training.test.ts
src/db/hangboard-activity-type-migration.integration.test.ts
pnpm-workspace.yaml

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

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Processing failure handling

Layer / File(s) Summary
Provider failure events
src/jobs/process-sync-job.ts, src/jobs/process-sync-job.test.ts
Sync failures now use provider-specific error codes and messages for retry and reconnect guidance.
Status propagation and alert actions
packages/server/src/repositories/processing-repository.ts, packages/server/src/repositories/processing-repository.test.ts
Processing statuses expose the latest failure code. Alerts distinguish retry-sync actions from reconnect actions.
Web and mobile reconnect controls
packages/web/src/components/ProcessingStatusWidget.tsx, packages/web/src/components/ProcessingStatusWidget.test.tsx, packages/mobile/components/ProcessingStatusWidget.tsx, packages/mobile/components/ProcessingStatusWidget.test.tsx
Widgets render provider reconnect controls only for authentication failures and preserve dismiss behavior.
Failure group reconnect metadata
packages/providers-meta/src/processing-status.ts, packages/providers-meta/src/processing-status.test.ts
Failure groups include provider identity and a reconnect flag derived from provider_auth_failed.

Hangboarding contracts

Layer / File(s) Summary
Hangboarding public interfaces
packages/providers-meta/src/hangboarding.ts, packages/providers-meta/package.json, packages/server/src/services/mobile-training-tab.test.ts
The providers metadata package exports hangboarding interval, session, and summary interfaces.

Mobile climbing presentation

Layer / File(s) Summary
Climbing entry breakdown
packages/mobile/components/ClimbingEntryBreakdown.tsx
The mobile component renders climbing metadata, attempt outcomes, ascent and send status, attempt counts, and source information.

Analytics test corrections

Layer / File(s) Summary
Cycling analytics access fixtures
packages/server/src/repositories/cycling-analytics-repository.test.ts
Two repository tests now return the requested activity ID from mocked access queries.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProviderSyncJob
  participant ProcessingRepository
  participant ProcessingStatusWidget
  ProviderSyncJob->>ProcessingRepository: store provider-specific failure event
  ProcessingRepository-->>ProcessingStatusWidget: return latest errorCode and failure details
  ProcessingStatusWidget->>ProcessingStatusWidget: render retry or reconnect action
Loading

Possibly related PRs

  • Asherlc/dofek#1862: Adds related errorCode propagation through processing events and statuses.
  • Asherlc/dofek#1869: Introduces the processing-status widget and API flow extended here.
  • Asherlc/dofek#1870: Adds related processing widget behavior for provider authentication failures.

Suggested labels: area/mobile, area/web, area/server, area/providers, type/bug

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title uses imperative wording, is under 70 characters, and summarizes the main change, but it lacks the required area prefix. Prefix the title with the relevant area, such as [server], [web], or [mobile], while retaining the concise imperative summary.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 28

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/routes/training/climbing.test.tsx (1)

165-174: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test both Hangboarding error states.

The route adds an initial-error state and a stale-data error panel for hangboardingSummary. This suite only verifies query input and section presence. Add tests for an error with no data and an error with cached data.

As per coding guidelines, “add tests for changed behavior.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/routes/training/climbing.test.tsx` around lines 165 - 174,
Extend the climbing route tests around the Hangboarding section to cover both
hangboardingSummary error states: an initial error with no data and a stale-data
error with cached data. Mock the query responses appropriately, assert the
initial error UI when no summary exists, and assert the stale-data error panel
while preserving the cached Hangboarding content.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.superpowers/sdd/2026-08-10-hangboarding-import-and-ui/task-3-report.md:
- Around line 112-120: Add a ## Retrospective section to task-3-report.md
covering the one-sentence root cause, direct fix, justification for remaining
validation risk, and one concrete documentation or skill improvement. Link the
relevant existing entry in docs/production-incident-baseline.md, or add an
infrastructure-failure entry there if none applies.

In `@analytics/models/read_models/cycling_activity.sql.test.ts`:
- Around line 10-13: Add executable ClickHouse coverage in
analytics/models/read_models/cycling_activity.sql.test.ts for both empty and
non-empty modality values; the existing modelSql assertion is only static. Also
update analytics/models/read_models/sleep_heart_rate_sample.sql.test.ts to
execute ClickHouse behavior covering dirty-key filtering, user/date scoping, and
retention of samples across multiple days.

In `@docs/production-incident-baseline.md`:
- Line 23328: Insert one blank line immediately before the incident heading
beginning “2026-08-08 — Dependabot PRs…” in the markdown document, ensuring the
heading is surrounded by blank lines and conforms to MD022.

In `@docs/superpowers/plans/2026-08-08-activity-overview-partial-measurements.md`:
- Line 3: Remove the mandatory REQUIRED SUB-SKILL directive from the plan
header. Update the “For agentic workers” guidance to be optional, or incorporate
the necessary execution steps directly into the plan so the document stands
alone without relying on unavailable agent skills.

In `@docs/superpowers/plans/2026-08-08-processing-status-alerts.md`:
- Line 3: Update the plan’s “For agentic workers” instruction to remove
references to the external superpowers skills and replace them with
repository-local workflow guidance or a checked-in document, ensuring the
standalone documentation remains actionable without agent-skill dependencies.
- Line 18: Update the plan’s scope to acknowledge the implemented changes in
process-sync-job, including persistence of provider_auth_failed and
provider_sync_failed raw events. Revise the recovery-copy example around the
reconnect guidance to branch on errorCode, using reconnect instructions for
provider_auth_failed and retry-later guidance for provider_sync_failed.

In `@docs/superpowers/plans/2026-08-10-body-fat-chart.md`:
- Around line 114-119: Require explicit user or workflow approval immediately
before each git commit command in Step 8 at
docs/superpowers/plans/2026-08-10-body-fat-chart.md lines 114-119, the web-chart
commit at lines 184-189, the web-page commit at lines 229-234, and the mobile-ui
commit at lines 305-310; preserve the existing commit commands and messages.

In `@docs/superpowers/plans/2026-08-10-hangboarding-import-and-ui.md`:
- Around line 546-617: Update Task 5 to create and commit
HangboardingSummary.tsx with its test and story files, since strain.tsx is
required to render this component in that task. Remove those three files from
Task 7 and limit Task 7 to activity detail presentation.

In `@docs/superpowers/specs/2026-08-08-processing-status-alerts-design.md`:
- Around line 163-166: Update the testing-guidance link in the
migration/repository coverage section to use ../../testing.md so it resolves to
docs/testing.md; leave the surrounding testing guidance unchanged.
- Around line 184-189: Update the “Scope of implementation” section to include
the processing sync worker change in src/jobs/process-sync-job.ts, specifically
recording classified provider failure events, and remove or revise the statement
that no sync workers change. Keep the remaining scope unchanged.

In `@packages/mobile/app-tests/`(tabs)/strain.test.tsx:
- Around line 945-955: The StrainScreen test should preserve cached Hangboarding
content while also displaying background training refresh errors. Update the
test to expect a compact QueryStatePanel using trainingQuery.error and assert
that “Training refresh failed” is visible, while retaining the cached-data
assertion.

In `@packages/mobile/app/`(tabs)/strain.tsx:
- Around line 580-588: Add a visible “Hangboarding” heading in the
shouldShowClimbingSection fragment immediately before HangboardingSummary,
matching the web climbing page’s heading treatment and preserving the existing
component data and loading behavior.

In `@packages/mobile/app/activity/`[id].tsx:
- Around line 1051-1054: Split ActivityDetailScreen into focused modules so the
source file is under 1,000 lines. Extract a cohesive activity-detail section or
action flow, including its related styles such as hangboardingStyles, into a
separate module and update ActivityDetailScreen imports/usages without changing
behavior.

In `@packages/mobile/components/HangboardingDetail.stories.tsx`:
- Around line 43-50: Add an Empty story alongside Default, Loading, and
ErrorState in the HangboardingDetail stories, configuring its args to represent
absent details or an empty interval list while preserving the existing story
patterns.

In `@packages/mobile/components/HangboardingSummary.test.tsx`:
- Around line 97-101: Replace the nullable summary.latestSession spread in the
test fixture with a standalone non-nullable latestSession fixture containing all
required fields of HangboardingSummary.latestSession, then override planName and
boardName to null for this case. Keep the resulting object type-compatible with
HangboardingSummary.

In `@packages/mobile/lib/query-client.ts`:
- Around line 5-18: Update isTransientNetworkError and its QueryCache.onError
usage to classify failures by typed transport or cause identity, using the
current message regex only as a narrow native-network fallback so backend/tRPC
errors containing similar text still reach captureException(). Add tests
covering both a genuine transient transport error and a backend error with
“network request failed” in its message.

In `@packages/providers-meta/src/processing-status.test.ts`:
- Around line 205-220: Add a non-authentication operation fixture using the
existing processing-status test setup, with errorCode "provider_sync_failed",
and include its expected grouped result with requiresReconnect set to false.
Preserve the existing provider_auth_failed assertion and ensure the new
expectation verifies retry-only sync failures do not request reconnection.

In `@packages/server/src/contracts/mobile-dashboard-contracts.ts`:
- Around line 240-245: Update the bodyFat schema’s bodyFatPct field to use
nonnegativeNumberSchema instead of z.number(), while leaving the surrounding
date and array structure unchanged.

In `@packages/server/src/repositories/cycling-analytics-repository.test.ts`:
- Around line 933-975: Update both tests around
CyclingAnalyticsRepository.getActivities so the database execute mock returns
the mocked activity’s ID, allowing filterToVisibleCanonicalActivities to retain
the row. Apply this to the execute mocks in the “treats an empty modality” and
“preserves a non-empty modality” tests without changing their modality
assertions.

In `@packages/server/src/repositories/hangboarding-repository.ts`:
- Around line 309-332: Update the session_metrics GROUP BY to use
sessions.activity_id instead of sessions.hang_ten_activity_id, while retaining
the started_at and ended_at grouping fields. Ensure distinct sessions sharing
timestamps remain separate, including canonical activities with NULL
hang_ten_activity_id, so session_count and duration totals remain accurate.
- Around line 206-334: Update getSummary so the independent summaryRows and
dailyRows queries start concurrently instead of awaiting summaryRows before
creating the daily query. Initiate both `#query` calls first, then await their
results together while preserving the existing schemas, SQL, and downstream row
handling.

In `@packages/server/src/routers/activity.ts`:
- Around line 157-174: Add Zod output schemas for HangboardingDetail and
HangboardingSummary, then attach the appropriate schema with .output(...) to the
hangboardDetails procedure in packages/server/src/routers/activity.ts (lines
157-174) and the hangboarding summary procedure in
packages/server/src/routers/climbing.ts (lines 222-232); ensure each schema
matches the repository return shape.

In `@packages/web/src/components/HangboardingDetail.stories.tsx`:
- Around line 51-59: Add Empty and Error stories alongside Default,
SegmentWarning, and Loading in the HangboardingDetail story definitions,
configuring each with the props required to render the component’s empty and
error states while preserving the existing variants.

In `@packages/web/src/components/HangboardingSummary.tsx`:
- Line 3: Move the HangboardingSummary and HangboardingDetail type exports to
the designated shared contract module, then update imports from the server
repository in packages/web/src/components/HangboardingSummary.tsx:3-3,
packages/web/src/components/HangboardingDetail.tsx:2-2,
packages/mobile/components/HangboardingSummary.test.tsx:3-3,
packages/web/src/components/HangboardingDetail.stories.tsx:2-2,
packages/web/src/components/HangboardingDetail.test.tsx:5-5,
packages/web/src/components/HangboardingSummary.stories.tsx:2-2, and
packages/web/src/components/HangboardingSummary.test.tsx:6-6 to use that shared
module while preserving the existing type usage.

In `@packages/web/src/pages/ActivityDetailPage.tsx`:
- Around line 300-312: Split the oversized ActivityDetailPage component into
focused activity-detail modules before adding the hangboarding section, keeping
each extracted module cohesive and preserving existing behavior. Move enough
sections out of ActivityDetailPage.tsx to reduce it below 1000 lines, and keep
the new hangboarding rendering integrated through the appropriate extracted or
remaining component.

In `@pnpm-workspace.yaml`:
- Around line 35-39: Replace the ineffective audit.ignore configuration with
pnpm’s recognized auditConfig.ignoreGhsas setting, and document both GHSA
identifiers with their dependency scope, runtime reachability, compensating
control, owner, and review date; retain the exceptions only alongside that
documentation.

In `@src/db/hangboard-activity-type-migration.integration.test.ts`:
- Around line 17-27: Update the raw SQL queries in
src/db/hangboard-activity-type-migration.integration.test.ts lines 17-27 and
packages/server/src/routers/activity.integration.test.ts lines 357-368 to use
executeWithSchema() with Zod schemas validating enumlabel and id respectively.
Preserve undefined results through parsing until the explicit missing-row
checks, and do not convert absent values to an empty-string sentinel.

In `@src/providers/apple-health/parsing-extra.test.ts`:
- Around line 4-67: Remove the duplicate Hang Ten test cases from the describe
block in parsing-extra.test.ts, including malformed JSON, exact brand matching,
and structurally invalid metadata scenarios. Retain the existing coverage in
parsing.test.ts as the single source of these assertions.

---

Outside diff comments:
In `@packages/web/src/routes/training/climbing.test.tsx`:
- Around line 165-174: Extend the climbing route tests around the Hangboarding
section to cover both hangboardingSummary error states: an initial error with no
data and a stale-data error with cached data. Mock the query responses
appropriately, assert the initial error UI when no summary exists, and assert
the stale-data error panel while preserving the cached Hangboarding content.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0bb51533-0fb5-4134-b662-f3cf308f8f37

📥 Commits

Reviewing files that changed from the base of the PR and between 5fa5ae6 and 3272151.

📒 Files selected for processing (93)
  • .superpowers/sdd/2026-08-10-hangboarding-import-and-ui/task-3-report.md
  • analytics/models/read_models/cycling_activity.sql
  • analytics/models/read_models/cycling_activity.sql.test.ts
  • analytics/models/read_models/sleep_heart_rate_sample.sql
  • analytics/models/read_models/sleep_heart_rate_sample.sql.test.ts
  • cspell.json
  • docs/production-incident-baseline.md
  • docs/superpowers/plans/2026-08-08-activity-overview-partial-measurements.md
  • docs/superpowers/plans/2026-08-08-processing-status-alerts.md
  • docs/superpowers/plans/2026-08-10-body-fat-chart.md
  • docs/superpowers/plans/2026-08-10-hangboarding-import-and-ui.md
  • docs/superpowers/specs/2026-08-08-activity-overview-partial-measurements-design.md
  • docs/superpowers/specs/2026-08-08-processing-status-alerts-design.md
  • docs/superpowers/specs/2026-08-10-body-fat-chart-design.md
  • docs/superpowers/specs/2026-08-10-hangboarding-ui-design.md
  • drizzle/0073_processing_stage_event_latest_lookup.sql
  • drizzle/meta/_journal.json
  • packages/mobile/app-tests/(tabs)/index.test.tsx
  • packages/mobile/app-tests/(tabs)/recovery.test.tsx
  • packages/mobile/app-tests/(tabs)/strain.test.tsx
  • packages/mobile/app-tests/activity/[id].test.tsx
  • packages/mobile/app/(tabs)/recovery.tsx
  • packages/mobile/app/(tabs)/strain.tsx
  • packages/mobile/app/activity/[id].tsx
  • packages/mobile/components/HangboardingDetail.stories.tsx
  • packages/mobile/components/HangboardingDetail.test.tsx
  • packages/mobile/components/HangboardingDetail.tsx
  • packages/mobile/components/HangboardingSummary.stories.tsx
  • packages/mobile/components/HangboardingSummary.test.tsx
  • packages/mobile/components/HangboardingSummary.tsx
  • packages/mobile/components/ProcessingStatusWidget.test.tsx
  • packages/mobile/components/ProcessingStatusWidget.tsx
  • packages/mobile/lib/query-client.test.ts
  • packages/mobile/lib/query-client.ts
  • packages/providers-meta/src/processing-status.test.ts
  • packages/providers-meta/src/processing-status.ts
  • packages/server/src/contracts/mobile-dashboard-contracts.test.ts
  • packages/server/src/contracts/mobile-dashboard-contracts.ts
  • packages/server/src/repositories/activities-calendar-repository.test.ts
  • packages/server/src/repositories/activities-calendar-repository.ts
  • packages/server/src/repositories/activity-repository.test.ts
  • packages/server/src/repositories/activity-repository.ts
  • packages/server/src/repositories/cycling-analytics-repository.test.ts
  • packages/server/src/repositories/cycling-analytics-repository.ts
  • packages/server/src/repositories/hangboarding-repository.integration.test.ts
  • packages/server/src/repositories/hangboarding-repository.test.ts
  • packages/server/src/repositories/hangboarding-repository.ts
  • packages/server/src/repositories/processing-repository.test.ts
  • packages/server/src/repositories/processing-repository.ts
  • packages/server/src/routers/activity.integration.test.ts
  • packages/server/src/routers/activity.test.ts
  • packages/server/src/routers/activity.ts
  • packages/server/src/routers/climbing.integration.test.ts
  • packages/server/src/routers/climbing.test.ts
  • packages/server/src/routers/climbing.ts
  • packages/server/src/routers/mobile-dashboard.test.ts
  • packages/server/src/services/mobile-recovery-tab.test.ts
  • packages/server/src/services/mobile-recovery-tab.ts
  • packages/server/src/services/mobile-training-tab.test.ts
  • packages/server/src/services/mobile-training-tab.ts
  • packages/training/src/activity-types.test.ts
  • packages/training/src/training.test.ts
  • packages/training/src/training.ts
  • packages/web/src/components/BodyFatPercentageChart.stories.tsx
  • packages/web/src/components/BodyFatPercentageChart.test.tsx
  • packages/web/src/components/BodyFatPercentageChart.tsx
  • packages/web/src/components/DataSourcesPanel.test.tsx
  • packages/web/src/components/HangboardingDetail.stories.tsx
  • packages/web/src/components/HangboardingDetail.test.tsx
  • packages/web/src/components/HangboardingDetail.tsx
  • packages/web/src/components/HangboardingSummary.stories.tsx
  • packages/web/src/components/HangboardingSummary.test.tsx
  • packages/web/src/components/HangboardingSummary.tsx
  • packages/web/src/components/ProcessingStatusWidget.test.tsx
  • packages/web/src/components/ProcessingStatusWidget.tsx
  • packages/web/src/pages/ActivityDetailPage.test.tsx
  • packages/web/src/pages/ActivityDetailPage.tsx
  • packages/web/src/pages/BodyPage.test.tsx
  • packages/web/src/pages/BodyPage.tsx
  • packages/web/src/routes/training/climbing.test.tsx
  • packages/web/src/routes/training/climbing.tsx
  • paseo.json
  • pnpm-workspace.yaml
  • src/db/hangboard-activity-type-migration.integration.test.ts
  • src/db/schema/processing.ts
  • src/jobs/process-sync-job.test.ts
  • src/jobs/process-sync-job.ts
  • src/providers/apple-health/db-insertion.integration.test.ts
  • src/providers/apple-health/db-insertion.test.ts
  • src/providers/apple-health/db-insertion.ts
  • src/providers/apple-health/hang-ten-intervals.test.ts
  • src/providers/apple-health/parsing-extra.test.ts
  • src/providers/apple-health/parsing.test.ts
💤 Files with no reviewable changes (1)
  • paseo.json

Comment thread analytics/models/read_models/cycling_activity.sql.test.ts
Comment thread docs/production-incident-baseline.md
Comment thread docs/superpowers/plans/2026-08-08-processing-status-alerts.md
Comment thread packages/web/src/components/HangboardingSummary.tsx
Comment thread packages/web/src/pages/ActivityDetailPage.tsx
Comment thread pnpm-workspace.yaml
Comment thread src/db/hangboard-activity-type-migration.integration.test.ts
Comment thread src/providers/apple-health/parsing-extra.test.ts
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for 825cfeb9 are ready:

This comment updates automatically on each PR push.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/mobile/components/ClimbingEntryBreakdown.tsx`:
- Around line 54-60: Update the attempt result rendering in
ClimbingEntryBreakdown so failed attempts with a missing failureReason display a
clear fallback label such as “Not sent” instead of an empty result. Preserve the
existing capitalization and failure-reason display when a reason is available.
- Around line 26-74: Add colocated Vitest coverage for ClimbingEntryBreakdown,
including sent attempts, failed attempts without a failure reason, and no-data
output. Add ClimbingEntryBreakdown.stories.tsx with default, loading, empty, and
meaningful-variant stories, using the component’s existing props and rendering
conventions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e23c2069-082f-4c03-8ab0-62585840aa03

📥 Commits

Reviewing files that changed from the base of the PR and between 3272151 and ad815bf.

📒 Files selected for processing (6)
  • packages/mobile/components/ClimbingEntryBreakdown.tsx
  • packages/providers-meta/package.json
  • packages/providers-meta/src/hangboarding.ts
  • packages/providers-meta/src/processing-status.test.ts
  • packages/server/src/repositories/cycling-analytics-repository.test.ts
  • packages/server/src/services/mobile-training-tab.test.ts

Comment thread packages/mobile/components/ClimbingEntryBreakdown.tsx Outdated
Comment thread packages/mobile/components/ClimbingEntryBreakdown.tsx Outdated
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Mobile Preview

Scan to open on device:

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

Channel pr-2507
Deep Link dofek://preview/pr-2507
Commit 825cfeb

To test on device:

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

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

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository Owner rate limit exceeded. Free accounts are limited to 3 reviews per 4 hours across all repositories. Upgrade to a paid plan for unlimited reviews.

@Asherlc
Asherlc enabled auto-merge (squash) August 12, 2026 20:15
@Asherlc
Asherlc merged commit cfe6fe8 into main Aug 12, 2026
191 of 195 checks passed
@Asherlc
Asherlc deleted the clarify-activities-sync-error-data-source branch August 12, 2026 20:17
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.

2 participants