From e84be6956a148882af03cf22a807093a4c909514 Mon Sep 17 00:00:00 2001 From: claude-ceo-assistant Date: Tue, 26 May 2026 17:02:43 -0700 Subject: [PATCH] refactor(canvas): drop org-tier inherit/source from LLM Billing Config section (internal#691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per CTO direction 2026-05-26: the org tier is gone. The Config-tab dropdown now shows the workspace-level mode directly with no "Inherit from org default" option and no resolved-vs-override source line — those distinctions are moot when the workspace is the only policy layer. Changes - LLMBillingSection: dropdown choices reduce to {platform_managed | byok | disabled}. Every change PUTs an explicit {mode: }; the {mode: null} clear path is no longer reachable from the UI (the server still accepts it for the admin CLI / ops use). - BillingModeResolution: drop org_default field; source enum drops org_default variant (matches the workspace-server wire shape post-refactor). - Drop SOURCE_LABELS and the source/org-default lines from the rendered card. Show "Current mode: " only. - Tests: re-author cases against the new wire shape. The garbled-override warning case is kept (defense in depth against CHECK-constraint drift). - Garbled-override warning copy: "ignored" → "ignored. Pick a valid mode above to overwrite the corrupt value." (the "clear" affordance is gone). Backward compat - The per-tenant GET/PUT routes are unchanged; the wire shape removal lines up with the workspace-server resolver simplification (sibling PR). Pre- written byok overrides on agents-team's 3 workspaces continue to be rendered correctly via resolved_mode. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../__tests__/llm-billing-section.test.tsx | 53 +++++------- .../tabs/config/llm-billing-section.tsx | 85 +++++++------------ 2 files changed, 53 insertions(+), 85 deletions(-) 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 && (
- Resolved mode: {resolution.resolved_mode}{" "} - - ({SOURCE_LABELS[resolution.source]}) - -
-
- Org default: {resolution.org_default} + Current mode: {resolution.resolved_mode}