Skip to content

fix: reduce Convex moderation churn causing excessive bandwidth and action compute#48

Merged
Simplereally merged 5 commits intomainfrom
codex/convex-remediation-migration
Mar 13, 2026
Merged

fix: reduce Convex moderation churn causing excessive bandwidth and action compute#48
Simplereally merged 5 commits intomainfrom
codex/convex-remediation-migration

Conversation

@Simplereally
Copy link
Copy Markdown
Owner

@Simplereally Simplereally commented Mar 13, 2026

Summary

This fixes the moderation recovery path that was driving runaway Convex usage.

In convex/contentAnalysis.ts, recovery could keep rescheduling itself every ~2 seconds when providers were rate-limited, and multiple scheduled runs could overlap. This change makes recovery wait until provider reset windows and adds deduped scheduling so stale or overlapping runs no-op instead of fanning out.

In convex/generatedImages.ts and convex/schema.ts, getRecoverableUnanalyzedImages was scanning broad unresolved-image ranges and filtering most rows after reading them, which drove excessive database bandwidth. This change adds an index for recoverable pending moderation work and makes the query read that index directly, leaving only a narrow legacy fallback path.

In workers/bloomstudio-worker/src/moderation.ts and convex/contentAnalysis.ts, moderation jobs were doing an extra claim/continue round-trip before work could start. This change returns the prompt or image URL directly from claim so the worker can begin immediately with fewer Convex calls.

Validation

  • bun run typecheck
  • bun run test -- convex/contentAnalysis.test.ts

Summary by CodeRabbit

  • New Features

    • Added background job scheduling for content analysis runs
    • Added provider health status querying capability
    • Added batch normalization for legacy moderation states
  • Improvements

    • Enhanced moderation claim responses with optional prompt and image URL fields
    • Implemented provider recovery delay calculations based on provider health status
    • Optimized content analysis scheduling logic with indexed queries

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Mar 13, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
bloomstudio Ignored Ignored Preview Mar 13, 2026 1:41am

@sourcery-ai

This comment was marked as spam.

@Simplereally Simplereally force-pushed the codex/convex-remediation-migration branch from 4106e26 to db9e88d Compare March 13, 2026 01:11
sourcery-ai[bot]

This comment was marked as outdated.

@Simplereally Simplereally changed the title Reduce Convex moderation churn fix: reduce Convex moderation churn causing excessive bandwidth and action compute Mar 13, 2026
Comment thread convex/contentAnalysis.ts
Comment thread convex/contentAnalysis.ts Outdated
Comment thread workers/bloomstudio-worker/src/types.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
convex/contentAnalysis.test.ts (1)

9-73: Please add direct coverage for the new scheduler state machine.

These helper assertions are good, but the churn fix in this PR lives in scheduleAnalyzeRecentImagesRun() / claimScheduledAnalyzeRecentImagesRun(). I’d add cases for “later run ignored”, “earlier run replaces token”, and “stale token no-ops” so the dedupe behavior has direct regression coverage.

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

In `@convex/contentAnalysis.test.ts` around lines 9 - 73, Add direct unit tests
for the scheduler state machine around scheduleAnalyzeRecentImagesRun and
claimScheduledAnalyzeRecentImagesRun: add three tests that (1) schedule a run,
then attempt to schedule a later run and assert the later run is ignored (the
original token/time remains), (2) schedule a run then schedule an earlier run
and assert the earlier run replaces the existing token/time, and (3) simulate a
stale token (e.g., claim with an old timestamp or after the run has been
processed) and assert claimScheduledAnalyzeRecentImagesRun becomes a no-op and
does not re-schedule or mutate state; use the same helper setup used by existing
tests to create provider health/queuedImage state and assert final scheduler
state (token/timestamp) and return values from
scheduleAnalyzeRecentImagesRun/claimScheduledAnalyzeRecentImagesRun to validate
dedupe behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@convex/contentAnalysis.ts`:
- Around line 132-147: getProviderRecoveryDelayMs currently returns null when
there are unavailable providers but none have a future rateLimitedUntil, which
stalls scheduling; change it so that if any providerHealths entries are present
and not isAvailable but unavailableResets is empty, the function returns
DELAY_BETWEEN_REQUESTS_MS (instead of null). Locate getProviderRecoveryDelayMs
and its usage of providerHealths / ProviderHealthSnapshot / isAvailable /
rateLimitedUntil, detect the case where unavailable providers exist but no
numeric reset times, and return DELAY_BETWEEN_REQUESTS_MS so analyzeRecentImages
will reschedule retries rather than stopping.

In `@convex/generatedImages.ts`:
- Around line 1196-1209: The fallback query storing legacyUndefinedSensitivity
uses ctx.db.query("generatedImages").filter(...) with
q.eq(q.field("isSensitive"), undefined) which forces a table-scan; fix by making
this path indexable — either backfill legacy rows so isSensitive is explicitly
set (e.g., null) and then change the query to use q.eq(q.field("isSensitive"),
null) (or another indexed sentinel) or add a dedicated indexed flag (e.g.,
legacyRecoveryNeeded) and query on that field instead; update the code that
computes legacyUndefinedSensitivity and any recovery loop to rely on the indexed
condition (and run a one-time backfill job to mutate existing rows) so the query
avoids full-table scans.

---

Nitpick comments:
In `@convex/contentAnalysis.test.ts`:
- Around line 9-73: Add direct unit tests for the scheduler state machine around
scheduleAnalyzeRecentImagesRun and claimScheduledAnalyzeRecentImagesRun: add
three tests that (1) schedule a run, then attempt to schedule a later run and
assert the later run is ignored (the original token/time remains), (2) schedule
a run then schedule an earlier run and assert the earlier run replaces the
existing token/time, and (3) simulate a stale token (e.g., claim with an old
timestamp or after the run has been processed) and assert
claimScheduledAnalyzeRecentImagesRun becomes a no-op and does not re-schedule or
mutate state; use the same helper setup used by existing tests to create
provider health/queuedImage state and assert final scheduler state
(token/timestamp) and return values from
scheduleAnalyzeRecentImagesRun/claimScheduledAnalyzeRecentImagesRun to validate
dedupe behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20bf2514-6263-4731-82ab-86e904bb4802

📥 Commits

Reviewing files that changed from the base of the PR and between 8110fcb and db9e88d.

⛔ Files ignored due to path filters (1)
  • convex/_generated/api.d.ts is excluded by !**/_generated/**
📒 Files selected for processing (8)
  • convex/contentAnalysis.test.ts
  • convex/contentAnalysis.ts
  • convex/crons.ts
  • convex/generatedImages.ts
  • convex/lib/providerHealthFunctions.ts
  • convex/schema.ts
  • workers/bloomstudio-worker/src/moderation.ts
  • workers/bloomstudio-worker/src/types.ts
💤 Files with no reviewable changes (1)
  • workers/bloomstudio-worker/src/types.ts

Comment thread convex/contentAnalysis.ts
Comment thread convex/generatedImages.ts Outdated
Repository owner deleted a comment from chatgpt-codex-connector Bot Mar 13, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 13, 2026
Repository owner deleted a comment from coderabbitai Bot Mar 13, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 13, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec2ee63f-3dda-44f4-ae58-0b6cd1226102

📥 Commits

Reviewing files that changed from the base of the PR and between db9e88d and 7e0b573.

📒 Files selected for processing (8)
  • convex/contentAnalysis.test.ts
  • convex/contentAnalysis.ts
  • convex/generatedImages.test.ts
  • convex/generatedImages.ts
  • convex/schema.ts
  • tsconfig.json
  • workers/bloomstudio-worker/src/secondary-assets.ts
  • workers/bloomstudio-worker/src/types.ts

📝 Walkthrough

Walkthrough

This PR implements background job scheduling for content analysis with provider health-aware recovery delays, introduces legacy moderation state normalization with batch processing, refactors the worker moderation claim flow to return full response objects, and adds supporting database schema indexes and type infrastructure.

Changes

Cohort / File(s) Summary
Content Analysis Scheduling
convex/contentAnalysis.ts, convex/contentAnalysis.test.ts
Added four new public functions: getProviderRecoveryDelayMs (computes delay from provider health), shouldSkipAnalyzeRecentImagesSchedule (scheduling decisions), getEffectiveScheduledBackgroundJob (selects best job), and getLatestBackgroundJobLastRunAt (retrieves last run). Updated getNextAnalysisRunDelayMs signature to accept providerRecoveryDelayMs instead of allProvidersRateLimited. Extended analyzeRecentImages with optional scheduleToken parameter and provider health-based recovery scheduling. Added two new mutations: scheduleAnalyzeRecentImagesRun and claimScheduledAnalyzeRecentImagesRun for delayed recovery management.
Provider Health & Cron Setup
convex/lib/providerHealthFunctions.ts, convex/crons.ts
Added getAllHealth query to fetch provider health for groq and openrouter in parallel. Updated analyze unanalyzed images cron registration with additional parameter.
Database Schema
convex/schema.ts
Added two composite indexes on generatedImages (by_sensitivity_moderation_status and by_moderation_status_sensitivity) for optimized querying. Introduced new backgroundJobState table with fields for jobName, nextRunAt, scheduledToken, lastRunAt, and updatedAt, plus two indexes for efficient lookups.
Legacy Moderation Normalization
convex/generatedImages.ts, convex/generatedImages.test.ts
Added GeneratedImageLegacyModerationState type and getLegacyModerationBackfillPatch helper function to compute patches for missing moderation fields. Introduced normalizeLegacyModerationStateBatch mutation for bulk backfill processing (limit 0–64). Refactored getRecoverableUnanalyzedImages and getUnanalyzedImages to use indexed queries instead of iterative pagination.
Worker Moderation Refactoring
workers/bloomstudio-worker/src/moderation.ts
Removed ContinueModerationResponse type and continueModerationJob flow. Changed claimModerationJob to return full ClaimModerationResponse (including claimed, optional prompt, optional imageUrl) instead of boolean. Updated handlePromptInferenceMessage and handleVisionAnalysisMessage to consume claim properties directly, simplifying control flow.
Type System & Infrastructure
workers/bloomstudio-worker/src/types.ts, workers/bloomstudio-worker/src/secondary-assets.ts, tsconfig.json
Replaced global RequestInit augmentation with exported types CloudflareRequestInitCfOptions and WorkerRequestInit. Updated secondary-assets.ts to use WorkerRequestInit. Extended claimModerationForWorker return signature to include optional prompt and imageUrl fields. Excluded worker-configuration.d.ts from TypeScript compilation.

Sequence Diagram(s)

No sequence diagrams generated. While the changes introduce new background job scheduling features, the interactions are primarily internal decision logic and state management rather than multi-component sequential flows that would benefit from visualization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Schedules hop through meadows green,
Recovery delays seen,
Moderation claims now complete—
No more endpoints, clean and neat!
Background jobs keep the rhythm true,
Provider health guides what's to do. 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary objective: reducing excessive Convex moderation churn by implementing background job scheduling, provider health-aware recovery delays, and direct prompt/imageUrl returns from claims to eliminate redundant round-trips.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/convex-remediation-migration
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

@Simplereally Simplereally merged commit a809c83 into main Mar 13, 2026
4 of 5 checks passed
@Simplereally Simplereally deleted the codex/convex-remediation-migration branch March 13, 2026 01:43
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