diff --git a/canvas/src/components/tabs/config/__tests__/llm-billing-section.test.tsx b/canvas/src/components/tabs/config/__tests__/llm-billing-section.test.tsx
index 1875f8a9c..d6c296f48 100644
--- a/canvas/src/components/tabs/config/__tests__/llm-billing-section.test.tsx
+++ b/canvas/src/components/tabs/config/__tests__/llm-billing-section.test.tsx
@@ -9,10 +9,12 @@ import {
} from "@testing-library/react";
import { LLMBillingSection } from "../llm-billing-section";
-// Tests for LLMBillingSection (internal#691). Locks in:
-// - the section renders the resolved mode + source label
-// - the dropdown maps "inherit" → PUT {mode: null}
-// - the dropdown maps "byok" → PUT {mode: "byok"}
+// Tests for LLMBillingSection (internal#691 + 2026-05-26 simplification).
+// Post-CTO direction: no org-tier, no "inherit" option. The dropdown is
+// strictly {platform_managed | byok | disabled} and every change PUTs an
+// explicit mode string. Locks in:
+// - the section renders the resolved mode
+// - the dropdown maps each choice → PUT {mode: choice} (no null body)
// - a garbled override surfaces the warning banner
// - the post-write resolution updates the UI without a refetch
@@ -51,14 +53,13 @@ afterEach(() => {
cleanup();
});
-describe("LLMBillingSection — internal#691", () => {
- it("renders the resolved mode + source for an inherited workspace", async () => {
+describe("LLMBillingSection — internal#691 post-org-tier-removal", () => {
+ it("renders the resolved mode for a constant-fallback workspace", async () => {
apiGet.mockResolvedValueOnce({
workspace_id: "ws-1",
resolved_mode: "platform_managed",
workspace_override: null,
- org_default: "platform_managed",
- source: "org_default",
+ source: "constant_fallback",
});
render();
@@ -68,12 +69,7 @@ describe("LLMBillingSection — internal#691", () => {
"/admin/workspaces/ws-1/llm-billing-mode",
);
});
- // Resolved mode appears.
- expect(screen.getByText(/Resolved mode:/i).textContent).toMatch(/platform_managed/);
- // Source label appears.
- expect(
- screen.getByText(/inherited from org default/i),
- ).toBeTruthy();
+ expect(screen.getByText(/Current mode:/i).textContent).toMatch(/platform_managed/);
});
it('PUTs {mode: "byok"} when user picks BYOK and reflects the new resolution', async () => {
@@ -81,14 +77,12 @@ describe("LLMBillingSection — internal#691", () => {
workspace_id: "ws-2",
resolved_mode: "platform_managed",
workspace_override: null,
- org_default: "platform_managed",
- source: "org_default",
+ source: "constant_fallback",
});
apiPut.mockResolvedValueOnce({
workspace_id: "ws-2",
resolved_mode: "byok",
workspace_override: "byok",
- org_default: "platform_managed",
source: "workspace_override",
});
@@ -96,7 +90,7 @@ describe("LLMBillingSection — internal#691", () => {
await waitFor(() => expect(apiGet).toHaveBeenCalled());
const select = (await screen.findByLabelText(
- /llm billing mode override/i,
+ /llm billing mode/i,
)) as HTMLSelectElement;
fireEvent.change(select, { target: { value: "byok" } });
@@ -106,42 +100,38 @@ describe("LLMBillingSection — internal#691", () => {
{ mode: "byok" },
);
});
- // Post-write resolution propagated to UI.
+ // Post-write resolution propagated to UI: current mode is now byok.
await waitFor(() => {
- expect(
- screen.getByText(/explicit override on this workspace/i),
- ).toBeTruthy();
+ expect(screen.getByText(/Current mode:/i).textContent).toMatch(/byok/);
});
});
- it("PUTs {mode: null} when user picks Inherit (clears the override)", async () => {
+ it('PUTs {mode: "platform_managed"} when user picks platform-managed (no null/inherit path)', async () => {
apiGet.mockResolvedValueOnce({
workspace_id: "ws-3",
resolved_mode: "byok",
workspace_override: "byok",
- org_default: "platform_managed",
source: "workspace_override",
});
apiPut.mockResolvedValueOnce({
workspace_id: "ws-3",
resolved_mode: "platform_managed",
- workspace_override: null,
- org_default: "platform_managed",
- source: "org_default",
+ workspace_override: "platform_managed",
+ source: "workspace_override",
});
render();
await waitFor(() => expect(apiGet).toHaveBeenCalled());
const select = (await screen.findByLabelText(
- /llm billing mode override/i,
+ /llm billing mode/i,
)) as HTMLSelectElement;
- fireEvent.change(select, { target: { value: "inherit" } });
+ fireEvent.change(select, { target: { value: "platform_managed" } });
await waitFor(() => {
expect(apiPut).toHaveBeenCalledWith(
"/admin/workspaces/ws-3/llm-billing-mode",
- { mode: null },
+ { mode: "platform_managed" },
);
});
});
@@ -151,8 +141,7 @@ describe("LLMBillingSection — internal#691", () => {
workspace_id: "ws-4",
resolved_mode: "platform_managed", // resolver fell through, default-closed
workspace_override: "byokk", // typo persisted somehow
- org_default: "platform_managed",
- source: "org_default",
+ source: "constant_fallback",
});
render();
diff --git a/canvas/src/components/tabs/config/llm-billing-section.tsx b/canvas/src/components/tabs/config/llm-billing-section.tsx
index 16498258e..447633512 100644
--- a/canvas/src/components/tabs/config/llm-billing-section.tsx
+++ b/canvas/src/components/tabs/config/llm-billing-section.tsx
@@ -3,17 +3,21 @@
// llm-billing-section.tsx — Config-tab section for the per-workspace
// llm_billing_mode override (internal#691).
//
+// Post-CTO-simplification (2026-05-26 23:54Z): there is no org-tier
+// default. The workspace is the unit of decision. The dropdown shows the
+// workspace-level value directly; there is no "inherit" option and no
+// org_default display. NULL on the server side resolves via constant
+// fallback to platform_managed (the bootstrap floor) and the dropdown
+// reflects that as the current value.
+//
// Surfaces:
-// - The currently RESOLVED mode for this workspace (the mode the
+// - The currently resolved mode for this workspace (the mode the
// workspace-server's strip gate will use at next provision).
-// - The org-level default (so the user sees what they're inheriting).
-// - A dropdown to set / clear the workspace-level override.
-// - A "source" line so operators can answer "is this inherited or
-// explicit?" without DB archeology (RFC Observability hot-spot).
+// - A dropdown to set the workspace-level mode.
//
// Hits:
// GET /admin/workspaces/:id/llm-billing-mode — read resolution
-// PUT /admin/workspaces/:id/llm-billing-mode — write {mode: "..."|null}
+// PUT /admin/workspaces/:id/llm-billing-mode — write {mode: "..."}
//
// Both routes are on the per-tenant workspace-server (same origin as the
// other canvas /admin calls). CP's proxy at /cp/admin/workspaces/:id/
@@ -26,34 +30,36 @@ import { Section } from "./form-inputs";
// Mirrors workspace-server/internal/handlers/llm_billing_mode.go::BillingModeResolution.
// Kept as a literal shape (not imported) because canvas has no Go-type bridge.
+//
+// Note: `source` is still part of the wire response (operator debug — see
+// the Go-side comment) but the canvas does not render it post-simplification
+// since there's no policy-source distinction left to surface to a workspace
+// user. Operators reading the admin route directly still get the field.
export interface BillingModeResolution {
workspace_id: string;
resolved_mode: "platform_managed" | "byok" | "disabled";
- // Pointer-typed on the Go side: nil = inherit, non-nil = the raw
- // workspace-level override (even if garbled and falling through).
+ // Pointer-typed on the Go side: nil = no explicit override (constant
+ // fallback applies), non-nil = the raw workspace-level override (even
+ // if garbled and falling through).
workspace_override: string | null;
- org_default: "platform_managed" | "byok" | "disabled";
- source: "workspace_override" | "org_default" | "constant_fallback";
+ source: "workspace_override" | "constant_fallback";
}
-// The dropdown emits one of these values. "inherit" is the UX-only label
-// that maps to a `null` body in the PUT request.
-type DropdownChoice = "inherit" | "platform_managed" | "byok" | "disabled";
+// The dropdown emits one of these values. There is no "inherit" option
+// after the org-tier removal — every choice maps to an explicit PUT body.
+type DropdownChoice = "platform_managed" | "byok" | "disabled";
interface Props {
workspaceId: string;
}
const MODE_LABELS: Record = {
- inherit: "Inherit from org default",
platform_managed: "Platform-managed (uses Molecule credits)",
byok: "BYOK (your own OAuth / vendor keys)",
disabled: "Disabled (no LLM access)",
};
const MODE_DESCRIPTIONS: Record = {
- inherit:
- "Use whichever mode is set at the organization level. Recommended unless this specific workspace needs a different billing source.",
platform_managed:
"Strip CLAUDE_CODE_OAUTH_TOKEN and vendor API keys from the workspace; route all LLM traffic through Molecule's proxy and bill your org credits.",
byok:
@@ -62,13 +68,6 @@ const MODE_DESCRIPTIONS: Record = {
"Block all LLM access for this workspace. Useful for sandbox workspaces that should not consume credits or hit external providers.",
};
-const SOURCE_LABELS: Record = {
- workspace_override: "explicit override on this workspace",
- org_default: "inherited from org default",
- constant_fallback:
- "fallback (workspace + org defaults missing or unrecognized — defaulted to platform_managed)",
-};
-
export function LLMBillingSection({ workspaceId }: Props) {
const [resolution, setResolution] = useState(
null,
@@ -97,23 +96,11 @@ export function LLMBillingSection({ workspaceId }: Props) {
void load();
}, [load]);
- // Current dropdown selection is derived from the resolution. If the
- // override is null, we show "inherit"; otherwise we mirror the raw
- // workspace_override (NOT resolved_mode — that would conflate "explicit
- // platform_managed override" with "inherit while org happens to be
- // platform_managed", which has different semantics on the write side).
- const currentChoice: DropdownChoice = (() => {
- if (!resolution) return "inherit";
- if (resolution.workspace_override == null) return "inherit";
- const raw = resolution.workspace_override;
- if (raw === "platform_managed" || raw === "byok" || raw === "disabled") {
- return raw;
- }
- // Garbled value persisted via some external write. Show inherit so
- // the user can pick a clean value; on save they'll either clear it
- // (PUT null) or overwrite it with a valid one.
- return "inherit";
- })();
+ // Dropdown selection mirrors the resolved mode. With no org tier, the
+ // resolved mode is either the explicit workspace override or the
+ // constant-fallback platform_managed; either way the user can see what
+ // the strip gate will do at next provision and pick a different value.
+ const currentChoice: DropdownChoice = resolution?.resolved_mode ?? "platform_managed";
const handleChange = async (choice: DropdownChoice) => {
if (!resolution) return;
@@ -121,11 +108,9 @@ export function LLMBillingSection({ workspaceId }: Props) {
setError(null);
setSuccess(false);
try {
- // "inherit" → PUT {mode: null}; otherwise → PUT {mode: choice}.
- const body = choice === "inherit" ? { mode: null } : { mode: choice };
const updated = await api.put(
`/admin/workspaces/${workspaceId}/llm-billing-mode`,
- body,
+ { mode: choice },
);
setResolution(updated);
setSuccess(true);
@@ -156,24 +141,18 @@ export function LLMBillingSection({ workspaceId }: Props) {
{resolution && (