From 120b3a25aa099dbf6ea3ef986ad30c71e04367b3 Mon Sep 17 00:00:00 2001 From: claude-ceo-assistant Date: Fri, 8 May 2026 08:55:19 -0700 Subject: [PATCH] feat(workspaces): update_tier column for canary vs production fan-out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes core#115 partial. Schema-only change; the apply-endpoint filter logic that reads this column lands with core#123 (drift detector + queue + apply endpoint, the deferred follow-up of core#113). Default 'production' so existing customers (Reno-Stars + any future tenant) are default-safe. Synthetic dogfooding workspaces opt INTO 'canary' explicitly. CHECK constraint pins the closed value set ('canary' | 'production') — the apply endpoint's filter relies on the database to reject anything else, so a future operator typo in PATCH /workspaces/:id ({update_tier: 'canery'}) returns a constraint violation, not silent fan-out to nobody. Partial index on canary rows since the apply-endpoint query path ('apply this update only to canary tier first') hits canary much more often than production, and the production set is the much larger default. WHAT THIS DOES NOT DO (lands with core#123) - PATCH endpoint to flip a workspace to canary - The apply endpoint that consults the column - Tests that exercise canary-vs-production fan-out Schema-only foundation; same pattern as core#113 (workspace_plugins). PHASE 4 SELF-REVIEW Correctness: No finding — IF NOT EXISTS guards, DEFAULT clause means existing rows get 'production' on migration apply. Readability: No finding — comment block documents the tier semantics + the deferral to core#123. Architecture: No finding — additive ALTER, partial index for the expected access pattern. Security: No finding — no code path; column constraint reduces blast radius of bad PATCH input. Performance: No finding — partial index minimizes write amplification on the production-default rows. REFS core#115 — this issue core#123 — apply endpoint follow-up (will exercise this column) core#113 — version subscription DB foundation (sibling pattern) Co-Authored-By: Claude Opus 4.7 (1M context) --- ...0508170000_workspaces_update_tier.down.sql | 2 ++ ...260508170000_workspaces_update_tier.up.sql | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 workspace-server/migrations/20260508170000_workspaces_update_tier.down.sql create mode 100644 workspace-server/migrations/20260508170000_workspaces_update_tier.up.sql diff --git a/workspace-server/migrations/20260508170000_workspaces_update_tier.down.sql b/workspace-server/migrations/20260508170000_workspaces_update_tier.down.sql new file mode 100644 index 00000000..2bb00727 --- /dev/null +++ b/workspace-server/migrations/20260508170000_workspaces_update_tier.down.sql @@ -0,0 +1,2 @@ +DROP INDEX IF EXISTS workspaces_update_tier_canary; +ALTER TABLE workspaces DROP COLUMN IF EXISTS update_tier; diff --git a/workspace-server/migrations/20260508170000_workspaces_update_tier.up.sql b/workspace-server/migrations/20260508170000_workspaces_update_tier.up.sql new file mode 100644 index 00000000..4ed9d522 --- /dev/null +++ b/workspace-server/migrations/20260508170000_workspaces_update_tier.up.sql @@ -0,0 +1,26 @@ +-- workspaces.update_tier — canary vs production filter for plugin updates +-- (core#115). Composes with the version-subscription DB foundation +-- (core#113, merged) and the upcoming drift+queue+apply endpoint +-- (core#123). +-- +-- Tiers: +-- 'production' (default) — fan-out target; only updated AFTER canary soak +-- 'canary' — early-adopter target; updates land here first +-- +-- Default 'production' so existing customers (Reno-Stars + any future +-- live tenant) are default-safe. Synthetic dogfooding workspaces opt +-- INTO 'canary' explicitly. +-- +-- The column is just metadata at this layer; the actual filter logic +-- ('apply this update only to canary tier first') lives in the future +-- POST /admin/plugin-updates/:id/apply endpoint (core#123). + +ALTER TABLE workspaces + ADD COLUMN IF NOT EXISTS update_tier TEXT NOT NULL DEFAULT 'production' + CHECK (update_tier IN ('canary', 'production')); + +-- Partial index for the apply endpoint's canary-tier scan: only +-- index canary rows since the apply path queries them most often +-- and the production set is the much larger default. +CREATE INDEX IF NOT EXISTS workspaces_update_tier_canary + ON workspaces(update_tier) WHERE update_tier = 'canary';