Skip to content

feat(activity): show card provenance - #2317

Merged
Asherlc merged 3 commits into
mainfrom
issue-2123-activity-card-provenance
Jul 29, 2026
Merged

Asherlc merged 3 commits into
mainfrom
issue-2123-activity-card-provenance

Conversation

@Asherlc

@Asherlc Asherlc commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • expose canonical activity source attribution on calendar activity cards
  • expose the latest serving-row refresh time as the card's last-processed time
  • render matching provenance and freshness details on web and mobile
  • cover compact source semantics at the model, repository, API, UI, and real-ClickHouse integration boundaries

Fixes #2123

Validation

  • pnpm exec vitest run ... — 96 focused server/web tests passed
  • pnpm --dir packages/mobile test — 1,165 mobile tests passed
  • pnpm tsc --noEmit
  • server, web, and mobile package typechecks
  • pnpm lint:sandbox — all 8 gates passed
  • Biome check on all changed TypeScript/TSX files
  • pnpm test — all 14,789 executed tests passed; Vitest exited nonzero afterward on runner RPC error Timeout calling "onTaskUpdate"

Local integration environment

The repository Compose startup failed before an integration test could run.

  • exact failing step: pnpm compose -- up -d --wait --wait-timeout 180 db clickhouse redis redpanda
  • first fatal line: Could not setup Async I/O: unknown error. The required nr_events 1 exceeds the capacity in /proc/sys/fs/aio-max-nr 65536.
  • cause: the shared Docker VM's system-wide AIO capacity was already exhausted by other workloads

No sysctl, timeout, retry, application behavior, or other workspace state was changed. The current workspace's disposable Compose resources were removed. Clean exact-head CI is the real integration gate.

Summary by Sourcery

Expose canonical source attribution and processing freshness on calendar activity entries and activity cards across server, web, and mobile.

New Features:

  • Add compact source provenance and last-processed timestamps to calendar activity entries returned by the server and calendar router.
  • Render activity source labels, overlap summaries, and relative last-processed times on web and mobile activity cards.

Enhancements:

  • Align list-card source provenance with existing activity detail source-decision semantics via a shared model helper.
  • Ensure ClickHouse-derived activity processing freshness matches the value surfaced in calendar entries through an integration test.
  • Update activity stories and tests to cover new provenance and freshness fields on activity cards.

Documentation:

  • Document a Docker Desktop AIO exhaustion incident and its impact on local integration validation in the production incident baseline.

Tests:

  • Extend server, web, and mobile tests to validate source provenance and processing freshness rendering and the underlying ClickHouse query.
  • Add integration coverage to assert canonical source attribution and processing freshness for a real activity in ClickHouse.

Summary by cubic

Show canonical source attribution and processing freshness on activity cards across web and mobile. Implements #2123 by reusing source-priority semantics and exposing lastProcessedAt from the read model, aligned with ClickHouse view freshness.

  • New Features

    • Server (packages/server)
      • Added buildActivityListSource to derive list-card provenance from canonical source-priority logic.
      • Calendar repository selects provider_id, source_name, source links, and computes last_processed_at as greatest of activity and summary refresh; API/schema return source and lastProcessedAt.
      • Expose refreshed_at in analytics.activity_summary via compatibility view and migration 0064_activity_summary_freshness; integration helpers and tests updated.
    • Web (packages/web)
      • ActivityCardContent shows a source pill, optional overlap summary, and “Processed X ago.”
    • Mobile (packages/mobile)
      • ActivitiesScreen renders the same provenance and freshness details.
  • Bug Fixes

    • Distinguish missing source-link attribution from an empty matched set so canonical labels render without false overlap claims and hidden activity provenance remains verifiable.
    • Align freshness contracts end-to-end by projecting activity-summary refreshed_at through the view and invalidating persisted mobile data with the previous calendar shape (cache contract bumped).

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

Review in cubic

Reuse canonical source-priority semantics and read-model freshness across web and mobile activity lists.

Refs #2123
Copilot AI review requested due to automatic review settings July 29, 2026 22:29
@Asherlc Asherlc linked an issue Jul 29, 2026 that may be closed by this pull request
@cursor

cursor Bot commented Jul 29, 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

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.

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 Jul 29, 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: 48 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: 371bf6bf-4108-4615-9be5-37b28263a39a

📥 Commits

Reviewing files that changed from the base of the PR and between 55a44d2 and ee247e0.

📒 Files selected for processing (27)
  • docs/production-incident-baseline.md
  • packages/mobile/app/(tabs)/activities.stories.tsx
  • packages/mobile/app/(tabs)/activities.test.tsx
  • packages/mobile/app/(tabs)/activities.tsx
  • packages/mobile/lib/mobile-query-persistence.test.tsx
  • packages/mobile/lib/mobile-query-persistence.ts
  • packages/server/src/models/activity-source-decision.test.ts
  • packages/server/src/models/activity-source-decision.ts
  • packages/server/src/repositories/activities-calendar-repository.test.ts
  • packages/server/src/repositories/activities-calendar-repository.ts
  • packages/server/src/repositories/activity-visibility-consistency.integration.test.ts
  • packages/server/src/routers/calendar.test.ts
  • packages/server/src/routers/calendar.ts
  • packages/server/src/routers/clickhouse-integration-test-helpers.test.ts
  • packages/server/src/routers/clickhouse-integration-test-models.ts
  • packages/web/src/components/ActivityCardContent.stories.tsx
  • packages/web/src/components/ActivityCardContent.test.tsx
  • packages/web/src/components/ActivityCardContent.tsx
  • packages/web/src/pages/ActivitiesPage.test.tsx
  • src/db/clickhouse-activity-summary.test.ts
  • src/db/clickhouse-activity-summary.ts
  • src/db/clickhouse-metric-stream-bootstrap.test.ts
  • src/db/clickhouse-metric-stream-bootstrap.ts
  • src/db/clickhouse-migrations/0064_activity_summary_freshness.test.ts
  • src/db/clickhouse-migrations/0064_activity_summary_freshness.ts
  • src/db/clickhouse-migrations/registry.test.ts
  • src/db/clickhouse-migrations/registry.ts

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 Jul 29, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Implements canonical source provenance and read-model processing freshness on calendar activities, wiring provider/source fields from ClickHouse/Postgres through the server models and calendar router into web and mobile card UIs, and adds supporting tests plus an incident doc entry about local Docker AIO exhaustion.

File-Level Changes

Change Details Files
Expose compact source provenance and processing freshness on calendar activity entries and cards across server, API, web, and mobile.
  • Extend calendar activity row schema and SQL to include provider_id, source_name, source_external_ids, absent_source_external_ids, and a computed last_processed_at from ClickHouse refreshed_at fields.
  • Add ActivityListSourceDetail model and buildActivityListSource helper reusing existing source-priority semantics and provider registry lookups.
  • Populate CalendarActivityEntry.source and lastProcessedAt from ActivitySourceAttribution and ActivityListSourceDetail for both analytics and Postgres-backed queries.
  • Update calendar router schema to expose source and lastProcessedAt to clients, and adjust repository/router tests to assert provenance and freshness fields and the ClickHouse greatest(...) query expression.
  • Update web ActivityCardContent and mobile ActivitiesScreen components to render primary source label pill, optional processed-relative time via formatRelativeTime, and optional overlapSummary, with corresponding styles and tests/stories.
packages/server/src/repositories/activities-calendar-repository.ts
packages/server/src/models/activity-source-decision.ts
packages/server/src/models/activity-source-decision.test.ts
packages/server/src/repositories/activities-calendar-repository.test.ts
packages/server/src/repositories/activity-visibility-consistency.integration.test.ts
packages/server/src/routers/calendar.ts
packages/server/src/routers/calendar.test.ts
packages/web/src/components/ActivityCardContent.tsx
packages/web/src/components/ActivityCardContent.test.tsx
packages/web/src/components/ActivityCardContent.stories.tsx
packages/web/src/pages/ActivitiesPage.test.tsx
packages/mobile/app/(tabs)/activities.tsx
packages/mobile/app/(tabs)/activities.test.tsx
packages/mobile/app/(tabs)/activities.stories.tsx
Document and test environment impact of shared Docker VM AIO exhaustion on integration validation.
  • Add incident entry describing Async I/O capacity exhaustion preventing local Compose integration runs and clarifying that CI remains the integration gate.
  • Capture the ClickHouse/Redpanda failure evidence, root cause, mitigation, and remaining risk for future diagnostics.
docs/production-incident-baseline.md

Assessment against linked issues

Issue Objective Addressed Explanation
#2123 Display canonical activity source attribution on activity list cards across web and mobile.
#2123 Expose overlap/deduplication disclosure for multi-source activities on list cards.
#2123 Show last-processed time (processing freshness) for activities on list cards.

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

Expose activity card source provenance and processing freshness

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add compact source provenance and last-processed timestamps to calendar activity entries.
• Render source label, overlap summary, and “Processed X ago” on web and mobile cards.
• Add unit + real-ClickHouse integration coverage to keep provenance/freshness consistent
 end-to-end.
Diagram

graph TD
CH[("ClickHouse") ] --> Repo["ActivitiesCalendarRepository"] --> API["calendarRouter"] --> Web["Web ActivityCard"]
API --> Mobile["Mobile ActivitiesScreen"]
Repo --> Model["buildActivityListSource"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Send full source-decision detail to list cards
  • ➕ Avoids maintaining a second (compact) representation
  • ➕ Allows richer UI later without API changes
  • ➖ Larger payload and more client-side rendering/wording logic
  • ➖ List UIs typically need stable, concise strings rather than full decision graphs
2. Compute provenance entirely on the client from raw source links
  • ➕ Keeps server DTOs smaller and more generic
  • ➕ Lets UI iterate on copy without server deploys
  • ➖ Requires exposing raw attribution/link data to clients (privacy and contract expansion)
  • ➖ Duplicates source-priority semantics across web/mobile and risks drift
3. Persist lastProcessedAt as a dedicated column in the read model
  • ➕ Simplifies queries and avoids repeating the greatest/coalesce expression
  • ➕ Can standardize freshness semantics across multiple endpoints
  • ➖ Adds write-path and backfill complexity
  • ➖ Harder to guarantee correctness if derived from multiple tables/sources

Recommendation: The PR’s approach (server-authored, compact provenance via a shared model helper + freshness derived from ClickHouse refreshed_at semantics) is the best tradeoff for consistency and contract stability. It centralizes source-priority semantics in one place and ships only what list cards need, while the added integration assertion helps prevent subtle drift between the repository query and surfaced lastProcessedAt.

Files changed (15) +450 / -5

Enhancement (5) +121 / -2
activities.tsxRender source pill, overlap summary, and processed-relative time on mobile cards +40/-0

Render source pill, overlap summary, and processed-relative time on mobile cards

• Adds a provenance row to the activity list card UI showing the primary source label and an optional relative processed time. Renders the overlap summary when present and introduces styles for the new elements.

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

activity-source-decision.tsIntroduce ActivityListSourceDetail and buildActivityListSource helper +28/-0

Introduce ActivityListSourceDetail and buildActivityListSource helper

• Adds a compact provenance DTO for list cards and a builder that reuses canonical source-decision semantics for overlap summaries. Ensures at least one source is reported even when sourceLinks are empty.

packages/server/src/models/activity-source-decision.ts

activities-calendar-repository.tsAdd provenance and lastProcessedAt to calendar entries (ClickHouse + Postgres paths) +26/-1

Add provenance and lastProcessedAt to calendar entries (ClickHouse + Postgres paths)

• Extends CalendarActivityEntry with source and lastProcessedAt. Updates ClickHouse query to compute last_processed_at from refreshed_at semantics, captures provider/source_name for canonical attribution, and builds source details using buildActivityListSource with provider registry lookup.

packages/server/src/repositories/activities-calendar-repository.ts

calendar.tsValidate provenance and lastProcessedAt in calendar API schema +8/-0

Validate provenance and lastProcessedAt in calendar API schema

• Adds Zod schema for the compact source provenance object and wires it into the calendarActivityEntrySchema alongside a nullable lastProcessedAt field.

packages/server/src/routers/calendar.ts

ActivityCardContent.tsxRender source pill, overlap summary, and processed-relative time on web cards +19/-1

Render source pill, overlap summary, and processed-relative time on web cards

• Extends ActivityCardData with source and lastProcessedAt fields and renders them in the card footer area. Uses formatRelativeTime to show relative freshness when available.

packages/web/src/components/ActivityCardContent.tsx

Tests (9) +280 / -3
activities.stories.tsxAdd provenance + freshness fields to mobile activity card stories +12/-0

Add provenance + freshness fields to mobile activity card stories

• Extends story fixture activity objects with server-authored source provenance (primarySourceLabel/sourceCount/overlapSummary) and lastProcessedAt timestamps to exercise the new UI rendering paths.

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

activities.test.tsxTest mobile rendering of provenance and relative processing freshness +42/-1

Test mobile rendering of provenance and relative processing freshness

• Updates activity fixtures to include source and lastProcessedAt fields. Adds a fake-timer-based assertion that overlap summaries and “Processed 1m ago” render correctly, and ensures timers are reset after each test.

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

activity-source-decision.test.tsAdd unit tests for compact list-card provenance builder +51/-1

Add unit tests for compact list-card provenance builder

• Introduces coverage for buildActivityListSource across single-source, multi-source overlap, custom primary source selection, and no-link fallback provider lookup scenarios.

packages/server/src/models/activity-source-decision.test.ts

activities-calendar-repository.test.tsVerify calendar repository returns provenance + lastProcessedAt and correct SQL +69/-0

Verify calendar repository returns provenance + lastProcessedAt and correct SQL

• Extends test fixtures to include provider/source fields and last_processed_at. Adds a focused test asserting returned CalendarActivityEntry includes computed provenance and freshness, and that the query uses the intended greatest/coalesce refreshed_at expression.

packages/server/src/repositories/activities-calendar-repository.test.ts

activity-visibility-consistency.integration.test.tsIntegration assert: calendar freshness matches ClickHouse refreshed_at semantics +35/-0

Integration assert: calendar freshness matches ClickHouse refreshed_at semantics

• Adds a ClickHouse query in the integration suite to compute last_processed_at using the same greatest/coalesce logic. Asserts the authorized activity’s returned source and that API lastProcessedAt matches the database-derived value.

packages/server/src/repositories/activity-visibility-consistency.integration.test.ts

calendar.test.tsUpdate calendar router tests for new response fields +18/-0

Update calendar router tests for new response fields

• Extends expected calendar activity entries to include source provenance and lastProcessedAt across mocked repository responses, ensuring API-level behavior stays aligned with repository output.

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

ActivityCardContent.stories.tsxAdd provenance + freshness fields to web activity card stories +12/-0

Add provenance + freshness fields to web activity card stories

• Updates ActivityCardData story fixtures to include source provenance and lastProcessedAt so Storybook reflects the new card metadata.

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

ActivityCardContent.test.tsxTest web rendering of provenance and relative processing freshness +35/-1

Test web rendering of provenance and relative processing freshness

• Adds fake-timer-driven assertions that the source pill, overlap summary, and “Processed 1m ago” render correctly. Ensures timers are restored after tests to avoid cross-test contamination.

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

ActivitiesPage.test.tsxUpdate activities page test fixtures for new card fields +6/-0

Update activities page test fixtures for new card fields

• Extends page-level activity fixtures to include source provenance and lastProcessedAt so existing rendering tests remain valid under the new ActivityCardData contract.

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

Documentation (1) +49 / -0
production-incident-baseline.mdDocument Docker Desktop AIO exhaustion blocking local integration runs +49/-0

Document Docker Desktop AIO exhaustion blocking local integration runs

• Adds an incident entry describing shared Docker VM AIO capacity exhaustion and its impact on local Compose-based integration validation. Captures symptoms, evidence, mitigation attempts, and follow-up risk reduction ideas.

docs/production-incident-baseline.md

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Mobile Preview

Scan to open on device:

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

Channel pr-2317
Deep Link dofek://preview/pr-2317
Commit 8e60c04

To test on device:

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

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

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for 8e60c04b are ready:

This comment updates automatically on each PR push.

@Asherlc

Asherlc commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@qodo-code-review

qodo-code-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Context used
✅ Compliance rules (platform): 202 rules

Grey Divider


Action required

1. Persisted cache shape crash ✓ Resolved 🐞 Bug ☼ Reliability
Description
ActivitiesScreen now unconditionally renders activity.source.primarySourceLabel, but mobile
restores persisted React Query data across app upgrades; restoring a pre-upgrade calendar.weekList
cache entry without source will throw at render time.
Code

packages/mobile/app/(tabs)/activities.tsx[R362-373]

+                      <View style={styles.provenanceRow}>
+                        <Text style={styles.sourcePill}>{activity.source.primarySourceLabel}</Text>
+                        {activity.lastProcessedAt &&
+                        formatRelativeTime(activity.lastProcessedAt) ? (
+                          <Text style={styles.processedAt}>
+                            Processed {formatRelativeTime(activity.lastProcessedAt)}
+                          </Text>
+                        ) : null}
+                      </View>
+                      {activity.source.overlapSummary ? (
+                        <Text style={styles.overlapSummary}>{activity.source.overlapSummary}</Text>
+                      ) : null}
Relevance

●●● Strong

Team often accepts defensive guards to prevent render/runtime crashes from unexpected cached/remote
data shapes.

PR-#2208
PR-#2209

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The app persists query cache keyed by a contract version; since the version is unchanged, older
cached calendar.weekList results can be restored. The new UI code dereferences
activity.source.primarySourceLabel directly, which will throw if that field is missing in restored
cached data.

packages/mobile/lib/mobile-query-persistence.ts[9-13]
packages/mobile/app/(tabs)/activities.tsx[106-125]
packages/mobile/app/(tabs)/activities.tsx[362-373]

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 persists React Query cache. This PR changes the expected `calendar.weekList` activity shape by adding required `source` and `lastProcessedAt` fields, and the UI now dereferences `activity.source.primarySourceLabel` without a null/undefined guard. If a user upgrades with an existing persisted cache (old activity objects lacking `source`), ActivitiesScreen can crash before the network refetch completes.

## Issue Context
- Persisted cache buster is based on `MOBILE_QUERY_CACHE_CONTRACT_VERSION`.
- The version is still `3`, so old caches will restore.

## Fix Focus Areas
- packages/mobile/lib/mobile-query-persistence.ts[9-13]
- packages/mobile/app/(tabs)/activities.tsx[106-125]
- packages/mobile/app/(tabs)/activities.tsx[362-373]

## What to change
1) Increment `MOBILE_QUERY_CACHE_CONTRACT_VERSION` (e.g., `3 -> 4`) to invalidate old persisted caches.
2) Add a defensive render guard in ActivitiesScreen so the UI doesn’t throw if `activity.source` is missing (e.g., conditional rendering or a fallback label) to protect against any future contract mismatch/corrupt cache scenarios.

(Optionally) Add a regression test that hydrates ActivitiesScreen with an older cached `weekList` response lacking `source` and asserts it renders without throwing.

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


2. Missing refreshed_at column ✓ Resolved 🐞 Bug ≡ Correctness
Description
ActivitiesCalendarRepository now computes last_processed_at using asum.refreshed_at, but the
analytics.activity_summary view does not select refreshed_at, so ClickHouse will throw an
unknown-identifier/unknown-column error and break weekList queries.
Code

packages/server/src/repositories/activities-calendar-repository.ts[R226-231]

+            toString(
+              greatest(
+                activity.refreshed_at,
+                coalesce(asum.refreshed_at, activity.refreshed_at)
+              )
+            ) AS last_processed_at,
Relevance

●●● Strong

Likely real production ClickHouse runtime error; team historically accepts ClickHouse query/schema
correctness fixes.

PR-#1591
PR-#1151

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The repository query now references coalesce(asum.refreshed_at, ...) while joining
analytics.activity_summary, but the view definition of analytics.activity_summary selects many
columns from activity_summary_rows and omits refreshed_at, so asum.refreshed_at cannot resolve
in ClickHouse.

packages/server/src/repositories/activities-calendar-repository.ts[201-233]
src/db/clickhouse-activity-summary.ts[52-96]
packages/server/src/repositories/activity-visibility-consistency.integration.test.ts[181-193]

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

## Issue description
`packages/server/src/repositories/activities-calendar-repository.ts` now references `asum.refreshed_at` while joining `analytics.activity_summary`. The underlying view definition for `analytics.activity_summary` does not project a `refreshed_at` column, so the query will fail at runtime.

## Issue Context
- `analytics.activity_summary_rows` has `refreshed_at`, but `analytics.activity_summary` (the view) currently omits it.
- This PR introduces a dependency on `activity_summary.refreshed_at` in both the repository query and an integration test query.

## Fix Focus Areas
- src/db/clickhouse-activity-summary.ts[52-96]
- packages/server/src/repositories/activities-calendar-repository.ts[201-233]
- packages/server/src/repositories/activity-visibility-consistency.integration.test.ts[181-193]
- packages/server/src/routers/clickhouse-integration-test-models.ts[373-411]

## What to change
Choose one of:
1) **Preferred (backwards compatible):** Add `refreshed_at` to the `analytics.activity_summary` view SELECT list (and keep the existing filtering). Then the repository’s `asum.refreshed_at` reference becomes valid.
2) **Alternative:** Change the repository (and integration test) join from `analytics.activity_summary` to `analytics.activity_summary_rows FINAL` (or join both) and filter `is_deleted = 0`, using the rows table’s `refreshed_at`.

Also update the ClickHouse integration test schema/model definitions so the test analytics table for `activity_summary` includes `refreshed_at`, otherwise integration tests will still fail even after fixing the production SQL.

ⓘ 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/server/src/repositories/activities-calendar-repository.ts
Comment thread packages/mobile/app/(tabs)/activities.tsx
Distinguish missing link attribution from an empty matched set so hidden activity provenance remains mutation-verifiable.
@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.

Project activity-summary refresh timestamps through the compatibility view and invalidate persisted mobile data with the previous calendar response shape.
@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 commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Addressed both Qodo findings in ee247e0:

  • Projected refreshed_at from analytics.activity_summary_rows through the compatibility view, added migration 0064_activity_summary_freshness to recreate the deployed view, and updated the isolated ClickHouse test schema/read-model.
  • Bumped MOBILE_QUERY_CACHE_CONTRACT_VERSION from 3 to 4 so persisted calendar.weekList data with the old required-field shape is discarded.

I intentionally did not add a missing-source UI fallback: the repository forbids compatibility branches that hide contract mismatches, and the cache contract bump is the canonical migration. Focused tests, root typecheck, lint:sandbox, and targeted mutation checks pass.

@Asherlc
Asherlc enabled auto-merge (squash) July 29, 2026 23:06
@Asherlc
Asherlc merged commit 49b785e into main Jul 29, 2026
106 checks passed
@Asherlc
Asherlc deleted the issue-2123-activity-card-provenance branch July 29, 2026 23:07
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.

[ACT-05] Activity list cards omit source and last-processed state

2 participants