From 7abb94dab8f8946f313399a9d88a2dd49702dc93 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Sun, 3 May 2026 05:56:18 -0700 Subject: [PATCH] fix(canvas): align tier text contracts with 4-tier reality (T1/T2/T3/T4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tier system in CreateWorkspaceDialog and design-tokens has been T1 Sandboxed / T2 Standard / T3 Privileged / T4 Full Access, but two chrome surfaces still showed the older 3-tier mapping with T3 as "Full Access": - Legend (bottom-left chrome on every canvas page) listed only T1/T2/T3 and called T3 "Full Access". On a SaaS tenant the actual workspace badges render T4 (in amber/warm) — there was no T4 entry in the legend at all, so the user sees an undocumented orange badge. - ConfigTab tier dropdown (per-workspace settings → Sandboxing) had no T4 option at all and called T3 "Full Access". So an existing T4 workspace would show "T3 — Full Access" as the selected option, silently downgrading the displayed tier on the settings panel. - tenant.ts isSaaSTenant() doc comment claimed SaaS workspaces are "inherently T3 Full Access" — wrong on both the number and the lock rationale (SaaS hides T1/T2/T3, not just T1/T2). Fix: - Legend now imports TIER_CONFIG and renders all four tiers (Sandboxed/Standard/Privileged/Full Access) using the same color swatches as the badges on workspace cards. Eliminates the previous drift where Legend's hardcoded sky/violet/warm chips didn't match the gray/sky/violet/amber actually rendered on nodes. - ConfigTab adds the missing T4 — Full Access option and renames T3 to Privileged. - tenant.ts comment updated to match the picker's actual hide list. Co-Authored-By: Claude Opus 4.7 (1M context) --- canvas/src/components/Legend.tsx | 20 ++++++++++++++++---- canvas/src/components/tabs/ConfigTab.tsx | 3 ++- canvas/src/lib/tenant.ts | 4 ++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/canvas/src/components/Legend.tsx b/canvas/src/components/Legend.tsx index 647479ef..c6d67365 100644 --- a/canvas/src/components/Legend.tsx +++ b/canvas/src/components/Legend.tsx @@ -1,11 +1,23 @@ "use client"; import { useEffect, useState } from "react"; -import { STATUS_CONFIG } from "@/lib/design-tokens"; +import { STATUS_CONFIG, TIER_CONFIG } from "@/lib/design-tokens"; import { useCanvasStore } from "@/store/canvas"; const LEGEND_STATUSES = ["online", "provisioning", "degraded", "failed", "paused", "offline"] as const; +// Tier descriptions kept in sync with CreateWorkspaceDialog.tsx (the +// source of truth for what each tier means semantically). Colors come +// from TIER_CONFIG so the legend swatch matches the badge actually +// rendered on every WorkspaceNode — drift here misled users into +// thinking the legend documented a different tier than the one shown. +const LEGEND_TIERS: ReadonlyArray<{ tier: number; label: string }> = [ + { tier: 1, label: "Sandboxed" }, + { tier: 2, label: "Standard" }, + { tier: 3, label: "Privileged" }, + { tier: 4, label: "Full Access" }, +]; + // Persist the user's choice across sessions. Default is "open" so // first-time users still see the symbol key; once dismissed we // respect that until they explicitly reopen via the floating pill. @@ -102,9 +114,9 @@ export function Legend() {
Tier
- - - + {LEGEND_TIERS.map(({ tier, label }) => ( + + ))}
diff --git a/canvas/src/components/tabs/ConfigTab.tsx b/canvas/src/components/tabs/ConfigTab.tsx index da2eb206..8682073b 100644 --- a/canvas/src/components/tabs/ConfigTab.tsx +++ b/canvas/src/components/tabs/ConfigTab.tsx @@ -655,7 +655,8 @@ export function ConfigTab({ workspaceId }: Props) { > - + + diff --git a/canvas/src/lib/tenant.ts b/canvas/src/lib/tenant.ts index 13881037..095b1391 100644 --- a/canvas/src/lib/tenant.ts +++ b/canvas/src/lib/tenant.ts @@ -59,8 +59,8 @@ export function getTenantSlug(): string { * isSaaSTenant reports whether the canvas is running as the UI for a * SaaS tenant (served at .moleculesai.app). Use for client-side * UX branches that should behave differently on SaaS vs self-hosted — - * e.g. the workspace tier picker hides T1/T2 sandbox tiers because every - * SaaS workspace gets its own EC2 VM (inherently T3 Full Access). + * e.g. the workspace tier picker hides T1/T2/T3 sandbox tiers because + * every SaaS workspace gets its own EC2 VM (inherently T4 Full Access). * * SSR-safe: returns false on the server to avoid hydration drift; call * sites should tolerate a flip from false→true on first client render.