Skip to content

harden ingestion & clustering - #22

Merged
flvvius merged 7 commits into
mainfrom
fix/ingestion-clustering
Apr 30, 2026
Merged

harden ingestion & clustering#22
flvvius merged 7 commits into
mainfrom
fix/ingestion-clustering

Conversation

@flvvius

@flvvius flvvius commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes

    • Improved image fallback so event images are preserved when candidate images are absent
    • Expanded duplicate-article detection to cover more processing states
    • More robust handling of malformed published dates during ingestion
    • Cleaner merge cleanup removing additional leftover records
  • Improvements

    • Topic-aware clustering and match scoring with refined similarity/merge thresholds
    • Bounded recency tie-breaker for presentation ranking
    • Consistent fixed-dimension embedding handling and mean calculations
    • Better URL/article normalization and indexing for faster queries
    • Seeding now reports created/updated/unchanged counts and selectively patches defaults

@vercel

vercel Bot commented Apr 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
news Error Error Apr 30, 2026 8:08pm
news-web Ready Ready Preview, Comment Apr 30, 2026 8:08pm

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@flvvius has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 26 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 315ef223-fd0c-4953-be61-b7ddcebefb97

📥 Commits

Reviewing files that changed from the base of the PR and between f8b3efc and 13f351d.

📒 Files selected for processing (3)
  • apps/web/src/routes/index.tsx
  • packages/backend/convex/clustering.ts
  • packages/backend/convex/config.ts

Walkthrough

Adds topic-aware event clustering and scoring, preserves AI-derived perspective summaries via provenance fields, fixes embedding dimensions with a helper, tightens ingestion (publishedAt parsing, source creation), makes singleton recluster locking configurable, and improves merge cleanup and presentation recency handling.

Changes

Cohort / File(s) Summary
Topic-Aware Clustering & Presentation
packages/backend/convex/clustering.ts
Threads topicSlugs through candidate generation, scoring, near-duplicate merging, and singleton reclustering; integrates topic overlap into acceptance gates and match scoring; updates merge/presentation behavior to preserve AI perspectiveSummaries via perspectiveSource, lastSummarizedAt, lastSummarySignature; uses bounded recency tie-breaker; falls back to event image when candidate lacks image; makes pipeline locking configurable; queues/sorts unmatched articles as pending before creating new events; deletes additional related rows on merge.
Embedding Helper & Avg Maintenance
packages/backend/convex/clustering.ts, packages/backend/convex/ingestion.ts
Refactors event embedding maintenance into appendArticleEmbeddingToEventMean and ensures consistent embedding shape/padding when attaching article embeddings.
Ingestion: Embeddings, Dates, Sources, Normalization
packages/backend/convex/ingestion.ts
Introduces fixed-dimension event embeddings (1536) with toEventEmbedding padding/truncation; adds parsePublishedAt and stores parsedPublishedAt, filters old articles using parsed epoch; uses parsedPublishedAt ?? Date.now() for stored articles.publishedAt; adds getOrCreateSource internalMutation; includes processing events in duplicate cleanup; tweaks URL/headline normalization and tracking-parameter removal.
Configuration Tuning & Seeding Behavior
packages/backend/convex/config.ts
Adjusts clustering/merge thresholds and time window defaults; simplifies some descriptions; changes seeding to patch only forcedDefaultKeys (update value/description when different) and report created/updated/unchanged counts.
Schema Changes & Indexes
packages/backend/convex/schema.ts
Adds optional `events.perspectiveSource?: "heuristic"
Summarization Provenance
packages/backend/convex/summarization.ts
applyEventSummaryResult now sets event.perspectiveSource = "ai" when applying AI-generated perspective summaries.
Merge Cleanup & Queries
packages/backend/convex/clustering.ts, packages/backend/convex/schema.ts
Extends merge cleanup to delete eventShareAssets, eventSummaryJobs, eventClaims and switches userInsights lookup to the new by_event index instead of full-table scans.

Sequence Diagram

sequenceDiagram
    actor Ingest as Article Ingestion
    participant Embed as Embedding Service
    participant Cluster as Clustering Engine
    participant Merge as Merge/Attach Logic
    participant Present as Presentation Refresh
    participant DB as Convex DB

    Ingest->>Embed: parse article, compute embedding, parsePublishedAt
    Embed->>Embed: normalize/pad to 1536 dims (toEventEmbedding)
    Embed-->>Cluster: deliver article + topics + fixed-dim embedding

    Cluster->>Cluster: generate topic-aware candidates
    Cluster->>Cluster: score by similarity + topic overlap
    Cluster->>Merge: select best candidate or mark pending

    alt Candidate Match
        Merge->>Merge: check time-window & similarity gates
        Merge->>Merge: respect perspectiveSource (AI-preservation)
        Merge->>DB: update event embedding (appendArticleEmbeddingToEventMean)
        Merge->>DB: delete related rows (eventShareAssets, eventSummaryJobs, eventClaims) if removed
    else No Match
        Cluster->>DB: queue as pending, retry attach sorted by seed quality, then create new event
    end

    Merge-->>Present: event ready
    Present->>DB: refresh presentation using bounded recency tie-breaker
    Present->>DB: update perspectiveSource, lastSummarizedAt, lastSummarySignature as needed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'harden ingestion & clustering' is directly related to the main changes which strengthen ingestion and clustering logic across multiple systems, including configuration tuning, embedding handling, duplicate cleanup, and similarity/matching improvements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ingestion-clustering

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
Review rate limit: 0/1 reviews remaining, refill in 38 minutes and 26 seconds.

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/backend/convex/config.ts (1)

637-703: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

These new thresholds won't reach existing deployments.

seedDefaults is insert-only, so any environment that already has these config rows will keep the old values after this PR. That means the hardening here (clustering_*, merge_max_time_delta_hours, singleton_recluster_min_similarity) only applies to fresh installs unless you add a migration or targeted upsert for existing keys.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/backend/convex/config.ts` around lines 637 - 703, seedDefaults is
insert-only so existing deployments won't get the new thresholds; modify the
seed step to perform an upsert/update for the specific keys rather than only
inserting. Update the seeding logic that populates seedDefaults to detect
existing rows by key (e.g., "clustering_weak_extraction_min_similarity",
"clustering_weak_extraction_strong_similarity", "merge_max_time_delta_hours",
"singleton_recluster_min_similarity", "clustering_min_similarity",
"cluster_publish_min_articles", "cluster_publish_min_sources",
"topic_inference_*", "merge_*") and apply a targeted upsert or migration that
updates those keys to the new values while leaving other keys intact (or create
a one-off migration script that updates only these config keys). Ensure the code
path that runs during deployment calls this upsert/migration instead of relying
on insert-only seedDefaults so existing environments receive the hardened
values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/backend/convex/clustering.ts`:
- Around line 2934-2936: The merge currently preserves mergedPerspectiveSource
=== "ai" but drops AI-summary metadata; update the merge logic handling
mergedPerspectiveSource and all merge call sites (the two merge callsites
referenced and the merge function in clustering.ts) to also carry forward the
most-recent/non-empty lastSummarizedAt and lastSummarySignature values when the
mergedPerspectiveSource is "ai" (or when the incoming/recipient has newer
summary metadata), so shouldResummarize() in summarization.ts sees current
timestamps/signatures; pick the newest lastSummarizedAt and the corresponding
lastSummarySignature (or prefer non-empty signature) and propagate them in the
merged event payload.
- Around line 60-61: The fixed epoch makes the recency clamp stale; replace the
hard constants PRESENTATION_RECENCY_EPOCH_MS and PRESENTATION_RECENCY_HORIZON_MS
with a relative computation so recency is computed against a dynamic reference
(e.g., Date.now() or the newest candidate timestamp). Implement a function like
computePresentationRecency(publishedAt, referenceTime = Date.now(), horizonMs =
365*24*60*60*1000) that returns a clamped 0..1 score using referenceTime -
publishedAt normalized by horizonMs, and update all uses of
PRESENTATION_RECENCY_EPOCH_MS/PRESENTATION_RECENCY_HORIZON_MS (the recency
scoring calls and the branches referenced in the diff) to call this function so
recent items retain discrimination over time.

---

Outside diff comments:
In `@packages/backend/convex/config.ts`:
- Around line 637-703: seedDefaults is insert-only so existing deployments won't
get the new thresholds; modify the seed step to perform an upsert/update for the
specific keys rather than only inserting. Update the seeding logic that
populates seedDefaults to detect existing rows by key (e.g.,
"clustering_weak_extraction_min_similarity",
"clustering_weak_extraction_strong_similarity", "merge_max_time_delta_hours",
"singleton_recluster_min_similarity", "clustering_min_similarity",
"cluster_publish_min_articles", "cluster_publish_min_sources",
"topic_inference_*", "merge_*") and apply a targeted upsert or migration that
updates those keys to the new values while leaving other keys intact (or create
a one-off migration script that updates only these config keys). Ensure the code
path that runs during deployment calls this upsert/migration instead of relying
on insert-only seedDefaults so existing environments receive the hardened
values.
🪄 Autofix (Beta)

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

Run ID: c2137425-f483-4cd0-aa4c-830a5ecf263a

📥 Commits

Reviewing files that changed from the base of the PR and between d369eff and a1be5ec.

📒 Files selected for processing (5)
  • packages/backend/convex/clustering.ts
  • packages/backend/convex/config.ts
  • packages/backend/convex/ingestion.ts
  • packages/backend/convex/schema.ts
  • packages/backend/convex/summarization.ts

Comment thread packages/backend/convex/clustering.ts Outdated
Comment thread packages/backend/convex/clustering.ts

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/backend/convex/config.ts`:
- Line 637: The default for clustering_same_source_min_similarity was updated
but not added to the forced reseed allowlist, so existing DB rows won't be
overwritten by seedDefaults; update the forcedDefaultKeys array used by
seedDefaults to include "clustering_same_source_min_similarity" (the same key
string used in the defaults) so that seedDefaults will force-reseed that setting
for existing environments; locate the forcedDefaultKeys definition and add the
key alongside the other entries (also ensure the same change is applied in the
second block referenced around the other occurrence).
🪄 Autofix (Beta)

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

Run ID: 548446cc-8a66-4187-b4c8-514d0ba9434c

📥 Commits

Reviewing files that changed from the base of the PR and between a1be5ec and f8b3efc.

📒 Files selected for processing (2)
  • packages/backend/convex/clustering.ts
  • packages/backend/convex/config.ts

Comment thread packages/backend/convex/config.ts
@flvvius
flvvius merged commit fdf4a9b into main Apr 30, 2026
2 of 4 checks passed
This was referenced May 7, 2026
@coderabbitai coderabbitai Bot mentioned this pull request May 31, 2026
This was referenced Jul 7, 2026
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.

1 participant