Skip to content

fix enrichment bach - atomic fact extraction - #21

Merged
flvvius merged 3 commits into
mainfrom
fix/enrichment
Apr 30, 2026
Merged

fix enrichment bach - atomic fact extraction#21
flvvius merged 3 commits into
mainfrom
fix/enrichment

Conversation

@flvvius

@flvvius flvvius commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added diagnostic tools to monitor enrichment pipeline health and coverage metrics
    • Introduced backfill functionality with pagination and budget controls for missing data
  • Improvements

    • Enhanced retry mechanisms for failed and deferred enrichment tasks with attempt caps
    • Improved status tracking with attempt counters and last-attempt timestamps
    • Switched from single-pass to chunked processing for more efficient resource usage

@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 5:32pm
news-web Ready Ready Preview, Comment Apr 30, 2026 5:32pm

@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 40 minutes and 49 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7c531bf3-50f1-436e-b44a-e1ec9304edff

📥 Commits

Reviewing files that changed from the base of the PR and between 084fb58 and 7dd813e.

📒 Files selected for processing (8)
  • packages/backend/convex/aiBudget.ts
  • packages/backend/convex/claimDivergenceNode.ts
  • packages/backend/convex/config.ts
  • packages/backend/convex/enrichmentNode.ts
  • packages/backend/convex/lib/aiCall.ts
  • packages/backend/convex/lib/articleExtraction.ts
  • packages/backend/convex/schema.ts
  • packages/backend/convex/summarizationNode.ts
📝 Walkthrough

Walkthrough

The PR enhances the article enrichment pipeline by splitting combined AI status validators into separate fact and bias validators, introducing attempt-capped retry logic with deferral mechanics, and refactoring fact extraction and bias detection processing from single-shot to chunked operations with budget re-checks. New diagnostic queries and schema fields enable pipeline funnel visibility and attempt tracking.

Changes

Cohort / File(s) Summary
Status Validators & Core Mutations
packages/backend/convex/enrichment.ts
Splits ARTICLE_AI_STATUS_VALIDATOR into separate ARTICLE_FACT_STATUS_VALIDATOR (pending/deferred/succeeded/succeeded_empty/failed/skipped) and ARTICLE_BIAS_STATUS_VALIDATOR (deferred/succeeded/failed/skipped). Adds three new internal mutations: claimArticlesNeedingFactExtraction (claims candidates with lease/state/attempt tracking), deferArticleFactExtraction, and deferArticleBiasDetection (both move work to deferred, clear leases, increment attempt counters, store truncated errors). Updates markArticleEnriched to accept new status validators and track retry attempts/timestamps; suppresses updates when both prior and new status are succeeded_empty.
Article Processing & Backfill
packages/backend/convex/enrichmentNode.ts
Refactors fact extraction and bias detection from single-shot processing to chunked operations with per-chunk budget re-checks. Changes budget-exhaustion behavior from marking failed to deferring with deferred status. Handles LLM omissions as deferred (vs. prior failed) and introduces succeeded_empty fact status. Skips bias scoring for articles with deferred fact status. Adds previousStatus to claimed article data. Introduces new backfillAtomicFacts internal action for pagination-based backfill with budget/batching controls.
Pipeline Diagnostics
packages/backend/convex/pipelineDiagnostics.ts
Adds new diagnostic module with two internalQuery endpoints: eventAiFunnel (bounds time window/limit, computes funnel stages from published → 3-article coverage → claimAnalyzed, includes samples for missing stages) and articleFactExtractionFunnel (computes distribution maps for status/factExtractionStatus/extractionQuality, returns samples for articles lacking atomic facts).
Schema Updates
packages/backend/convex/schema.ts
Extends articles.factExtractionStatus to include "pending", "deferred", "succeeded_empty". Adds factExtractionAttempts and factExtractionLastAttemptAt optional fields. Updates articles.biasDetectionStatus to include "deferred". Adds biasDetectionAttempts and biasDetectionLastAttemptAt optional fields.

Sequence Diagram(s)

sequenceDiagram
    participant Scheduler as Scheduler/Runner
    participant Backend as Backend Service
    participant DB as Database
    participant LLM as LLM Service
    participant Budget as Budget Manager

    Scheduler->>Backend: Trigger enrichment run
    Backend->>DB: claimArticlesNeedingFactExtraction<br/>(limit, leaseExpiresAt, beforePublishedAt,<br/>includeFailed, includeSucceededEmpty)
    DB-->>Backend: Return claimed articles batch
    
    Backend->>Backend: Split into chunks (chunkArray)
    
    loop For Each Chunk
        Backend->>Budget: Check budget remaining
        alt Budget available
            Backend->>LLM: Extract facts from chunk
            LLM-->>Backend: Fact extraction results
            
            Backend->>DB: markArticleEnriched<br/>(factExtractionStatus, attempts++)
            
            alt All facts extracted
                Backend->>Backend: Prepare for bias detection
                Backend->>LLM: Score bias from chunk
                LLM-->>Backend: Bias detection results
                Backend->>DB: markArticleEnriched<br/>(biasDetectionStatus, attempts++)
            else LLM omitted articles
                Backend->>DB: deferArticleFactExtraction<br/>(deferred, reason)
                Note over Backend: Skip bias for deferred articles
            end
        else Budget exhausted
            Backend->>DB: deferArticleFactExtraction<br/>(deferred reason, analyzedAt)
            Note over Backend: Remaining chunks deferred for retry
            Backend->>Backend: Return control, signal retry needed
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #9 — Introduces core enrichment pipeline and article schema that this PR builds upon and significantly modifies (enrichment.ts, schema fields).
  • PR #18 — Modifies same enrichment pipeline files (enrichment.ts, enrichmentNode.ts) with overlapping mutations and fact/bias-status handling logic.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'fix enrichment bach - atomic fact extraction' is vague and contains unclear terminology. 'bach' appears to be a typo or abbreviation that doesn't convey meaningful information about the changeset, which involves substantial refactoring of status validators, reenrichment eligibility logic, new mutations/actions, and diagnostic endpoints. Clarify the title by removing unclear terms like 'bach' and making it more specific about the main change, e.g., 'Refactor enrichment status handling and add retry logic for fact extraction' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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/enrichment

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 40 minutes and 49 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: 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/pipelineDiagnostics.ts`:
- Around line 91-155: The per-event loop in pipelineDiagnostics (the for (const
event of events) loop) issues queries for "articles" and "eventClaims" per event
and can be very slow for large event sets; add a clear doc comment at the top of
the pipelineDiagnostics routine (or immediately above the loop) stating this
function is intended for ad-hoc/diagnostic use only and may be slow for many
events, and either (a) add a configurable maxEvents parameter/default (e.g.,
maxEvents = 1000) and early-return or truncate when events.length > maxEvents,
or (b) document that callers must batch/paginate and not call this frequently;
reference the loop, the articles and eventClaims queries, stageEventIds, and
samples when documenting so future readers know which operations are expensive.
🪄 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: 08e6395f-f64f-4da8-bbbe-ef789851aef4

📥 Commits

Reviewing files that changed from the base of the PR and between 0bf4740 and 084fb58.

⛔ Files ignored due to path filters (1)
  • packages/backend/convex/_generated/api.d.ts is excluded by !**/_generated/**, !**/_generated/**
📒 Files selected for processing (4)
  • packages/backend/convex/enrichment.ts
  • packages/backend/convex/enrichmentNode.ts
  • packages/backend/convex/pipelineDiagnostics.ts
  • packages/backend/convex/schema.ts

Comment on lines +91 to +155
for (const event of events) {
stageEventIds.published.add(event._id);

const articles = await ctx.db
.query("articles")
.withIndex("by_event", (q) => q.eq("eventId", event._id))
.collect();
const sourceCount = new Set(articles.map((article) => article.sourceId))
.size;
const factualArticles = articles.filter(hasAtomicFacts);
const factualSourceCount = new Set(
factualArticles.map((article) => article.sourceId),
).size;

if (articles.length >= 3) stageEventIds.article3.add(event._id);
if (articles.length >= 3 && sourceCount >= 2) {
stageEventIds.source2.add(event._id);
} else if (samples.missingArticleCoverage.length < 10) {
samples.missingArticleCoverage.push({
eventId: event._id,
title: event.title,
articleCount: articles.length,
sourceCount,
});
}

if (articles.length >= 3 && sourceCount >= 2 && factualArticles.length >= 3) {
stageEventIds.factualArticle3.add(event._id);
}
if (
articles.length >= 3 &&
sourceCount >= 2 &&
factualArticles.length >= 3 &&
factualSourceCount >= 2
) {
stageEventIds.factualSource2.add(event._id);
} else if (
articles.length >= 3 &&
sourceCount >= 2 &&
samples.missingFactualCoverage.length < 10
) {
samples.missingFactualCoverage.push({
eventId: event._id,
title: event.title,
articleCount: articles.length,
sourceCount,
factualArticleCount: factualArticles.length,
factualSourceCount,
});
}

if (hasPerspectiveSummary(event)) {
stageEventIds.summarized.add(event._id);
}
if (event.lastClaimAnalysisAt) {
stageEventIds.claimAnalyzed.add(event._id);
}

const hasClaimRows = Boolean(
await ctx.db
.query("eventClaims")
.withIndex("by_event", (q) => q.eq("eventId", event._id))
.first(),
);
if (hasClaimRows) stageEventIds.hasClaims.add(event._id);

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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider performance implications for large event sets.

The loop queries articles and potentially eventClaims for each event (up to 1000 events). While acceptable for an internal diagnostic query, be aware this could be slow with many events. Consider adding documentation noting this is intended for ad-hoc diagnostics rather than frequent automated calls.

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

In `@packages/backend/convex/pipelineDiagnostics.ts` around lines 91 - 155, The
per-event loop in pipelineDiagnostics (the for (const event of events) loop)
issues queries for "articles" and "eventClaims" per event and can be very slow
for large event sets; add a clear doc comment at the top of the
pipelineDiagnostics routine (or immediately above the loop) stating this
function is intended for ad-hoc/diagnostic use only and may be slow for many
events, and either (a) add a configurable maxEvents parameter/default (e.g.,
maxEvents = 1000) and early-return or truncate when events.length > maxEvents,
or (b) document that callers must batch/paginate and not call this frequently;
reference the loop, the articles and eventClaims queries, stageEventIds, and
samples when documenting so future readers know which operations are expensive.

@flvvius
flvvius merged commit d369eff into main Apr 30, 2026
2 of 3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request May 9, 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