Skip to content

[codex] Share build minute pricing credits#1900

Merged
riderx merged 18 commits intomainfrom
codex/build-minute-credit-system
Apr 14, 2026
Merged

[codex] Share build minute pricing credits#1900
riderx merged 18 commits intomainfrom
codex/build-minute-credit-system

Conversation

@riderx
Copy link
Copy Markdown
Member

@riderx riderx commented Apr 8, 2026

Summary (AI generated)

  • reuse the shared usage credit calculator for build-minute overage pricing
  • add a new Supabase migration and seed updates to price build minutes from $0.16 down to $0.08 across the existing usage tiers
  • cover the new pricing path with Vitest and SQL assertions and update the usage-page pricing copy

Motivation (AI generated)

Build minutes were still using a separate fixed-price path while MAU, storage, and bandwidth already relied on the shared credit system. Moving build minutes onto the same pricing engine removes duplicated pricing logic and lets the dashboard, backend, and database all compute overage consistently.

Business Impact (AI generated)

This lowers build-minute pricing to the requested range while keeping the billing logic centralized. It reduces the risk of mismatched prices between the product surface and backend charging rules, which directly affects customer trust and revenue accuracy.

Test Plan (AI generated)

  • bun lint
  • bun lint:backend
  • bun typecheck
  • bun run supabase:with-env -- bunx vitest run tests/credits-pricing.test.ts tests/build_time_tracking.test.ts tests/overage-tracking.test.ts
  • bun scripts/supabase-worktree.ts test db

Screenshots (AI generated)

Credits Pricing UI

Credits pricing and top-up UI

Generated with AI

Summary by CodeRabbit

  • Chores

    • Lowered build-time credit prices per minute across all supported locales and updated shared pricing tiers.
  • Bug Fixes

    • Improved usage overage estimation to rely on centralized cost calculation, added error handling, and clarified displayed totals.
  • Tests

    • Added tests covering build-time pricing, cost calculations, scoped pricing overrides, validation, and related edge cases.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Updated build-time credit prices across locale files and the database; added a typed client API and Supabase edge function support for computing build_time costs (with org-scoped pricing); refactored the Usage page to call the new estimator; added migration/seed changes and tests for build-time pricing and org overrides.

Changes

Cohort / File(s) Summary
Localization & Pricing Strings
messages/de.json, messages/en.json, messages/es.json, messages/fr.json, messages/hi.json, messages/id.json, messages/it.json, messages/ja.json, messages/ko.json, messages/pl.json, messages/pt-br.json, messages/ru.json, messages/tr.json, messages/vi.json, messages/zh-cn.json
Reduced per-minute USD rates for all six build-time pricing tiers in locale JSON files (value-only updates).
Frontend: Usage Page
src/pages/settings/organization/Usage.vue
Replaced client-side per-metric price calculations with an async call to calculateCreditCost; removed cached creditUnitPrices; changed total/estimated price logic, filtered credit deductions to billing cycle, added try/catch, and switched to formatting helpers.
Service: Supabase client
src/services/supabase.ts
Added exported types/interfaces for credit cost calculation and a new calculateCreditCost(request) that calls the Supabase edge/function and returns a typed response with error handling.
Backend Edge Function
supabase/functions/_backend/private/credits.ts
Added build_time and org_id handling to request/response, validation for build_time, org/global scoped pricing merge, tiered cost computation for build_time, and GET support for org_id.
Database: Migration & Seed
supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql, supabase/seed.sql
Updated shared (org_id IS NULL) capgo_credits_steps build_time tiers: new step ranges, price_per_unit values, and unit_factor = 60; migration performs idempotent update-then-insert; seed updated to match.
Tests
supabase/tests/32_test_usage_credits.sql, tests/credits-pricing.test.ts
Added/updated SQL assertions and Vitest suite covering /private/credits GET/POST, build_time cost computation, negative input validation, org-scoped overrides and fallback-to-global behavior; includes repricing scenario checks.

Sequence Diagram

sequenceDiagram
    participant User
    participant Vue as Usage.vue
    participant Service as src/services/supabase.ts
    participant EdgeFn as /private/credits
    participant DB as capgo_credits_steps

    User->>Vue: open usage page
    Vue->>Service: calculateCreditCost({mau, bandwidth, storage, build_time})
    Service->>EdgeFn: invoke edge function with request
    EdgeFn->>DB: query global and org-scoped pricing tiers
    DB-->>EdgeFn: return tier rows
    EdgeFn->>EdgeFn: merge scoped/global steps and compute tiered costs (including build_time)
    EdgeFn-->>Service: return total_cost & breakdown
    Service-->>Vue: propagate response
    Vue->>Vue: set estimatedUsagePrice and totalPrice
    Vue-->>User: display updated estimated billing
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐇 I hopped through tiers and gently pared,
Prices slimmed down, the math was shared,
Seeds in DB, a function spun,
Frontend asks, the edge returns—hop, done! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title '[codex] Share build minute pricing credits' clearly summarizes the main change: moving build-minute pricing to the shared credit system.
Description check ✅ Passed The PR description includes a clear summary, motivation, business impact, and a comprehensive test plan with checkmarks demonstrating execution of required tests.

✏️ 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 codex/build-minute-credit-system

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

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq bot commented Apr 8, 2026

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing codex/build-minute-credit-system (815c05b) with main (110282f)

Open in CodSpeed

@riderx riderx marked this pull request as ready for review April 8, 2026 14:10
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19792e456c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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 (3)
supabase/tests/32_test_usage_credits.sql (1)

44-55: Make the new pricing assertions deterministic against global tiers.

Consider filtering to org_id IS NULL so org-scoped custom tiers don’t make this test flaky.

Suggested SQL refinement
 SELECT
     results_eq(
-        $$SELECT price_per_unit FROM public.capgo_credits_steps WHERE type = 'build_time' AND step_min = 0$$,
+        $$SELECT price_per_unit
+          FROM public.capgo_credits_steps
+         WHERE type = 'build_time'
+           AND org_id IS NULL
+           AND step_min = 0
+         ORDER BY step_max ASC
+         LIMIT 1$$,
         $$VALUES (0.16::double precision)$$,
         'build_time credit pricing starts at $0.16 per minute'
     );

 SELECT
     results_eq(
-        $$SELECT price_per_unit FROM public.capgo_credits_steps WHERE type = 'build_time' ORDER BY step_max DESC LIMIT 1$$,
+        $$SELECT price_per_unit
+          FROM public.capgo_credits_steps
+         WHERE type = 'build_time'
+           AND org_id IS NULL
+         ORDER BY step_max DESC, step_min DESC
+         LIMIT 1$$,
         $$VALUES (0.08::double precision)$$,
         'build_time credit pricing floors at $0.08 per minute'
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/tests/32_test_usage_credits.sql` around lines 44 - 55, The
assertions query public.capgo_credits_steps for build_time pricing but can be
affected by org-scoped custom tiers; make them deterministic by adding "org_id
IS NULL" to both queries (the one selecting price_per_unit WHERE type =
'build_time' AND step_min = 0 and the one ORDER BY step_max DESC LIMIT 1) so
they only assert against global tiers in capgo_credits_steps.
messages/ru.json (1)

611-622: Keep the numeric ladder out of locale files.

These strings still duplicate the build-minute prices that other surfaces already source from capgo_credits_steps. The next pricing change will require another 16-locale sweep and can drift from the backend again. Consider localizing only the labels/units and rendering the numeric tier values from the shared pricing source.

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

In `@messages/ru.json` around lines 611 - 622, The locale file contains hard-coded
numeric pricing tiers (keys like "credits-pricing-build-tier-first-100",
"credits-pricing-build-tier-next-400",
"credits-pricing-build-tier-next-5000-price", etc.) which duplicates the
authoritative data; remove numeric values from these keys and keep only
label/unit strings, then update the UI rendering to pull the numeric tier values
from the shared capgo_credits_steps source at runtime and interpolate them into
the localized label; ensure keys remain stable (e.g.,
"credits-pricing-build-tier-first" or "credits-pricing-build-tier-label") so
translators only receive unit/label text and the numeric values are rendered
from capgo_credits_steps.
tests/credits-pricing.test.ts (1)

10-55: Run these API tests with it.concurrent().

Both cases only read pricing state / hit the stateless calculator path, so sequential it() just slows this file down.

♻️ Suggested diff
-  it('returns the updated build_time tiers from the shared pricing table', async () => {
+  it.concurrent('returns the updated build_time tiers from the shared pricing table', async () => {
@@
-  it('prices build_time overage through the shared calculator endpoint', async () => {
+  it.concurrent('prices build_time overage through the shared calculator endpoint', async () => {

Based on learnings: Applies to tests/**/*.{ts,js} : Use it.concurrent() instead of it() when possible to run tests in parallel within the same file, maximizing parallelism for faster CI/CD

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

In `@tests/credits-pricing.test.ts` around lines 10 - 55, Two tests inside
describe('credits pricing API') are currently using sequential it() but are safe
to run in parallel; change both it(...) calls into it.concurrent(...) for the
two test cases (the one with title "returns the updated build_time tiers from
the shared pricing table" and the one titled "prices build_time overage through
the shared calculator endpoint") keeping their async functions,
fetchWithRetry/getEndpointUrl usage, request bodies and assertions identical so
they execute concurrently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/settings/organization/Usage.vue`:
- Around line 139-155: The code currently treats missing plan/quote data as
zeros, causing underreporting; change calculateCreditCost usage and downstream
math so missing currentPlan or a failed quote result in "unavailable" rather
than 0: before calling calculateCreditCost, check that currentPlan is present
(from getPlans()) and only compute overageCost if currentPlan exists; on any
error or when currentPlan is missing set estimatedUsagePrice to null/undefined
(not 0); update the totalUsagePrice/totalPrice logic that uses
estimatedUsagePrice, creditDeductions, and totalCreditDeductions so it only
folds in estimatedUsagePrice when it is a real number (otherwise treat usage
price as unavailable and surface that in the UI), and ensure
calculateCreditCost, estimatedUsagePrice, totalUsagePrice, and totalPrice all
follow this non-zero/nullable flow.

In `@supabase/functions/_backend/private/credits.ts`:
- Around line 289-290: Validate body.build_time before using: parse it into a
number (e.g., const buildTime = Number(body.build_time)), then check
Number.isFinite(buildTime) and buildTime >= 0; if the check fails, either set a
safe default (0) or return a 400 error. Replace usages/returns of the unchecked
buildTime with the validated value (e.g., validatedBuildTime) so the JSON
response at the later return point does not emit NaN or non-numeric values.
Ensure validation logic is applied wherever build_time is read/returned in this
module.

---

Nitpick comments:
In `@messages/ru.json`:
- Around line 611-622: The locale file contains hard-coded numeric pricing tiers
(keys like "credits-pricing-build-tier-first-100",
"credits-pricing-build-tier-next-400",
"credits-pricing-build-tier-next-5000-price", etc.) which duplicates the
authoritative data; remove numeric values from these keys and keep only
label/unit strings, then update the UI rendering to pull the numeric tier values
from the shared capgo_credits_steps source at runtime and interpolate them into
the localized label; ensure keys remain stable (e.g.,
"credits-pricing-build-tier-first" or "credits-pricing-build-tier-label") so
translators only receive unit/label text and the numeric values are rendered
from capgo_credits_steps.

In `@supabase/tests/32_test_usage_credits.sql`:
- Around line 44-55: The assertions query public.capgo_credits_steps for
build_time pricing but can be affected by org-scoped custom tiers; make them
deterministic by adding "org_id IS NULL" to both queries (the one selecting
price_per_unit WHERE type = 'build_time' AND step_min = 0 and the one ORDER BY
step_max DESC LIMIT 1) so they only assert against global tiers in
capgo_credits_steps.

In `@tests/credits-pricing.test.ts`:
- Around line 10-55: Two tests inside describe('credits pricing API') are
currently using sequential it() but are safe to run in parallel; change both
it(...) calls into it.concurrent(...) for the two test cases (the one with title
"returns the updated build_time tiers from the shared pricing table" and the one
titled "prices build_time overage through the shared calculator endpoint")
keeping their async functions, fetchWithRetry/getEndpointUrl usage, request
bodies and assertions identical so they execute concurrently.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: eb837678-5373-4b4f-92ac-a241a42b3714

📥 Commits

Reviewing files that changed from the base of the PR and between da34ba7 and 19792e4.

📒 Files selected for processing (22)
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/hi.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/pl.json
  • messages/pt-br.json
  • messages/ru.json
  • messages/tr.json
  • messages/vi.json
  • messages/zh-cn.json
  • src/pages/settings/organization/Usage.vue
  • src/services/supabase.ts
  • supabase/functions/_backend/private/credits.ts
  • supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql
  • supabase/seed.sql
  • supabase/tests/32_test_usage_credits.sql
  • tests/credits-pricing.test.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.

Caution

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

⚠️ Outside diff range comments (1)
src/pages/settings/organization/Usage.vue (1)

97-120: ⚠️ Potential issue | 🟠 Major

Only prefer deductions when one overlaps the active billing cycle.

totalCreditDeductions is cycle-filtered, but Line 155 switches to deductions whenever creditDeductions.length > 0. A historical row makes this branch win even when the current-cycle total is still 0, so the estimate is suppressed until the first deduction for the new cycle lands.

Also applies to: 155-156

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

In `@src/pages/settings/organization/Usage.vue` around lines 97 - 120, The current
logic uses creditDeductions.length to decide whether to prefer deductions
(causing historical deductions to suppress estimates); change the decision to
use the cycle-filtered total (totalCreditDeductions) or an explicit check for
any deduction that overlaps the active billing cycle (using
billingStart/billingEnd and the same overlap logic applied when computing
totalCreditDeductions). Update the branch that currently checks
creditDeductions.length > 0 (around the decision at lines ~155-156) to instead
check totalCreditDeductions > 0 or a filtered list of deductions that overlap
the billing window so only current-cycle deductions affect the UI.
♻️ Duplicate comments (1)
src/pages/settings/organization/Usage.vue (1)

138-156: ⚠️ Potential issue | 🟠 Major

Still folding unavailable pricing into $0.

If currentPlan is missing, this path prices usage against zero included units and also drops basePrice to 0; if calculateCreditCost() fails, estimatedUsagePrice still stays 0. The page then shows a concrete total when the inputs were actually unavailable.

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

In `@src/pages/settings/organization/Usage.vue` around lines 138 - 156, The code
currently treats missing plan data or a failed calculateCreditCost() as $0;
change logic in the Usage.vue block around currentPlan, estimatedUsagePrice,
calculateCreditCost, totalUsagePrice and totalPrice so that missing/failed
pricing produces an "unavailable" state rather than folding into zeros: detect
when currentPlan is null/undefined and set a pricingUnavailable flag (or set
estimatedUsagePrice to null/undefined) before calling calculateCreditCost; wrap
the await calculateCreditCost call in try/catch and on error set
pricingUnavailable (or leave estimatedUsagePrice null) instead of leaving it at
0; then compute totalUsagePrice and totalPrice only when pricingUnavailable is
false (otherwise propagate null/undefined or a sentinel so the UI can show
N/A/placeholder instead of a numeric $0).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/pages/settings/organization/Usage.vue`:
- Around line 97-120: The current logic uses creditDeductions.length to decide
whether to prefer deductions (causing historical deductions to suppress
estimates); change the decision to use the cycle-filtered total
(totalCreditDeductions) or an explicit check for any deduction that overlaps the
active billing cycle (using billingStart/billingEnd and the same overlap logic
applied when computing totalCreditDeductions). Update the branch that currently
checks creditDeductions.length > 0 (around the decision at lines ~155-156) to
instead check totalCreditDeductions > 0 or a filtered list of deductions that
overlap the billing window so only current-cycle deductions affect the UI.

---

Duplicate comments:
In `@src/pages/settings/organization/Usage.vue`:
- Around line 138-156: The code currently treats missing plan data or a failed
calculateCreditCost() as $0; change logic in the Usage.vue block around
currentPlan, estimatedUsagePrice, calculateCreditCost, totalUsagePrice and
totalPrice so that missing/failed pricing produces an "unavailable" state rather
than folding into zeros: detect when currentPlan is null/undefined and set a
pricingUnavailable flag (or set estimatedUsagePrice to null/undefined) before
calling calculateCreditCost; wrap the await calculateCreditCost call in
try/catch and on error set pricingUnavailable (or leave estimatedUsagePrice
null) instead of leaving it at 0; then compute totalUsagePrice and totalPrice
only when pricingUnavailable is false (otherwise propagate null/undefined or a
sentinel so the UI can show N/A/placeholder instead of a numeric $0).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4544dae-bfdd-4df8-911e-752fa86c3adb

📥 Commits

Reviewing files that changed from the base of the PR and between 19792e4 and 6920ee1.

📒 Files selected for processing (5)
  • src/pages/settings/organization/Usage.vue
  • src/services/supabase.ts
  • supabase/functions/_backend/private/credits.ts
  • supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql
  • tests/credits-pricing.test.ts
✅ Files skipped from review due to trivial changes (1)
  • supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql
🚧 Files skipped from review as they are similar to previous changes (2)
  • supabase/functions/_backend/private/credits.ts
  • tests/credits-pricing.test.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6920ee1e7a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc88606f92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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

Caution

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

⚠️ Outside diff range comments (1)
supabase/functions/_backend/private/credits.ts (1)

344-352: ⚠️ Potential issue | 🟡 Minor

Don't collapse auth failures into failed_to_fetch_pricing_data.

Line 351 rewraps every exception from getScopedCreditSteps(). For org-scoped requests, that hides the existing not_authorized error and makes callers treat an auth problem like a pricing outage.

💡 Proposed fix
 app.get('/', async (c) => {
-  try {
-    const orgId = c.req.query('org_id') ?? undefined
-    const credits = await getScopedCreditSteps(c as AppContext, orgId)
-    return c.json(credits)
-  }
-  catch (e) {
-    throw simpleError('failed_to_fetch_pricing_data', 'Failed to fetch pricing data', {}, e)
-  }
+  const orgId = c.req.query('org_id') ?? undefined
+  const credits = await getScopedCreditSteps(c as AppContext, orgId)
+  return c.json(credits)
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/functions/_backend/private/credits.ts` around lines 344 - 352, The
current app.get('/') handler wraps all exceptions from getScopedCreditSteps(...)
into a generic simpleError('failed_to_fetch_pricing_data', ...), which hides
authorization errors; update the catch to detect if the caught error is the
existing not_authorized error (e.g., check error.code or error.name as used
elsewhere) and rethrow it unchanged, otherwise wrap non-auth errors with
simpleError('failed_to_fetch_pricing_data', ...); reference the app.get('/',
...) route, getScopedCreditSteps, and the
simpleError('failed_to_fetch_pricing_data', ...) call when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@supabase/functions/_backend/private/credits.ts`:
- Around line 79-105: The GET handler currently swallows all errors from
getScopedCreditSteps() into a generic 'failed_to_fetch_pricing_data'—change the
handler to rethrow or return not_authorized errors unchanged (i.e., if
err.message === 'not_authorized' or err.name indicates auth, propagate it) and
only map other errors to the generic failure; in addition, update
preferScopedCreditSteps(steps, orgId) to detect mismatched boundaries between
global and org-scoped rows for the same type (e.g., when a type has both
org-scoped and global entries with differing step_min/step_max), and either
throw a descriptive error or surface a validation warning so org-scoped tiers
aren’t silently dropped (alternatively enforce uniqueness/validation at insert
as suggested—e.g., add a DB uniqueness constraint or insert-time validation to
ensure org-scoped step boundaries match global boundaries).

---

Outside diff comments:
In `@supabase/functions/_backend/private/credits.ts`:
- Around line 344-352: The current app.get('/') handler wraps all exceptions
from getScopedCreditSteps(...) into a generic
simpleError('failed_to_fetch_pricing_data', ...), which hides authorization
errors; update the catch to detect if the caught error is the existing
not_authorized error (e.g., check error.code or error.name as used elsewhere)
and rethrow it unchanged, otherwise wrap non-auth errors with
simpleError('failed_to_fetch_pricing_data', ...); reference the app.get('/',
...) route, getScopedCreditSteps, and the
simpleError('failed_to_fetch_pricing_data', ...) call when making the change.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 153a9067-72a9-4198-a450-6810874d2854

📥 Commits

Reviewing files that changed from the base of the PR and between 6920ee1 and bc88606.

📒 Files selected for processing (5)
  • src/pages/settings/organization/Usage.vue
  • supabase/functions/_backend/private/credits.ts
  • supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql
  • supabase/tests/32_test_usage_credits.sql
  • tests/credits-pricing.test.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/credits-pricing.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • supabase/migrations/20260408134842_adjust_build_time_credit_pricing.sql
  • supabase/tests/32_test_usage_credits.sql
  • src/pages/settings/organization/Usage.vue

@riderx
Copy link
Copy Markdown
Member Author

riderx commented Apr 8, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

🧹 Nitpick comments (2)
supabase/functions/_backend/private/credits.ts (2)

139-139: Redundant filter on already-typed group.

The filter(step => step.type === type) is unnecessary since group.scoped only contains steps of the current type (populated at lines 125-133).

♻️ Suggested simplification
-    const scopedSteps = sortCreditSteps(group.scoped.filter(step => step.type === type))
+    const scopedSteps = sortCreditSteps(group.scoped)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/functions/_backend/private/credits.ts` at line 139, The code
unnecessarily filters group.scoped by step.type even though group.scoped is
already built to contain only steps of the current type; update the consumer to
call sortCreditSteps(group.scoped) instead of
sortCreditSteps(group.scoped.filter(step => step.type === type)) (modify the
assignment to scopedSteps) so you avoid redundant filtering and extra work when
computing scopedSteps.

160-164: Extract nested ternary for readability.

Per SonarCloud, the nested ternary makes the authorization flow harder to follow. Consider extracting to explicit conditionals.

♻️ Suggested refactor
-  const pricingClient = orgId
-    ? authorization
-      ? supabaseClient(c, authorization)
-      : undefined
-    : supabaseAdmin(c)
+  let pricingClient: ReturnType<typeof supabaseAdmin> | undefined
+  if (orgId) {
+    if (authorization)
+      pricingClient = supabaseClient(c, authorization)
+  }
+  else {
+    pricingClient = supabaseAdmin(c)
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/functions/_backend/private/credits.ts` around lines 160 - 164, The
nested ternary used to set pricingClient (checking orgId and authorization) is
hard to read; replace it with an explicit conditional assignment: declare
pricingClient let/const above and then use if/else blocks to implement the same
logic (if orgId is truthy -> if authorization truthy -> pricingClient =
supabaseClient(c, authorization) else pricingClient = undefined; else
pricingClient = supabaseAdmin(c)). Keep the same variable names (pricingClient,
orgId, authorization, supabaseClient, supabaseAdmin, and c) and preserve
identical runtime behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@supabase/functions/_backend/private/credits.ts`:
- Line 139: The code unnecessarily filters group.scoped by step.type even though
group.scoped is already built to contain only steps of the current type; update
the consumer to call sortCreditSteps(group.scoped) instead of
sortCreditSteps(group.scoped.filter(step => step.type === type)) (modify the
assignment to scopedSteps) so you avoid redundant filtering and extra work when
computing scopedSteps.
- Around line 160-164: The nested ternary used to set pricingClient (checking
orgId and authorization) is hard to read; replace it with an explicit
conditional assignment: declare pricingClient let/const above and then use
if/else blocks to implement the same logic (if orgId is truthy -> if
authorization truthy -> pricingClient = supabaseClient(c, authorization) else
pricingClient = undefined; else pricingClient = supabaseAdmin(c)). Keep the same
variable names (pricingClient, orgId, authorization, supabaseClient,
supabaseAdmin, and c) and preserve identical runtime behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d9adefe2-da3a-4625-89bc-1bac49982a0f

📥 Commits

Reviewing files that changed from the base of the PR and between 0051ade and e03496f.

📒 Files selected for processing (2)
  • supabase/functions/_backend/private/credits.ts
  • tests/credits-pricing.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/credits-pricing.test.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c1b2745f60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5aca3a1617

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8271140a75

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@riderx
Copy link
Copy Markdown
Member Author

riderx commented Apr 14, 2026

@copilot resolve conflcit

Co-authored-by: riderx <4084527+riderx@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

@copilot resolve conflcit

Resolved the merge conflict in supabase/functions/_backend/public/webhooks/index.ts and merged main into this branch (commit 815c05b). The conflict was in checkWebhookPermission — kept the policy check already at the top of the function and used the inline limited_to_apps check from main, which is cleaner since the policy check was otherwise being called twice.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
B Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@riderx riderx merged commit d7ea9fd into main Apr 14, 2026
12 of 15 checks passed
@riderx riderx deleted the codex/build-minute-credit-system branch April 14, 2026 19:38
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.

2 participants