From 0e4d55b895ab63ef1a1150a71bd92919dae3ba0b Mon Sep 17 00:00:00 2001 From: Phil Merrell Date: Tue, 7 Jul 2026 20:57:09 -0600 Subject: [PATCH] chore(memory): default Memory Spaces ON with a kill switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Memory Spaces is a complete feature (CRUD + SPA panel + agent binding), so it should ship enabled for every deployer/forker — opt-out, not opt-in — matching the kbSync / scheduledRuns convention. The table + bucket are already provisioned unconditionally in PlatformStack, so this only flips the runtime MEMORY_SPACES_ENABLED env var; no new infra footprint. - config.ts: memorySpaces.enabled default true (empty/unset workflow var = on, only literal "false" disables); interface + block docs updated - platform.yml: forward CDK_MEMORY_SPACES_ENABLED (kill switch) and CDK_AGENTS_API_ENABLED (per-env enable for the still-default-off /agents surface, so dev can turn it on for dogfooding without a code change) - app-api-environment.ts: comment reflects default-on - config.test.ts: 5 tests locking default-on + kill-switch + context override Agent Designer (AGENTS_API_ENABLED) stays default OFF until the Phase-4 Designer UI ships — a headless /agents surface helps no forker. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/platform.yml | 10 +++++ infrastructure/lib/config.ts | 27 +++++++------ .../constructs/app-api/app-api-environment.ts | 2 +- infrastructure/test/config.test.ts | 38 +++++++++++++++++++ 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/.github/workflows/platform.yml b/.github/workflows/platform.yml index 335b7135..1f7ac6ca 100644 --- a/.github/workflows/platform.yml +++ b/.github/workflows/platform.yml @@ -102,6 +102,16 @@ jobs: # (on). Set the `CDK_SCHEDULED_RUNS_ENABLED` variable to "false" in # an environment only to dark-stop the feature there. CDK_SCHEDULED_RUNS_ENABLED: ${{ vars.CDK_SCHEDULED_RUNS_ENABLED }} + # Memory Spaces (user-owned markdown "second brain" + agent binding). + # Default ON with a kill switch: unset resolves to empty string, which + # config.ts treats as the default (on). Set the `CDK_MEMORY_SPACES_ENABLED` + # variable to "false" in an environment only to dark-stop the feature there. + CDK_MEMORY_SPACES_ENABLED: ${{ vars.CDK_MEMORY_SPACES_ENABLED }} + # Agent Designer /agents surface. Default OFF (opt-in) until the Phase-4 + # Designer UI ships — a headless API helps no forker. Set the + # `CDK_AGENTS_API_ENABLED` variable to "true" in an environment (e.g. dev) + # to enable it there for dogfooding. + CDK_AGENTS_API_ENABLED: ${{ vars.CDK_AGENTS_API_ENABLED }} # Secrets AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} diff --git a/infrastructure/lib/config.ts b/infrastructure/lib/config.ts index 989eea2c..1ad0dd5c 100644 --- a/infrastructure/lib/config.ts +++ b/infrastructure/lib/config.ts @@ -160,10 +160,12 @@ export interface ScheduledRunsConfig { } /** - * Memory Spaces feature flag. Default OFF with an on switch — the feature - * is opt-in per environment, enabled with CDK_MEMORY_SPACES_ENABLED=true - * (or a `memorySpaces.enabled: true` cdk.json context). Sets the - * MEMORY_SPACES_ENABLED env var on app-api and inference-api. + * Memory Spaces feature flag. Default ON with a kill switch — the feature is + * complete and ships enabled for every deployer (opt-out), disabled per + * environment with CDK_MEMORY_SPACES_ENABLED=false (or a + * `memorySpaces.enabled: false` cdk.json context). Sets the + * MEMORY_SPACES_ENABLED env var on app-api and inference-api. The table + bucket + * are provisioned unconditionally, so this only gates route mounting at runtime. */ export interface MemorySpacesConfig { enabled: boolean; @@ -328,15 +330,16 @@ export function loadConfig(scope: cdk.App): AppConfig { : scope.node.tryGetContext('scheduledRuns')?.enabled ?? true, }, memorySpaces: { - // Default OFF with an on switch: the feature is opt-in per - // environment, enabled only when explicitly turned on. The workflow - // forwards an EMPTY STRING when the variable is unset, so treat - // empty/unset as "use the default (off)" and only the literal "true" - // as the on switch. A `memorySpaces.enabled` cdk.json context can - // also force it on. + // Default ON with a kill switch: Memory Spaces is a complete feature and + // ships enabled for every deployer (opt-out, not opt-in — matches kbSync / + // scheduledRuns). The table + bucket are provisioned unconditionally, so this + // only toggles the runtime MEMORY_SPACES_ENABLED env var. The workflow forwards + // an EMPTY STRING when the variable is unset, so treat empty/unset as the + // default (on) and only the literal "false" as the kill switch. A + // `memorySpaces.enabled: false` cdk.json context can also disable it. enabled: process.env.CDK_MEMORY_SPACES_ENABLED - ? process.env.CDK_MEMORY_SPACES_ENABLED === 'true' - : scope.node.tryGetContext('memorySpaces')?.enabled ?? false, + ? process.env.CDK_MEMORY_SPACES_ENABLED !== 'false' + : scope.node.tryGetContext('memorySpaces')?.enabled ?? true, }, agents: { // Default OFF with an on switch (same pattern as memorySpaces): opt-in per diff --git a/infrastructure/lib/constructs/app-api/app-api-environment.ts b/infrastructure/lib/constructs/app-api/app-api-environment.ts index d17d1b50..b1884c8c 100644 --- a/infrastructure/lib/constructs/app-api/app-api-environment.ts +++ b/infrastructure/lib/constructs/app-api/app-api-environment.ts @@ -283,7 +283,7 @@ export function buildAppApiEnvironment( // (scheduled-runs PR-1). Cohort access is RBAC (`scheduled-runs` // capability); this only gates feature existence per environment. SCHEDULED_RUNS_ENABLED: config.scheduledRuns.enabled ? 'true' : 'false', - // Kill switch for the Memory Spaces feature (default off per env). + // Memory Spaces feature (default ON with a kill switch per env). // The table/bucket names are always wired (the service reads them lazily); // only MEMORY_SPACES_ENABLED gates whether the routes are mounted. Without // these two, app-api falls back to the default "memory-spaces" name and diff --git a/infrastructure/test/config.test.ts b/infrastructure/test/config.test.ts index cd0da833..9522dba6 100644 --- a/infrastructure/test/config.test.ts +++ b/infrastructure/test/config.test.ts @@ -384,6 +384,44 @@ describe('RAG Ingestion Configuration', () => { }); }); + // ============================================================ + // Memory Spaces feature flag — default ON with a kill switch + // (complete feature; ships enabled for forkers, empty var must not disable) + // ============================================================ + + describe('Memory Spaces feature flag', () => { + test('defaults to enabled when CDK_MEMORY_SPACES_ENABLED is unset', () => { + delete process.env.CDK_MEMORY_SPACES_ENABLED; + + expect(loadConfig(app).memorySpaces.enabled).toBe(true); + }); + + test('treats empty string (unset GitHub Actions variable) as enabled', () => { + process.env.CDK_MEMORY_SPACES_ENABLED = ''; + + expect(loadConfig(app).memorySpaces.enabled).toBe(true); + }); + + test('CDK_MEMORY_SPACES_ENABLED="false" is the kill switch', () => { + process.env.CDK_MEMORY_SPACES_ENABLED = 'false'; + + expect(loadConfig(app).memorySpaces.enabled).toBe(false); + }); + + test('CDK_MEMORY_SPACES_ENABLED="true" stays enabled', () => { + process.env.CDK_MEMORY_SPACES_ENABLED = 'true'; + + expect(loadConfig(app).memorySpaces.enabled).toBe(true); + }); + + test('cdk.json context memorySpaces.enabled=false disables when env is unset', () => { + delete process.env.CDK_MEMORY_SPACES_ENABLED; + app.node.setContext('memorySpaces', { enabled: false }); + + expect(loadConfig(app).memorySpaces.enabled).toBe(false); + }); + }); + // ============================================================ // Configuration Validation Tests // ============================================================