Skip to content

fix(billing): weekKey index becomes a true partial — legacy usage tracking works past month one - #4000

Merged
PierreBrisorgueil merged 2 commits into
masterfrom
fix/3991-weekkey-partial-index
Jul 28, 2026
Merged

fix(billing): weekKey index becomes a true partial — legacy usage tracking works past month one#4000
PierreBrisorgueil merged 2 commits into
masterfrom
fix/3991-weekkey-partial-index

Conversation

@PierreBrisorgueil

@PierreBrisorgueil PierreBrisorgueil commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What — The {organizationId, weekKey} unique index moves from sparse: true (which never excluded weekKey-less docs: compound-sparse skips only when ALL fields are missing) to a real partial filter (weekKey: {$exists: true}) under a new explicit name, with a coexistence migration (create-new → drop-old) and a loud log on the previously silent null-return in the legacy increment() path.

Why — With meterMode: false (the default), a second month's legacy usage increment for the same organization collided on the mis-scoped index and silently returned null — legacy usage tracking stopped after the first month, with no error anywhere.

Design notes: same-name drop/recreate was deliberately avoided — the old index is live on deployed DBs and awaitIndexBuilds() (#3993) runs before migrations, so a same-name spec change would IndexOptionsConflict-crash boot; the distinct-name coexistence technique follows the existing users email-CI migration precedent. Migration: zero-write dup pre-check → create new → drop old, idempotent, skip-window fast path, E11000-catch. increment() null now logger.errors with full context (not thrown — public API, no caller guarantees non-null).

Review gate: Claude fallback (kimi down, infra#60 fix in flight) — OK, 0 findings, all merge-blocker questions verified incl. both cited precedents. Suites: unit 2272, integration 529, lint clean. Simplify pass kept (shared dup-check helper).

Closes #3991

Summary by CodeRabbit

  • Bug Fixes

    • Corrected billing usage uniqueness for meter-based weekly records.
    • Prevented records without a week key from colliding across different months.
    • Added safeguards to detect duplicate usage data before applying the database update.
    • Billing usage write anomalies are now logged clearly instead of being silently ignored.
  • Reliability

    • The billing usage index migration is safe to rerun and handles concurrent update conflicts more explicitly.

… one doc per org (#3991)

The (organizationId, weekKey) unique index declared sparse: true on a
COMPOUND index — MongoDB only excludes a doc from a compound sparse
index when ALL indexed fields are missing, and organizationId is
always present. Every legacy (weekKey-less) usage document was
indexed too (weekKey: null), so a second legacy month for the same
org collided as a duplicate key and increment()'s retry silently
lost the write.

- Model: partialFilterExpression { weekKey: { $exists: true } },
  explicit distinct name (avoids an IndexOptionsConflict boot-crash
  against the still-live old-named index on already-deployed DBs).
- New migration: creates the new index alongside the old one, then
  drops the old one — dup pre-check, idempotent, skip-window fast
  path, E11000-catch abort, mirroring the #3990 migration's safety
  patterns.
- Service: increment() now logs loud (with context) instead of
  silently swallowing a lost write on the (now anomalous) null case.
- Regression + migration integration tests, MIGRATIONS.md entry.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PierreBrisorgueil, 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: 7c7bde3c-9a58-4dee-a4f8-4148cfeec462

📥 Commits

Reviewing files that changed from the base of the PR and between 120cc6b and bd36564.

📒 Files selected for processing (3)
  • modules/billing/migrations/20260728120000-fix-usage-weekkey-index-partial.js
  • modules/billing/repositories/billing.usage.repository.js
  • modules/billing/tests/billing.usage.weekKeyIndexPartialFilter.migration.integration.tests.js

Walkthrough

The PR replaces the compound sparse billing usage index with a named partial unique index, adds an idempotent migration with duplicate detection and race handling, and surfaces anomalous null results from legacy usage increments through service logging.

Changes

Billing usage index and increment handling

Layer / File(s) Summary
Partial index contract and detection
modules/billing/models/..., modules/billing/migrations/..., modules/billing/tests/billing.usage.*
Billing usage uniqueness now applies only when weekKey exists, with matching helpers and integration setup for the target index shape.
Index migration and database validation
modules/billing/migrations/..., modules/billing/tests/billing.usage.weekKeyIndexPartialFilter.migration.integration.tests.js, MIGRATIONS.md
The migration detects duplicates, creates the new index before dropping divergent indexes, handles creation races, supports reruns, and documents deployment steps.
Increment null-result handling
modules/billing/repositories/..., modules/billing/services/..., modules/billing/tests/billing.usage.service.unit.tests.js
Repository and service contracts allow null results; the service logs anomalous duplicate-key retry outcomes and returns null.
Estimated code review effort: 4 (Complex) ~45 minutes

Possibly related PRs

  • pierreb-devkit/Node#3273: Earlier billing usage repository/service increment behavior that this change extends with nullable-result handling.

Suggested labels: Fix, billing

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning It covers summary, rationale, and issue closure, but it omits required template sections like Scope, Validation, and Guardrails. Add the template sections for Scope, Validation, and Guardrails, and format the summary under the required headings.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly captures the main change: fixing the billing weekKey index to be a real partial index and restoring legacy usage tracking.
Linked Issues check ✅ Passed The PR implements #3991's partial index, migration, and null-return visibility fixes, matching the issue's acceptance criteria.
Out of Scope Changes check ✅ Passed The code, tests, and docs all support the index fix and null-handling change; no unrelated or extra-scope modifications are evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/3991-weekkey-partial-index

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.

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.43%. Comparing base (c8049d6) to head (bd36564).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4000   +/-   ##
=======================================
  Coverage   93.42%   93.43%           
=======================================
  Files         170      170           
  Lines        5688     5693    +5     
  Branches     1826     1828    +2     
=======================================
+ Hits         5314     5319    +5     
  Misses        304      304           
  Partials       70       70           
Flag Coverage Δ
integration 61.53% <16.66%> (-0.06%) ⬇️
unit 75.79% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c8049d6...bd36564. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

🤖 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
`@modules/billing/migrations/20260728120000-fix-usage-weekkey-index-partial.js`:
- Around line 208-214: Update the drop loop in the migration around
usages.dropIndex to catch and ignore MongoDB IndexNotFound errors (code 27),
while rethrowing all other failures. Preserve the existing index selection and
logging behavior, allowing concurrent instances to remove the same legacy index
without failing the migration.
- Around line 179-204: Update the index reconciliation flow around
isExactTargetIndex and NEW_INDEX_NAME so an existing same-name index with
divergent options is dropped before createIndex, allowing the expected unique
partial index to converge. Preserve the existing exact-index skip behavior, and
ensure the drop occurs before the create attempt rather than being excluded by
the later cleanup step.

In `@modules/billing/repositories/billing.usage.repository.js`:
- Around line 34-40: Update the return contract near BillingUsageRepository’s
usage update method to document both null outcomes: invalid organizationId
rejected before any write and duplicate-key retry finding no exact-match
document. In BillingUsageService.increment, distinguish these cases in logging
so invalid input is not reported as a lost write.
🪄 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 Plus

Run ID: 56e18274-e502-442d-8b13-585ba6f029fa

📥 Commits

Reviewing files that changed from the base of the PR and between c8049d6 and 120cc6b.

📒 Files selected for processing (9)
  • MIGRATIONS.md
  • modules/billing/migrations/20260728120000-fix-usage-weekkey-index-partial.js
  • modules/billing/models/billing.usage.model.mongoose.js
  • modules/billing/repositories/billing.usage.repository.js
  • modules/billing/services/billing.usage.service.js
  • modules/billing/tests/billing.usage.bootIndexReady.integration.tests.js
  • modules/billing/tests/billing.usage.repository.integration.tests.js
  • modules/billing/tests/billing.usage.service.unit.tests.js
  • modules/billing/tests/billing.usage.weekKeyIndexPartialFilter.migration.integration.tests.js

Comment thread modules/billing/repositories/billing.usage.repository.js Outdated
#3991)

- Migration: drop a pre-existing NEW_INDEX_NAME index with a divergent spec
  before createIndex, so a hand-fixed/earlier-iteration index doesn't wedge
  every future boot in an IndexOptionsConflict crash loop (step (c) never
  drops NEW_INDEX_NAME, so it could never self-heal otherwise).
- Repository: document that increment() also returns null on an invalid
  organizationId (no write attempted), not only on the anomalous
  duplicate-key-retry-miss case.
- Add a regression test for the divergent-NEW_INDEX_NAME recovery path.
@PierreBrisorgueil
PierreBrisorgueil merged commit fa3d02c into master Jul 28, 2026
6 checks passed
@PierreBrisorgueil
PierreBrisorgueil deleted the fix/3991-weekkey-partial-index branch July 28, 2026 14:44
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.

🐛 legacy usage compound sparse unique index collapses to one document per organization, ever

1 participant