Skip to content

budget overrides ui - #5443

Merged
akshaydeo merged 3 commits into
devfrom
07-22-budget_overrides_ui
Jul 23, 2026
Merged

akshaydeo merged 3 commits into
devfrom
07-22-budget_overrides_ui

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

Changes

  • Added override_amount, override_mode, and override_cycles_remaining fields to the Budget type, along with BudgetOverrideRequest and BudgetOverrideResponse types.
  • Introduced three utility functions in governance.ts: hasActiveBudgetOverride, getEffectiveBudgetLimit, and validateBudgetOverride. These handle override state detection, effective limit calculation, and input validation respectively.
  • Replaced all direct references to b.max_limit in exhaustion checks, progress bars, and CSV exports with getEffectiveBudgetLimit(b) so overrides are reflected everywhere budgets are displayed or evaluated.
  • Added setVirtualKeyBudgetOverride (PUT) and removeVirtualKeyBudgetOverride (DELETE) RTK Query mutations to governanceApi, targeting /governance/virtual-keys/:vkId/budgets/:budgetId/override.
  • Created BudgetOverrideDialog component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
  • The BudgetDisplay tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
  • Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
  1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
  2. Click Add override next to a budget line.
  3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
  4. Re-open the dialog and click Edit override to confirm existing values are pre-populated.
  5. Click Remove override and confirm the budget reverts to its base limit.
  6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
  7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

Screenshots/Recordings

Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

The override mutations respect the existing RbacResource.VirtualKeys / RbacOperation.Update permission check; the Add/Edit override button is disabled for users without that permission.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Budget overrides were added to governance contracts, utilities, API mutations, and virtual-key UI flows. Effective limits now drive usage, exhaustion, displays, and CSV exports. Test command modules update Bifrost core to v1.7.3.

Changes

Virtual-key budget overrides

Layer / File(s) Summary
Override contracts and calculations
ui/lib/types/governance.ts, ui/lib/types/schemas.ts, ui/lib/utils/governance.ts, ui/lib/utils/governance.test.ts, ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
Budget shapes support override amount, mode, and remaining cycles; schemas and helpers validate overrides, calculate effective limits, compute validity dates, and test override behavior.
Override API and dialog
ui/lib/store/apis/governanceApi.ts, ui/components/budgetOverrideDialog.tsx
PUT and DELETE governance mutations persist overrides, while the dialog supports cycles or forever modes, validation, removal, and error handling.
Virtual-key editing and details
ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx, ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
Virtual-key sheets add RBAC-gated override controls, mutation handlers, effective-limit displays, and override duration status.
Effective budget displays and exports
ui/components/budgetDisplay.tsx, ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts, ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
Usage, exhaustion state, progress displays, and CSV budget values use effective limits and active override data.

Go module updates

Layer / File(s) Summary
Bifrost core dependency updates
tests/cmd/e2eseed/go.mod, tests/cmd/seed/go.mod, tests/cmd/seedvks/go.mod
Bifrost core is updated from v1.7.1 to v1.7.3.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant BudgetOverrideDialog
  participant virtualKeySheet
  participant governanceApi
  participant VirtualKeyBudgetEndpoint
  Operator->>BudgetOverrideDialog: enter override amount and duration
  BudgetOverrideDialog->>virtualKeySheet: submit validated request
  virtualKeySheet->>governanceApi: set budget override
  governanceApi->>VirtualKeyBudgetEndpoint: PUT override request
  VirtualKeyBudgetEndpoint-->>governanceApi: updated budget and effective limit
  governanceApi-->>virtualKeySheet: mutation result and cache invalidation
  virtualKeySheet-->>Operator: render updated override and budget
Loading

Possibly related PRs

  • maximhq/bifrost#5436: Implements backend budget-override lifecycle and effective-limit enforcement corresponding to the UI fields and calculations in this change.

Suggested reviewers: pratham-mishra04, impoiler

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title names the main feature, but it's generic and lacks enough specificity to be a strong history summary. Use a more specific title like "Add budget overrides for virtual key budgets".
✅ Passed checks (3 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.
Description check ✅ Passed The description matches the template and covers summary, changes, testing, type, affected areas, security, and checklist.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-22-budget_overrides_ui

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

@akshaydeo
akshaydeo marked this pull request as ready for review July 21, 2026 22:45
This was referenced Jul 21, 2026

akshaydeo commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.


You're currently rate limited under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. Your next review will be available in 29 minutes.

@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from 05389e1 to 1e1c2e5 Compare July 22, 2026 08:08
@akshaydeo akshaydeo mentioned this pull request Jul 22, 2026
18 tasks

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from 1e1c2e5 to d2c4c2a Compare July 22, 2026 09:02
@akshaydeo
akshaydeo force-pushed the 07-22-budget_override_governance_store_updates branch from 46b5981 to 4657156 Compare July 22, 2026 09:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx (1)

73-113: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Rate-limit exhaustion logic is duplicated with a truthy-vs-null-check divergence across three implementations.

useVirtualKeyUsage.ts (lines 77-84) correctly uses != null guards when comparing rate-limit current usage against max limits. Two other call sites reimplement the same comparison with truthy guards (value && ...), which silently skip the edge case where current_usage is 0 and max_limit is also 0 (fully exhausted zero-limit) because 0 && ... never reaches the comparison. This PR already had to apply the same one-line getEffectiveBudgetLimit fix to all three places for the budget half of the check — the rate-limit half shows the duplication is real and prone to drift.

  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx#L73-L113: destructure and use isExhausted directly from useVirtualKeyUsage(virtualKey) (already called here) instead of recomputing it locally.
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx#L75-L82: this file doesn't use the hook (it maps over a raw VirtualKey[] for CSV export), so extract the shared exhaustion logic (budgets via getEffectiveBudgetLimit + rate limits via != null checks) into a reusable utility in ui/lib/utils/governance.ts and have both useVirtualKeyUsage.ts and virtualKeysToCSV call it.
🤖 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 `@ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx` around lines
73 - 113, The duplicated exhaustion logic must be centralized and reused. In
ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx lines 73-113,
destructure isExhausted from the existing useVirtualKeyUsage(virtualKey) call
and remove the local calculation. In
ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx lines 75-82, use a
shared utility from ui/lib/utils/governance.ts that checks budgets via
getEffectiveBudgetLimit and rate limits with != null guards; update
useVirtualKeyUsage.ts to call the same utility.
ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx (1)

75-82: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Rate-limit exhaustion check uses truthy comparisons instead of null-safe checks.

Same divergence as virtualKeyDetailsSheet.tsx: vk.rate_limit?.token_current_usage && vk.rate_limit?.token_max_limit && ... misses the zero-usage/zero-limit exhausted case that useVirtualKeyUsage.ts's != null version correctly catches. See consolidated comment below.

🤖 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 `@ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx` around lines 75 -
82, Update the isExhausted calculation in the virtual keys table to use
null-safe presence checks for token_current_usage, token_max_limit,
request_current_usage, and request_max_limit instead of truthiness checks.
Preserve the existing budget comparison and ensure zero-valued usage or limits
are still compared and can mark the key exhausted, matching
useVirtualKeyUsage.ts.
🧹 Nitpick comments (4)
ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts (1)

8-10: 📐 Maintainability & Code Quality | 🔵 Trivial

Duplicated override-mode literal instead of reusing BudgetOverrideMode.

override_mode?: "cycles" | "forever" re-declares the union that BudgetOverrideMode (in ui/lib/types/governance.ts) already exports. See consolidated comment below for the shared fix across files.

🤖 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 `@ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts` around lines 8 - 10,
Update the access profile type’s override_mode field to reuse the exported
BudgetOverrideMode type from governance.ts instead of redeclaring the "cycles" |
"forever" union. Preserve the field’s optionality and leave override_amount and
override_cycles_remaining unchanged.
ui/components/budgetOverrideDialog.tsx (2)

181-199: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

"Remove override" gives no loading feedback.

Unlike the codebase's established pattern (e.g., the Rotate Key button's "Rotating..." label), the destructive Remove button only becomes disabled while isSaving — no spinner or text change signals the in-flight request.

⏳ Suggested fix
 						<Button
 							type="button"
 							variant="destructive"
 							className="rounded-sm"
 							onClick={handleRemove}
 							disabled={isSaving}
 							data-testid="budget-override-remove"
 						>
-							Remove override
+							{isSaving ? "Removing..." : "Remove override"}
 						</Button>

As per path instructions, "For ui/**, check interactive workflows for loading, empty, error, and success states."

🤖 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 `@ui/components/budgetOverrideDialog.tsx` around lines 181 - 199, The Remove
override button in the budget override dialog lacks in-flight loading feedback.
Update the Button controlled by handleRemove and isSaving to use the established
loading presentation, including a spinner or loading label while isSaving, while
preserving its destructive styling and disabled behavior.

Source: Path instructions


132-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

"Duration" label isn't programmatically associated with the Select.

Unlike the amount/cycles fields (which pair Label htmlFor with matching Input id), the Duration Label has no htmlFor and SelectTrigger has no id, so screen readers can't associate them.

Note: adding id/htmlFor is the standard fix, but Radix's own tracker documents cases where Select.Trigger doesn't forward the id to the underlying element for full label association — worth confirming this project's Select wrapper actually resolves it before relying solely on that fix.

♿ Suggested fix (verify wrapper forwards id correctly)
-							<Label>Duration</Label>
-							<Select value={mode} onValueChange={(value) => setMode(value as "cycles" | "forever")} disabled={isSaving}>
-								<SelectTrigger className="w-full rounded-sm" data-testid="budget-override-mode">
+							<Label htmlFor={`budget-override-mode-${budget.id}`}>Duration</Label>
+							<Select value={mode} onValueChange={(value) => setMode(value as "cycles" | "forever")} disabled={isSaving}>
+								<SelectTrigger id={`budget-override-mode-${budget.id}`} className="w-full rounded-sm" data-testid="budget-override-mode">
🤖 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 `@ui/components/budgetOverrideDialog.tsx` around lines 132 - 143, Associate the
Duration label with the mode Select by adding a matching identifier to the
Label’s htmlFor and the SelectTrigger’s id. Update the project’s Select wrapper
usage around SelectTrigger to confirm the id reaches the underlying control; if
it does not, apply the wrapper-supported association mechanism while preserving
the existing mode and disabled behavior.
ui/lib/utils/governance.ts (1)

33-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Override-mode literal "cycles" | "forever" is duplicated in three places instead of reusing BudgetOverrideMode.

ui/lib/types/governance.ts already exports BudgetOverrideMode = "cycles" | "forever", but three other sites re-declare the same literal union inline. This is harmless today since the literals match, but any future change to the mode set (e.g., adding a new mode) requires updating all four locations in lockstep, and a mismatch would only surface as a runtime/type error rather than a compile-time one at the point of divergence.

  • ui/lib/utils/governance.ts#L33-L56: import BudgetOverrideMode and use it for BudgetOverrideFields.override_mode and validateBudgetOverride's mode parameter instead of "cycles" | "forever".
  • ui/components/budgetOverrideDialog.tsx#L32-L32: import BudgetOverrideMode from @/lib/types/governance (already imports Budget/BudgetOverrideRequest from there) and use it for the mode state type instead of "cycles" | "forever".
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts#L8-L10: use BudgetOverrideMode for override_mode if this fallback module is allowed to depend on @/lib/types/governance; otherwise leave as-is (verify whether this _fallbacks module is intentionally decoupled from the main lib tree).
🤖 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 `@ui/lib/utils/governance.ts` around lines 33 - 56, Centralize all
override-mode typing on the existing BudgetOverrideMode symbol. In
ui/lib/utils/governance.ts:33-56, import and use BudgetOverrideMode for
BudgetOverrideFields.override_mode and validateBudgetOverride’s mode parameter;
in ui/components/budgetOverrideDialog.tsx:32, use the same imported type for
mode state. In ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts:8-10, use
BudgetOverrideMode only if the fallback module may depend on the main governance
types; otherwise leave that declaration unchanged.
🤖 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 `@ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx`:
- Around line 311-327: Update the Provider Budgets override detail rendered by
the hasActiveBudgetOverride branch near UsageLine to append the same
cycles-remaining or “until removed” text used by the Budget Information section,
based on the budget’s override_mode. Reuse the existing duration calculation and
wording so both sections present identical override information.

---

Outside diff comments:
In `@ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx`:
- Around line 73-113: The duplicated exhaustion logic must be centralized and
reused. In ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx lines
73-113, destructure isExhausted from the existing useVirtualKeyUsage(virtualKey)
call and remove the local calculation. In
ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx lines 75-82, use a
shared utility from ui/lib/utils/governance.ts that checks budgets via
getEffectiveBudgetLimit and rate limits with != null guards; update
useVirtualKeyUsage.ts to call the same utility.

In `@ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx`:
- Around line 75-82: Update the isExhausted calculation in the virtual keys
table to use null-safe presence checks for token_current_usage, token_max_limit,
request_current_usage, and request_max_limit instead of truthiness checks.
Preserve the existing budget comparison and ensure zero-valued usage or limits
are still compared and can mark the key exhausted, matching
useVirtualKeyUsage.ts.

---

Nitpick comments:
In `@ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts`:
- Around line 8-10: Update the access profile type’s override_mode field to
reuse the exported BudgetOverrideMode type from governance.ts instead of
redeclaring the "cycles" | "forever" union. Preserve the field’s optionality and
leave override_amount and override_cycles_remaining unchanged.

In `@ui/components/budgetOverrideDialog.tsx`:
- Around line 181-199: The Remove override button in the budget override dialog
lacks in-flight loading feedback. Update the Button controlled by handleRemove
and isSaving to use the established loading presentation, including a spinner or
loading label while isSaving, while preserving its destructive styling and
disabled behavior.
- Around line 132-143: Associate the Duration label with the mode Select by
adding a matching identifier to the Label’s htmlFor and the SelectTrigger’s id.
Update the project’s Select wrapper usage around SelectTrigger to confirm the id
reaches the underlying control; if it does not, apply the wrapper-supported
association mechanism while preserving the existing mode and disabled behavior.

In `@ui/lib/utils/governance.ts`:
- Around line 33-56: Centralize all override-mode typing on the existing
BudgetOverrideMode symbol. In ui/lib/utils/governance.ts:33-56, import and use
BudgetOverrideMode for BudgetOverrideFields.override_mode and
validateBudgetOverride’s mode parameter; in
ui/components/budgetOverrideDialog.tsx:32, use the same imported type for mode
state. In ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts:8-10, use
BudgetOverrideMode only if the fallback module may depend on the main governance
types; otherwise leave that declaration unchanged.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 2320f252-3d28-462f-bf1d-27866852b1be

📥 Commits

Reviewing files that changed from the base of the PR and between 46b5981 and 1e1c2e5.

📒 Files selected for processing (14)
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetDisplay.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/lib/store/apis/governanceApi.ts
  • ui/lib/types/governance.ts
  • ui/lib/utils/governance.test.ts
  • ui/lib/utils/governance.ts

Comment thread ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
@akshaydeo
akshaydeo force-pushed the 07-22-budget_override_governance_store_updates branch from 4657156 to 6b8024f Compare July 22, 2026 09:30
@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from d2c4c2a to d59302d Compare July 22, 2026 09:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/lib/utils/governance.ts`:
- Around line 52-54: Update validateBudgetOverride to require
Number.isSafeInteger for positive cycle counts instead of only Number.isInteger.
In the date-calculation logic covering the affected range, reject unsafe or
arithmetic-invalid cycle values and return null when the resulting expiry date
is invalid, while preserving valid-date behavior.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 477edb63-ed5c-43c1-a19a-e78c6edf2f2f

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1c2e5 and d59302d.

📒 Files selected for processing (14)
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetDisplay.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/lib/store/apis/governanceApi.ts
  • ui/lib/types/governance.ts
  • ui/lib/utils/governance.test.ts
  • ui/lib/utils/governance.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • tests/cmd/seedvks/go.mod
  • ui/lib/utils/governance.test.ts
  • tests/cmd/seed/go.mod
  • tests/cmd/e2eseed/go.mod
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/lib/store/apis/governanceApi.ts
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
  • ui/lib/types/governance.ts

Comment thread ui/lib/utils/governance.ts Outdated
@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from d59302d to 1504eb2 Compare July 22, 2026 16:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@ui/components/budgetOverrideDialog.tsx`:
- Around line 46-54: Update handleSubmit in BudgetOverrideDialog to validate the
form through a Zod schema defined in ui/lib/types/schemas.ts, including
meaningful field validation messages. Replace the validation-only
validateBudgetOverride flow with the schema result, map its errors into the
dialog’s setError handling, and preserve submission only when parsing succeeds.

In `@ui/lib/utils/governance.ts`:
- Around line 86-99: Update the calendar-aligned branches in the duration expiry
logic for “M” and “y”/“Y” so month-end and leap-day start dates are clamped to
the target month’s final day rather than overflowing into the following month.
Preserve the existing non-calendar calculations and use the computed target
year/month when applying the clamp.
🪄 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: CHILL

Plan: Pro Plus

Run ID: d0a8cece-1154-46d3-8c2c-a55bd858486d

📥 Commits

Reviewing files that changed from the base of the PR and between d59302d and 1504eb2.

📒 Files selected for processing (14)
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetDisplay.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/lib/store/apis/governanceApi.ts
  • ui/lib/types/governance.ts
  • ui/lib/utils/governance.test.ts
  • ui/lib/utils/governance.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • ui/lib/utils/governance.test.ts
  • tests/cmd/seedvks/go.mod
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • tests/cmd/seed/go.mod
  • tests/cmd/e2eseed/go.mod
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/lib/types/governance.ts
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetDisplay.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx

Comment thread ui/components/budgetOverrideDialog.tsx
Comment thread ui/lib/utils/governance.ts
@akshaydeo
akshaydeo force-pushed the 07-22-budget_override_governance_store_updates branch from 6b8024f to bda0931 Compare July 22, 2026 16:54
@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch 2 times, most recently from a34e661 to 65b87f1 Compare July 22, 2026 18:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
ui/lib/utils/governance.test.ts (2)

21-26: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add boundary cases for cycle validation.

Only fractional cycles are tested. Add cases for 0, negative values, and missing cycles when mode is "cycles" to cover every rejection path in the schema refinement.

🤖 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 `@ui/lib/utils/governance.test.ts` around lines 21 - 26, Add boundary
assertions to the “validates positive amounts and whole finite cycle counts”
test for validateBudgetOverride: verify that cycles mode rejects 0, negative
values, and a missing cycle count. Keep the existing fractional rejection and
valid cycle/forever cases unchanged.

12-19: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the incomplete override branch.

This test claims to cover “incomplete or expired” state, but only exercises a complete finite override with zero remaining cycles. Add a fixture with missing override fields and verify the effective limit remains max_limit.

🤖 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 `@ui/lib/utils/governance.test.ts` around lines 12 - 19, Add an incomplete
override fixture to the test case for hasActiveBudgetOverride and
getEffectiveBudgetLimit, omitting required override fields while retaining
max_limit. Assert that the incomplete state is inactive and
getEffectiveBudgetLimit returns the original max_limit, while preserving the
existing expired finite-override assertions.
🤖 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.

Nitpick comments:
In `@ui/lib/utils/governance.test.ts`:
- Around line 21-26: Add boundary assertions to the “validates positive amounts
and whole finite cycle counts” test for validateBudgetOverride: verify that
cycles mode rejects 0, negative values, and a missing cycle count. Keep the
existing fractional rejection and valid cycle/forever cases unchanged.
- Around line 12-19: Add an incomplete override fixture to the test case for
hasActiveBudgetOverride and getEffectiveBudgetLimit, omitting required override
fields while retaining max_limit. Assert that the incomplete state is inactive
and getEffectiveBudgetLimit returns the original max_limit, while preserving the
existing expired finite-override assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 14d150d4-b912-4d1a-a4f0-b15de4fe6733

📥 Commits

Reviewing files that changed from the base of the PR and between 1504eb2 and 65b87f1.

📒 Files selected for processing (15)
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetDisplay.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/lib/store/apis/governanceApi.ts
  • ui/lib/types/governance.ts
  • ui/lib/types/schemas.ts
  • ui/lib/utils/governance.test.ts
  • ui/lib/utils/governance.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seedvks/go.mod
  • tests/cmd/seed/go.mod
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • ui/app/_fallbacks/enterprise/lib/types/accessProfile.ts
  • ui/components/budgetDisplay.tsx
  • ui/lib/store/apis/governanceApi.ts
  • ui/lib/types/governance.ts
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/budgetOverrideDialog.tsx
  • ui/app/workspace/virtual-keys/hooks/useVirtualKeyUsage.ts
  • ui/app/workspace/virtual-keys/views/virtualKeyDetailsSheet.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 22, 2026
@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from 65b87f1 to 55a0b95 Compare July 22, 2026 22:10
@akshaydeo
akshaydeo force-pushed the 07-22-budget_override_governance_store_updates branch from bda0931 to 97cb796 Compare July 22, 2026 22:10

akshaydeo commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Jul 23, 10:47 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 23, 10:47 AM UTC: Graphite couldn't merge this pull request because a downstack PR budget overrides: db changes #5434 failed to merge.
  • Jul 23, 10:50 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 23, 10:52 AM UTC: Graphite couldn't merge this pull request because a downstack PR vk budget overrides: APIs #5435 failed to merge.
  • Jul 23, 3:20 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 23, 3:25 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo force-pushed the 07-22-budget_overrides_ui branch from 55a0b95 to 95f798b Compare July 23, 2026 15:04
@akshaydeo
akshaydeo force-pushed the 07-22-budget_override_governance_store_updates branch from 97cb796 to 26e0572 Compare July 23, 2026 15:04
@akshaydeo
akshaydeo changed the base branch from 07-22-budget_override_governance_store_updates to graphite-base/5443 July 23, 2026 15:22
@akshaydeo
akshaydeo changed the base branch from graphite-base/5443 to dev July 23, 2026 15:25
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review July 23, 2026 15:25

The base branch was changed.

@akshaydeo
akshaydeo merged commit 11edb4d into dev Jul 23, 2026
11 of 12 checks passed
@akshaydeo
akshaydeo deleted the 07-22-budget_overrides_ui branch July 23, 2026 15:25
akshaydeo added a commit that referenced this pull request Jul 24, 2026
## Summary

Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

## Changes

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

## Screenshots/Recordings

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo added a commit that referenced this pull request Jul 29, 2026
Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

- [ ] Yes
- [x] No

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo added a commit that referenced this pull request Jul 30, 2026
Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

- [ ] Yes
- [x] No

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo added a commit that referenced this pull request Jul 30, 2026
Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

- [ ] Yes
- [x] No

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo added a commit that referenced this pull request Jul 30, 2026
Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

- [ ] Yes
- [x] No

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
## Summary

Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

## Changes

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

## Screenshots/Recordings

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
## Summary

Adds support for additive budget overrides on virtual key budgets, allowing operators to temporarily increase a virtual key's spending capacity beyond its base limit without modifying the base budget itself.

## Changes

- Added `override_amount`, `override_mode`, and `override_cycles_remaining` fields to the `Budget` type, along with `BudgetOverrideRequest` and `BudgetOverrideResponse` types.
- Introduced three utility functions in `governance.ts`: `hasActiveBudgetOverride`, `getEffectiveBudgetLimit`, and `validateBudgetOverride`. These handle override state detection, effective limit calculation, and input validation respectively.
- Replaced all direct references to `b.max_limit` in exhaustion checks, progress bars, and CSV exports with `getEffectiveBudgetLimit(b)` so overrides are reflected everywhere budgets are displayed or evaluated.
- Added `setVirtualKeyBudgetOverride` (PUT) and `removeVirtualKeyBudgetOverride` (DELETE) RTK Query mutations to `governanceApi`, targeting `/governance/virtual-keys/:vkId/budgets/:budgetId/override`.
- Created `BudgetOverrideDialog` component that lets operators add, edit, or remove an override on a single budget. The dialog supports two modes: a fixed number of reset cycles or indefinite ("until removed"). It is surfaced in the virtual key detail sheet for non-managed keys.
- The `BudgetDisplay` tooltip and inline label now show an "override" badge and a breakdown of base + override amounts when an active override is present.
- Added unit tests covering effective limit calculation, expired/incomplete override detection, and input validation.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Open a virtual key detail sheet for a key that is not managed by an access profile and has at least one budget with a persisted ID.
2. Click **Add override** next to a budget line.
3. Enter an additional amount, select a mode (cycles or forever), and save. Verify the usage bar and effective limit update immediately.
4. Re-open the dialog and click **Edit override** to confirm existing values are pre-populated.
5. Click **Remove override** and confirm the budget reverts to its base limit.
6. Verify that a key whose usage meets or exceeds the effective limit (base + override) is shown as exhausted.
7. Export virtual keys to CSV and confirm the Budget Limit column reflects the effective limit.

## Screenshots/Recordings

_Add before/after screenshots of the virtual key detail sheet showing the override badge, breakdown text, and dialog._

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

The override mutations respect the existing `RbacResource.VirtualKeys` / `RbacOperation.Update` permission check; the **Add/Edit override** button is disabled for users without that permission.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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