From f9cb62c672478e812d32fefd4f5caf06d3d84d9f Mon Sep 17 00:00:00 2001 From: chrarnoldus <12196001+chrarnoldus@users.noreply.github.com> Date: Thu, 24 Sep 2026 12:40:48 +0000 Subject: [PATCH] Remove model experiment maintenance Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- .../route.ts | 40 -------- ...odel-experiment-request-partitions.test.ts | 57 ------------ .../model-experiment-request-partitions.ts | 44 --------- apps/web/src/lib/user/index.test.ts | 93 ------------------- apps/web/src/lib/user/index.ts | 2 - apps/web/src/tests/setup/workerSetup.ts | 10 -- apps/web/vercel.json | 4 - 7 files changed, 250 deletions(-) delete mode 100644 apps/web/src/app/api/cron/model-experiment-request-partition-maintenance/route.ts delete mode 100644 apps/web/src/lib/model-experiment-request-partitions.test.ts delete mode 100644 apps/web/src/lib/model-experiment-request-partitions.ts diff --git a/apps/web/src/app/api/cron/model-experiment-request-partition-maintenance/route.ts b/apps/web/src/app/api/cron/model-experiment-request-partition-maintenance/route.ts deleted file mode 100644 index 5099724aab..0000000000 --- a/apps/web/src/app/api/cron/model-experiment-request-partition-maintenance/route.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NextResponse } from 'next/server'; -import { captureException } from '@sentry/nextjs'; -import { db } from '@/lib/drizzle'; -import { CRON_SECRET } from '@/lib/config.server'; -import { provisionModelExperimentRequestPartitions } from '@/lib/model-experiment-request-partitions'; - -if (!CRON_SECRET) { - throw new Error('CRON_SECRET is not configured in environment variables'); -} - -/** - * Provisions the current month and two months ahead so inserts route into a - * bounded monthly partition window. - */ -export async function GET(request: Request) { - const authHeader = request.headers.get('authorization'); - if (authHeader !== `Bearer ${CRON_SECRET}`) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - const { created, errors: partitionErrors } = await provisionModelExperimentRequestPartitions(db); - const errors = partitionErrors.map(({ name, error }) => { - const message = `Failed to create partition ${name}: ${error instanceof Error ? error.message : String(error)}`; - console.error(`[model-experiment-request-partition-maintenance] ${message}`); - captureException(error, { - tags: { source: 'model-experiment-request-partition-maintenance', partition: name }, - }); - return message; - }); - - console.log( - `[model-experiment-request-partition-maintenance] created=[${created.join(', ')}] errors=${errors.length}` - ); - - return NextResponse.json({ - success: errors.length === 0, - created, - errors, - }); -} diff --git a/apps/web/src/lib/model-experiment-request-partitions.test.ts b/apps/web/src/lib/model-experiment-request-partitions.test.ts deleted file mode 100644 index 6dd761e6bd..0000000000 --- a/apps/web/src/lib/model-experiment-request-partitions.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { describe, expect, test } from '@jest/globals'; -import { PgDialect } from 'drizzle-orm/pg-core'; -import type { SQL } from 'drizzle-orm'; -import { provisionModelExperimentRequestPartitions } from '@/lib/model-experiment-request-partitions'; - -describe('model experiment request partitions', () => { - test('provisions current month and two months ahead', async () => { - const statements: string[] = []; - const dialect = new PgDialect(); - const fakeDb = { - execute: async (query: SQL) => { - statements.push(dialect.sqlToQuery(query).sql); - return { rows: [] }; - }, - }; - - const result = await provisionModelExperimentRequestPartitions( - fakeDb as never, - new Date(2026, 7, 15, 12) // August 2026 - ); - - expect(result).toEqual({ - created: [ - 'model_experiment_request_2026_08', - 'model_experiment_request_2026_09', - 'model_experiment_request_2026_10', - ], - errors: [], - }); - expect(statements).toEqual([ - `CREATE TABLE IF NOT EXISTS "model_experiment_request_2026_08" PARTITION OF "model_experiment_request" FOR VALUES FROM ('2026-08-01') TO ('2026-09-01')`, - `CREATE TABLE IF NOT EXISTS "model_experiment_request_2026_09" PARTITION OF "model_experiment_request" FOR VALUES FROM ('2026-09-01') TO ('2026-10-01')`, - `CREATE TABLE IF NOT EXISTS "model_experiment_request_2026_10" PARTITION OF "model_experiment_request" FOR VALUES FROM ('2026-10-01') TO ('2026-11-01')`, - ]); - }); - - test('collects per-partition failures without stopping the window', async () => { - let calls = 0; - const result = await provisionModelExperimentRequestPartitions( - { - execute: async () => { - calls += 1; - if (calls === 2) throw new Error('boom'); - return { rows: [] }; - }, - } as never, - new Date(2026, 7, 1) - ); - - expect(result.created).toEqual([ - 'model_experiment_request_2026_08', - 'model_experiment_request_2026_10', - ]); - expect(result.errors).toHaveLength(1); - expect(result.errors[0]?.name).toBe('model_experiment_request_2026_09'); - }); -}); diff --git a/apps/web/src/lib/model-experiment-request-partitions.ts b/apps/web/src/lib/model-experiment-request-partitions.ts deleted file mode 100644 index 8749f38b7b..0000000000 --- a/apps/web/src/lib/model-experiment-request-partitions.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { db as defaultDb } from '@/lib/drizzle'; -import { sql } from 'drizzle-orm'; -import { format } from 'date-fns'; - -type ModelExperimentRequestPartitionDb = Pick; - -export type ModelExperimentRequestPartitionProvisioningResult = { - created: string[]; - errors: Array<{ name: string; error: unknown }>; -}; - -/** - * Creates the current month and next two monthly request-audit partitions. - * - * Production keeps this window current via cron. Fresh migrate snapshots (CI, - * Jest workers) only have the seed months from the partitioning migration, so - * tests must call this before inserting rows whose created_at defaults to now(). - */ -export async function provisionModelExperimentRequestPartitions( - fromDb: ModelExperimentRequestPartitionDb, - now: Date = new Date() -): Promise { - const created: string[] = []; - const errors: Array<{ name: string; error: unknown }> = []; - - for (let offset = 0; offset <= 2; offset++) { - const target = new Date(now.getFullYear(), now.getMonth() + offset, 1); - const nextMonth = new Date(target.getFullYear(), target.getMonth() + 1, 1); - const name = `model_experiment_request_${format(target, 'yyyy_MM')}`; - - try { - await fromDb.execute( - sql.raw( - `CREATE TABLE IF NOT EXISTS "${name}" PARTITION OF "model_experiment_request" FOR VALUES FROM ('${format(target, 'yyyy-MM-dd')}') TO ('${format(nextMonth, 'yyyy-MM-dd')}')` - ) - ); - created.push(name); - } catch (error) { - errors.push({ name, error }); - } - } - - return { created, errors }; -} diff --git a/apps/web/src/lib/user/index.test.ts b/apps/web/src/lib/user/index.test.ts index ab9a009609..b29b8032d8 100644 --- a/apps/web/src/lib/user/index.test.ts +++ b/apps/web/src/lib/user/index.test.ts @@ -100,10 +100,6 @@ import { microdollar_usage, microdollar_usage_metadata, system_prompt_prefix, - model_experiment, - model_experiment_variant, - model_experiment_variant_version, - model_experiment_request, stripe_dispute_actions, stripe_dispute_cases, stripe_early_fraud_warning_cases, @@ -278,10 +274,6 @@ describe('User', () => { await db.delete(organization_user_limits); await db.delete(organization_memberships); await db.delete(free_model_usage); - await db.delete(model_experiment_request); - await db.delete(model_experiment_variant_version); - await db.delete(model_experiment_variant); - await db.delete(model_experiment); await db.delete(microdollar_usage_metadata); await db.delete(microdollar_usage); await db.delete(user_feedback); @@ -5424,91 +5416,6 @@ describe('User', () => { expect(softDeletedCreator?.can_manage_credits).toBe(false); }); - it('should preserve model experiment attribution and prompt hashes', async () => { - const user = await insertTestUser(); - const usageId = randomUUID(); - const createdAt = '2026-05-25T12:00:00.000Z'; - const requestBodySha256 = 'a'.repeat(64); - - await db.insert(microdollar_usage).values({ - id: usageId, - kilo_user_id: user.id, - cost: 0, - input_tokens: 100, - output_tokens: 50, - cache_write_tokens: 0, - cache_hit_tokens: 0, - created_at: createdAt, - provider: 'custom', - model: 'partner/checkpoint-rc1', - requested_model: 'kilo/preview-experiment-test', - has_error: false, - }); - - const [experiment] = await db - .insert(model_experiment) - .values({ - public_model_id: 'kilo/preview-experiment-test', - name: 'Soft-delete retention test', - status: 'active', - created_by_user_id: user.id, - }) - .returning({ id: model_experiment.id }); - if (!experiment) throw new Error('Failed to insert model experiment'); - - const [variant] = await db - .insert(model_experiment_variant) - .values({ - experiment_id: experiment.id, - label: 'A', - weight: 1, - }) - .returning({ id: model_experiment_variant.id }); - if (!variant) throw new Error('Failed to insert model experiment variant'); - - const [variantVersion] = await db - .insert(model_experiment_variant_version) - .values({ - variant_id: variant.id, - upstream: { - internal_id: 'partner/checkpoint-rc1', - base_url: 'https://partner.example.com/v1', - }, - encrypted_api_key: { iv: 'iv', data: 'data', authTag: 'authTag' }, - created_by: user.id, - }) - .returning({ id: model_experiment_variant_version.id }); - if (!variantVersion) throw new Error('Failed to insert model experiment variant version'); - - await db.insert(model_experiment_request).values({ - usage_id: usageId, - variant_version_id: variantVersion.id, - allocation_subject: 'user', - client_request_id: 'client-message-id', - request_kind: 'chat_completions', - request_body_sha256: requestBodySha256, - was_truncated: false, - created_at: createdAt, - }); - - await softDeleteUser(user.id); - - const [usage] = await db - .select() - .from(microdollar_usage) - .where(eq(microdollar_usage.id, usageId)); - expect(usage?.kilo_user_id).toBe(user.id); - - const [attribution] = await db - .select() - .from(model_experiment_request) - .where(eq(model_experiment_request.usage_id, usageId)); - if (!attribution) throw new Error('Expected model experiment attribution to be retained'); - expect(attribution.request_body_sha256).toBe(requestBodySha256); - expect(attribution.client_request_id).toBe('client-message-id'); - expect(new Date(attribution.created_at).toISOString()).toBe(createdAt); - }); - it('should preserve Kilo Pass subscriptions and issuance chain', async () => { const user = await insertTestUser(); diff --git a/apps/web/src/lib/user/index.ts b/apps/web/src/lib/user/index.ts index 8fc666e9d8..ad88aa50b4 100644 --- a/apps/web/src/lib/user/index.ts +++ b/apps/web/src/lib/user/index.ts @@ -1033,8 +1033,6 @@ export async function assertUserCanBeSoftDeleted(userId: string): Promise * - stytch_fingerprints and provider safety identifiers (abuse detection) * - referral_code_usages (financial, references anonymized user) * - kiloclaw_subscriptions, kiloclaw_earlybird_purchases, kiloclaw_email_log (retained records) - * - model_experiment_request (experiment attribution and prompt hashes retained - * under the dedicated experiment retention policy) * - kiloclaw_scheduled_action_targets (retained operational records; * - transactional_email_log (retained outbox marker, financial record; * user_id FK references the anonymized kilocode_users row and optional diff --git a/apps/web/src/tests/setup/workerSetup.ts b/apps/web/src/tests/setup/workerSetup.ts index 338ca5f797..27a7ac9a6a 100644 --- a/apps/web/src/tests/setup/workerSetup.ts +++ b/apps/web/src/tests/setup/workerSetup.ts @@ -10,7 +10,6 @@ import { provisionComputeUsageChargePartitions, provisionExaUsageLogPartitions, } from '@/lib/usage-partitions'; -import { provisionModelExperimentRequestPartitions } from '@/lib/model-experiment-request-partitions'; import { existsSync, writeFileSync, mkdirSync } from 'fs'; import { join } from 'path'; import { shutdownPosthog } from '@/lib/posthog'; @@ -75,15 +74,6 @@ beforeAll(async () => { `Failed to create compute usage charge partition ${name}: ${error instanceof Error ? error.message : String(error)}` ); } - - const { errors: modelExperimentPartitionErrors } = - await provisionModelExperimentRequestPartitions(testDb); - if (modelExperimentPartitionErrors.length > 0) { - const [{ name, error }] = modelExperimentPartitionErrors; - throw new Error( - `Failed to create model experiment request partition ${name}: ${error instanceof Error ? error.message : String(error)}` - ); - } } finally { await testPool.end(); } diff --git a/apps/web/vercel.json b/apps/web/vercel.json index 35d79a7c4b..1cb8e7cbed 100644 --- a/apps/web/vercel.json +++ b/apps/web/vercel.json @@ -124,10 +124,6 @@ "path": "/api/cron/usage-partition-maintenance", "schedule": "0 0 1 * *" }, - { - "path": "/api/cron/model-experiment-request-partition-maintenance", - "schedule": "0 0 1 * *" - }, { "path": "/api/cron/cleanup-free-model-usage", "schedule": "0 * * * *"