Skip to content

Finish coderouter billing operations and telemetry - #9732

Merged
lawrencecchen merged 3 commits into
mainfrom
feat/coderouter-private-beta-100
Aug 7, 2026
Merged

lawrencecchen merged 3 commits into
mainfrom
feat/coderouter-private-beta-100

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Adds hourly Stripe/RDS reconciliation, delayed-event repair, refund and checkout-start analytics, internal runbooks and benchmark tooling, bounded retries/concurrency, privacy-safe Sentry breadcrumbs, and deterministic coverage.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Completes coderouter billing operations and telemetry for the private beta. Adds serialized hourly Stripe↔RDS reconciliation, hardened webhooks (including refunds), privacy‑safe checkout/refund analytics, and lightweight ops tooling.

  • New Features

    • Hourly reconciliation cron /api/cron/billing-reconcile (Bearer CRON_SECRET) runs under a global advisory lock to serialize cron/operator runs, uses per-subscription cursor last_reconciled_at, bounded concurrency, and CLI bun coderouter:reconcile-billing with --dry-run; exits nonzero on failures/truncation; returns 503 with Retry-After; scheduled at minute 23 in vercel.json.
    • Webhook always re-fetches the current Stripe subscription; handles charge.refunded by joining invoice→subscription, records analytics, and does not revoke active access.
    • Checkout-start analytics from checkout routes are deferred via Next.js after() with a safe fallback; unified capture adds stable $insert_id, team grouping via $groups, and a single retry on 5xx only.
    • Benchmark harness bun coderouter:benchmark reports status counts, p50/p95/p99, and Server-Timing, and refuses to send route tokens to unapproved origins; runbook docs/coderouter-operations.md covers replay, reconciliation, latency evidence, and observability.
  • Bug Fixes

    • Prevents stale Stripe payloads from overwriting newer entitlements; Stripe is authoritative.
    • Stripe catalog provisioning uses /products/search with next_page and curl timeouts/retries; dev stack listens for charge.refunded.
    • Adds privacy-safe Sentry breadcrumb for reconciliation runs; analytics failures never affect billing paths.

Written for commit 10351a5. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Billing

    • Added automated Stripe subscription reconciliation with drift detection, repair, dry-run support, and failure reporting.
    • Scheduled recurring reconciliation with secure access controls.
    • Improved handling of refunded charges and stale subscription events to keep entitlements accurate.
    • Improved Stripe catalog provisioning and webhook configuration.
  • Observability

    • Added checkout-start and refund analytics with retries, deduplication, and privacy-safe event data.
  • Operations

    • Added benchmarking and billing-reconciliation command-line tools.
    • Added an operations runbook covering billing recovery, performance checks, and observability practices.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Stripe subscription reconciliation with protected cron and CLI entry points, updates checkout and webhook billing analytics, handles refunded charges, improves Stripe catalog provisioning, and adds a benchmark harness with an operations runbook.

Changes

Billing reconciliation

Layer / File(s) Summary
Reconciliation workflow
web/db/schema.ts, web/db/migrations/..., web/services/billing/reconcile.ts, web/tests/billing-reconcile.test.ts
Compares local and Stripe subscription state, repairs drift unless dry-run is enabled, limits concurrency, tracks reconciliation progress, and reports failures and truncation.
Protected execution and validation
web/app/api/cron/billing-reconcile/route.ts, web/scripts/coderouter/reconcile-billing.ts, web/vercel.json, web/package.json, docs/coderouter-operations.md, web/tests/billing-reconcile-route.test.ts
Adds authenticated cron and CLI execution, hourly scheduling, retryable failure responses, and operational procedures.

Stripe billing lifecycle

Layer / File(s) Summary
Billing analytics delivery
web/services/analytics/stripeBilling.ts, web/tests/stripe-billing-analytics.test.ts
Adds shared PostHog delivery with timeout and retry handling, checkout-started events, refund events, deterministic identifiers, and privacy-focused assertions.
Deferred checkout capture
web/app/api/billing/checkout/route.ts
Schedules Pro and Team checkout-started analytics after session creation without blocking redirects.
Current-state webhook processing
web/app/api/stripe/webhook/route.ts, web/tests/stripe-webhook-route.test.ts
Retrieves current subscriptions before entitlement updates and handles refunded charges through invoice and subscription resolution.
Refund event wiring
web/scripts/stripe/dev-stack.sh, web/scripts/stripe/provision-catalog.sh
Adds charge.refunded to local and provisioned webhook event lists.

Coderouter operations tooling

Layer / File(s) Summary
Latency benchmark harness
web/scripts/coderouter/benchmark.ts, web/tests/coderouter-benchmark.test.ts, web/package.json
Adds endpoint benchmarking with warmups, timeouts, status validation, latency percentiles, Server-Timing metrics, and JSON output.
Operational procedures
docs/coderouter-operations.md
Documents webhook replay, reconciliation, benchmarking, and privacy-safe observability procedures.

Stripe catalog provisioning

Layer / File(s) Summary
Catalog lookup and request resilience
web/scripts/stripe/provision-catalog.sh, web/tests/stripe-provision-catalog.test.ts
Adds Stripe request retries and timeouts, metadata-filtered product search pagination, identity validation, progress output, and matching tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant BillingReconcileRoute
  participant ReconcileService
  participant Database
  participant Stripe
  Scheduler->>BillingReconcileRoute: send authenticated GET request
  BillingReconcileRoute->>ReconcileService: start reconciliation
  ReconcileService->>Database: load local subscription snapshots
  ReconcileService->>Stripe: retrieve current subscriptions
  Stripe-->>ReconcileService: return provider state
  ReconcileService->>Stripe: repair detected drift
  ReconcileService-->>BillingReconcileRoute: return reconciliation result
  BillingReconcileRoute-->>Scheduler: return 200 or 503 response
Loading

Possibly related PRs


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux User-Facing Error Privacy ❌ Error The changed provisioning command prints upstream vendor details in new output: “Scanned Stripe products,” “Checked Stripe price,” and “Resolving ... Stripe catalog.” Remove provider-specific names and lookup-key or identifier details from command output. Use generic catalog messages and keep diagnostics in sanitized internal telemetry.
Cmux Full Internationalization ❌ Error The production cron API adds English response copy, "Billing reconciliation failed; retry the cron run.", without a locale source or catalog entries. Replace the hard-coded message with a locale-aware API response, and add matching translated entries to all 20 locale files under web/messages/.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description summarizes the changes but omits the required Testing, Demo Video, Review Trigger, and Checklist sections. Add the required template sections and provide testing details, manual verification, demo information when applicable, review triggers, and checklist status.
✅ Passed checks (21 passed)
Check name Status Explanation
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.
Cmux Swift Actor Isolation ✅ Passed The PR diff against origin/main contains 20 non-Swift files and no Swift paths, so it introduces no Swift actor-isolation changes.
Cmux Swift Blocking Runtime ✅ Passed The PR diff contains no Swift files; all changes are docs, web TypeScript, SQL, shell, JSON, and tests, so the Swift blocking-runtime check is not applicable.
Cmux Browser Automation Off-Main ✅ Passed The PR changes only docs/web files. It adds no Swift changes, browser socket commands, worker routing, or policy-test changes in the rule-scoped paths.
Cmux Expensive Synchronous Load ✅ Passed The PR range changes 20 docs/web files only; it contains no .swift paths or added expensive synchronous Swift loads, so the Swift-specific check does not apply.
Cmux Cache Substitution Correctness ✅ Passed No cache substitution is present. Webhooks now retrieve current Stripe subscriptions, and reconciliation compares DB snapshots with fresh Stripe retrievals before repair; no history or undo cache p...
Cmux No Hacky Sleeps ✅ Passed The PR adds no sleep, setTimeout, setInterval, or polling wait. It uses bounded AbortSignal timeouts, immediate bounded analytics retry, Next.js after() lifecycle dispatch, and deterministic Promis...
Cmux Algorithmic Complexity ✅ Passed Reconciliation uses an indexed paged query, caps work at 1,000 rows and 32 workers, performs one linear pass, and bulk-updates checked IDs; other scans are bounded, operator, or benchmark-only.
Cmux Swift Concurrency ✅ Passed The PR diff against origin/main contains no Swift files, so it introduces no cmux Swift concurrency patterns.
Cmux Swift @Concurrent ✅ Passed The full PR diff contains no Swift files and no Swift concurrency annotation changes, so the @concurrent check is not applicable.
Cmux Swift Package Boundaries ✅ Passed The PR range from its merge-base to HEAD contains no .swift or Package.swift changes; the Swift package-boundary rule is not applicable.
Cmux Swiftpm Lockfiles ✅ Passed The PR diff contains no SwiftPM package, Package.resolved, Xcode project, .gitignore, workflow, or dependency changes; the SwiftPM lockfile policy is not triggered.
Cmux Swift Logging ✅ Passed The PR diff against origin/main contains no .swift files or Swift logging changes; the touched paths are docs, TypeScript, SQL, shell, JSON, and tests.
Cmux Swiftui State Layout ✅ Passed The full pull request diff contains only docs/ and web/ changes, with no changed Swift or SwiftUI paths; the SwiftUI state/layout rule is not applicable.
Cmux Architecture Rethink ✅ Passed The PR diff against origin/main contains no Swift files; its lock-like code is a TypeScript PostgreSQL advisory lease, so the Swift architecture rule is not applicable.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR diff from 6c0f090 to HEAD contains no .swift files, so it does not introduce or change any Swift auxiliary windows or close-shortcut ownership.
Cmux Source Artifacts ✅ Passed The 20 changed paths are intentional docs, source, migration, config, scripts, and tests; scans found no artifact-like paths, binary blobs, or generated-output markers.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR diff contains no Swift files under production /Sources/; all changed paths are documentation, web TypeScript, SQL, JSON, and shell files.
Cmux No Ambient Global State ✅ Passed The PR range changes 20 files under docs/ and web/ only; no .swift files or production Swift declarations are added or modified.
Title check ✅ Passed The title clearly summarizes the main change: completing Coderouter billing operations and telemetry.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/coderouter-private-beta-100

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: 10

🤖 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 `@web/scripts/coderouter/benchmark.ts`:
- Around line 174-184: Update parseArgs to validate each inlineKey against the
supported keys origin, samples, timeout, and token before storing its value, and
throw for unsupported options such as --orign. Track keys already parsed and
reject duplicate occurrences before assigning either inline or next-argument
values.
- Around line 100-126: The sample aggregation in the benchmark result builder
repeatedly rescans samples for each status and timing name. Update the
surrounding aggregation logic to traverse samples once, accumulating status
counts in a Map and timing values in per-name arrays, then derive statusCounts
and serverTimingMs by sorting only the accumulated keys or percentile arrays;
preserve the existing output shape and percentile behavior.
- Around line 30-33: Validate and normalize origin before using it in requests
or JSON output: reject URL userinfo, query strings, and fragments, and permit
the environment-derived routeToken only when origin matches the approved-origin
policy. Ensure serialization and command output never expose routeToken or other
credentials, while preserving valid explicit-token behavior as appropriate.
- Around line 57-59: Move the CLI-visible error messages in the benchmark flow,
including the messages around the status check and the other referenced error
sites, into the repository’s locale source. Replace hard-coded text with the
established locale lookup while preserving stable machine-readable JSON schema
keys, and update every web/messages/*.json catalog with the corresponding
translations.
- Around line 130-141: The parseServerTiming function must split Server-Timing
entries on commas only when outside quoted strings. Replace the direct
value.split(",") iteration with quote-aware tokenization, then preserve the
existing parameter and duration parsing; add a fixture covering
cache;desc="edge, cache";dur=12.5 and verify it records the cache duration
correctly.

In `@web/scripts/coderouter/reconcile-billing.ts`:
- Around line 5-13: Update the CLI argument validation around unknown so it
throws without including unknown argument values, and wrap
reconcileStripeSubscriptions in a failure handler that records sanitized
internal telemetry, prints only a generic recovery message, and sets a nonzero
process.exitCode. Preserve the existing JSON success output and failure status
handling for successful reconciliation results.

In `@web/scripts/stripe/provision-catalog.sh`:
- Line 179: Update the price-check message at
web/scripts/stripe/provision-catalog.sh:179-179 and the catalog/product progress
messages at web/scripts/stripe/provision-catalog.sh:248-252 to use the locale
source and matching localized catalog entries. Make all output provider-neutral
by removing explicit Stripe/provider names unless the configured product
provider must be shown.
- Around line 77-86: Update stripe_post so retried POST requests are safe by
generating or accepting one stable Idempotency-Key per operation and passing it
on every retry through the curl headers; alternatively remove automatic retries
from this POST path. Keep the existing stripe_get retry behavior unchanged.

In `@web/services/billing/reconcile.ts`:
- Around line 120-121: Replace the fixed oldest-first ordering in the
reconciliation query with a persisted reconciliation cursor or work-queue
checkpoint, using an indexed keyset such as (lastReconciledAt, id) to rotate
through subscriptions across runs. Update the checkpoint after processing each
bounded batch, add the required schema index, and cover that a later
subscription is checked on a subsequent truncated run.

In `@web/tests/billing-reconcile.test.ts`:
- Around line 53-61: Update the retrieve mock in the billing reconciliation test
to replace the fixed setTimeout delay with a promise readiness barrier. Track
retrieve starts, resolve the barrier when both calls have begun, and await that
barrier so concurrency is deterministic while preserving the inFlight and peak
tracking behavior.
🪄 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: 202c707a-e49e-4e21-86ff-0d7cdbab399e

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0c47f and 6c0f090.

📒 Files selected for processing (17)
  • docs/coderouter-operations.md
  • web/app/api/billing/checkout/route.ts
  • web/app/api/cron/billing-reconcile/route.ts
  • web/app/api/stripe/webhook/route.ts
  • web/package.json
  • web/scripts/coderouter/benchmark.ts
  • web/scripts/coderouter/reconcile-billing.ts
  • web/scripts/stripe/dev-stack.sh
  • web/scripts/stripe/provision-catalog.sh
  • web/services/analytics/stripeBilling.ts
  • web/services/billing/reconcile.ts
  • web/tests/billing-reconcile-route.test.ts
  • web/tests/billing-reconcile.test.ts
  • web/tests/stripe-billing-analytics.test.ts
  • web/tests/stripe-provision-catalog.test.ts
  • web/tests/stripe-webhook-route.test.ts
  • web/vercel.json

Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/reconcile-billing.ts Outdated
Comment thread web/scripts/stripe/provision-catalog.sh
Comment thread web/scripts/stripe/provision-catalog.sh
Comment thread web/services/billing/reconcile.ts Outdated
Comment thread web/tests/billing-reconcile.test.ts

@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: 5

Caution

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

⚠️ Outside diff range comments (1)
web/scripts/stripe/provision-catalog.sh (1)

110-146: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep an authoritative fallback for product discovery.

The new /products/search lookup is not strongly consistent. Stripe documents that Product Search is unsuitable for read-after-write flows. A newly created product can remain absent from search results for under a minute normally and much longer during an outage. (docs.stripe.com)

If a previous product creation succeeds but the response is lost, the next run can see no match and create a duplicate product. Keep an authoritative /products fallback before creating a product, or use an idempotency key that remains stable across reruns. Add a test for this recovery path.

#!/bin/bash
set -euo pipefail

sed -n '100,160p' web/scripts/stripe/provision-catalog.sh
rg -n -C 8 'products/search|stripe_post "/products"|next_page|ensure_product|resolve_product' \
  web/scripts/stripe/provision-catalog.sh \
  web/tests/stripe-provision-catalog.test.ts

Also applies to: 84-86

🤖 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 `@web/scripts/stripe/provision-catalog.sh` around lines 110 - 146, Update the
product-resolution flow around the /products/search pagination and
ensure_product logic to use an authoritative /products lookup before creating a
new product, preserving matching filters for name, active status, and cmux/plan
metadata. Ensure products temporarily missing from search are recovered without
duplication, and add a test covering recovery after a prior creation response is
lost.
🤖 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 `@web/scripts/coderouter/benchmark.ts`:
- Around line 225-226: Update the argument validation in main() to throw a
generic error without interpolating the raw value, and add a regression test
using a secret-like positional argument that verifies the thrown message does
not contain it.

In `@web/scripts/coderouter/reconcile-billing.ts`:
- Line 9: Replace the hard-coded CLI messages in reconcile-billing.ts, including
the output around the referenced console.error lines, with the project’s
localization API. Add matching translation keys and English-equivalent entries
to every supported locale catalog, preserving the existing message behavior and
dry-run guidance.

In `@web/services/billing/reconcile.ts`:
- Around line 125-128: Align the cursor ordering and index definitions: retain
the unreconciled-first ordering in web/services/billing/reconcile.ts lines
125-128, declare lastReconciledAt ASC NULLS FIRST followed by id ASC in
web/db/schema.ts lines 625-628, and create the physical index with the same
ordering in
web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql lines
4-5.
- Around line 64-65: Update the batch flow around list and snapshots to acquire
a shared database-backed lease or advisory lock before selecting records, retain
it through Stripe retrieval and repair completion, and release it in finally.
Ensure every cron and CLI entry point uses this same claim mechanism, and add a
concurrency test proving a second invocation cannot process an already claimed
batch.
- Around line 94-96: Guard the markChecked call in the reconciliation flow so it
runs only when snapshots exist and options.dryRun is false; preserve normal
reconciliation updates. Add a dry-run test asserting markChecked is not called.

---

Outside diff comments:
In `@web/scripts/stripe/provision-catalog.sh`:
- Around line 110-146: Update the product-resolution flow around the
/products/search pagination and ensure_product logic to use an authoritative
/products lookup before creating a new product, preserving matching filters for
name, active status, and cmux/plan metadata. Ensure products temporarily missing
from search are recovered without duplication, and add a test covering recovery
after a prior creation response is lost.
🪄 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: 7c3b0eb7-392e-4b9e-bdf2-f2c5da8fdecc

📥 Commits

Reviewing files that changed from the base of the PR and between 6c0f090 and 9fec121.

📒 Files selected for processing (8)
  • web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql
  • web/db/schema.ts
  • web/scripts/coderouter/benchmark.ts
  • web/scripts/coderouter/reconcile-billing.ts
  • web/scripts/stripe/provision-catalog.sh
  • web/services/billing/reconcile.ts
  • web/tests/billing-reconcile.test.ts
  • web/tests/coderouter-benchmark.test.ts

Comment thread web/scripts/coderouter/benchmark.ts Outdated
Comment thread web/scripts/coderouter/reconcile-billing.ts
Comment thread web/services/billing/reconcile.ts
Comment thread web/services/billing/reconcile.ts Outdated
Comment thread web/services/billing/reconcile.ts

@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: 1

🤖 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 `@web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql`:
- Around line 4-6: Change the migration flow for
stripe_subscriptions_reconcile_cursor_idx so the index is built with CREATE
INDEX CONCURRENTLY in a separate non-transactional deployment step before this
migration; do not leave the normal CREATE INDEX statement in the
transaction-based migration path used by drizzle-orm/node-postgres/migrator or
drizzle-kit migrate.
🪄 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: 3139d7d3-97db-4507-b86a-8ae137a1de0f

📥 Commits

Reviewing files that changed from the base of the PR and between 9fec121 and 10351a5.

📒 Files selected for processing (6)
  • web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql
  • web/db/schema.ts
  • web/scripts/coderouter/benchmark.ts
  • web/services/billing/reconcile.ts
  • web/tests/billing-reconcile.test.ts
  • web/tests/coderouter-benchmark.test.ts

Comment on lines +4 to +6
CREATE INDEX "stripe_subscriptions_reconcile_cursor_idx"
ON "stripe_subscriptions"
("last_reconciled_at" ASC NULLS FIRST, "id" ASC);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the migration runner and determine whether it wraps migrations in a transaction.
fd -t f . | rg '(^|/)(drizzle[^/]*|.*migration.*|package\.json)$' | while IFS= read -r file; do
  rg -n -C 3 'drizzle.*migrate|migrate\(|transaction|CREATE INDEX CONCURRENTLY|concurrent' "$file" || true
done

Repository: manaflow-ai/cmux

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Relevant files:\n'
fd -t f . | rg '(^|/)(package\.json|drizzle|migration\.ts|.*migration.*|turso|postgres|libsql).*' | head -200

printf '\nMigration SQL:\n'
cat -n web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql

printf '\nMigration runner / drizzle config references:\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'drizzle.*migrate|migrate\(|BEGIN|COMMIT|transaction\(|turso|integrations|execute\(' web package.json 2>/dev/null || true

printf '\nFiles mentioning drizzle migrate in config scripts:\n'
python3 - <<'PY'
import json, os, subprocess
files = subprocess.check_output(['fd','-t','f','package.json'], text=True).splitlines()
for f in files[:50]:
    try:
        data=json.load(open(f))
    except Exception:
        continue
    for k,v in data.get('scripts',{}).items():
        if any(s in str(v) for s in ['drizzle','migrate','tursonorm','turso','migration']):
            print(f'{f}:{k}={v}')
PY

Repository: manaflow-ai/cmux

Length of output: 30158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'web/drizzle.config.ts:\n'
cat -n web/drizzle.config.ts

printf '\nScripts using db-local migration entrypoint:\n'
cat -n web/scripts/db-local.sh | sed -n '1,180p'

printf '\nCloud VM migration script database/migrate usage:\n'
cat -n web/scripts/cloud-vm/migrate-vercel-aurora-iam.mjs | sed -n '1,140p'

printf '\nAWS RDS IAM migration script migrate call:\n'
cat -n web/scripts/migrate-aws-rds-iam.ts | sed -n '1,80p'

Repository: manaflow-ai/cmux

Length of output: 10566


Run this index build non-transactionally before this migration.

stripe_subscriptions_reconcile_cursor_idx uses normal CREATE INDEX, which blocks writes to stripe_subscriptions while the index builds. Create it with CREATE INDEX CONCURRENTLY before this migration, or split this migration into a separate non-transactional deployment step. Existing production migration paths (drizzle-orm/node-postgres/migrator and local drizzle-kit migrate) run migrations in a transaction, so this statement cannot run directly in those flows.

🧰 Tools
🪛 SQLFluff (4.2.2)

[error] 4-6: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.

(PG01)

🪛 Squawk (2.61.0)

[warning] 4-6: During normal index creation, table updates are blocked, but reads are still allowed. Use concurrently to avoid blocking writes.

(require-concurrent-index-creation)

🤖 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 `@web/db/migrations/20260807010000_stripe_reconcile_cursor/migration.sql`
around lines 4 - 6, Change the migration flow for
stripe_subscriptions_reconcile_cursor_idx so the index is built with CREATE
INDEX CONCURRENTLY in a separate non-transactional deployment step before this
migration; do not leave the normal CREATE INDEX statement in the
transaction-based migration path used by drizzle-orm/node-postgres/migrator or
drizzle-kit migrate.

Source: Linters/SAST tools

@lawrencecchen
lawrencecchen merged commit 9ee56b5 into main Aug 7, 2026
28 checks passed
@lawrencecchen
lawrencecchen deleted the feat/coderouter-private-beta-100 branch August 7, 2026 01:55
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