import { randomUUID, createHash } from "node:crypto"; import type BetterSqlite3 from "better-sqlite3"; import { serializeAuditSummary, auditRetentionMilliseconds } from "./audit-policy.js"; export const modelIds = [ "gemini-3.1-flash-image-preview", "gemini-3-pro-image-preview", "gpt-image-2", ] as const; export type ModelId = typeof modelIds[number]; export type ContractValidationStatus = "blocked" | "unverified" | "verified"; export type ModelRuntimeReason = | "available" | "configured_disabled" | "contract_unverified" | "contract_blocked" | "gateway_balance_insufficient" | "gateway_paused" | "worker_degraded"; export interface ModelConfigCandidate { model_id: string; display_name: string; enabled: boolean; is_default: boolean; recommendation_priority: number; route_profile: Record; gateway_account_ref: string; error_mapping_profile: Record; credit_cost: number; supported_ratios: string[]; reference_limits: { max_file_bytes: number; max_files: number; max_total_bytes: number }; prompt_max_length: number; safety_source: string; contract_validation_status?: ContractValidationStatus; contract_evidence_ref?: string | null; config_version?: number; } export interface ModelRuntimeAvailability { available_for_new_jobs: boolean; reason: ModelRuntimeReason; checked_at: string; } export interface ModelConfigView extends ModelConfigCandidate { config_version: number; contract_validation_status: ContractValidationStatus; contract_evidence_ref: string | null; runtime_availability: ModelRuntimeAvailability; } export interface ModelConfigurationView { config_set_version: number; configured_default_model_id: ModelId; recommended_model_id: ModelId | null; models: ModelConfigView[]; } export class ModelConfigurationError extends Error { constructor( readonly code: | "MODEL_CONFIG_VERSION_CONFLICT" | "MODEL_DEFAULT_REPLACEMENT_REQUIRED" | "MODEL_DEFAULT_REPLACEMENT_INVALID" | "MODEL_RECOMMENDATION_PRIORITY_INVALID" | "MODEL_RECOMMENDATION_PRIORITY_CONFLICT" | "IDEMPOTENCY_KEY_CONFLICT", readonly details: Record = {}, ) { super(code); this.name = "ModelConfigurationError"; } } interface StoredVersion { config_version: number; contract_evidence_ref: string | null; contract_validation_status: ContractValidationStatus; credit_cost: number; display_name: string; error_mapping_profile_json: string; gateway_account_ref: string; model_id: ModelId; prompt_max_length: number; reference_limits_json: string; route_profile_json: string; safety_source: string; supported_ratios_json: string; } interface StoredMember { config_set_id: string; config_version: number; enabled: 0 | 1; is_default: 0 | 1; model_id: ModelId; recommendation_priority: number; } const defaultErrorMapping: Record = { gateway_contract_invalid: "gateway_contract_invalid", gateway_balance_insufficient: "gateway_balance_insufficient", reference_invalid: "reference_invalid", safety_rejected: "safety_rejected", unknown_non_retryable: "unknown_non_retryable", unknown_retryable: "unknown_retryable", upstream_failed: "upstream_failed", upstream_timeout: "upstream_timeout", }; const seedCandidates: ModelConfigCandidate[] = [ { model_id: modelIds[0], display_name: "Gemini 3.1 Flash Image Preview", enabled: true, is_default: true, recommendation_priority: 1, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" }, gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1, supported_ratios: ["3:4", "1:1", "4:3", "9:16"], reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 }, prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null, }, { model_id: modelIds[1], display_name: "Gemini 3 Pro Image Preview", enabled: true, is_default: false, recommendation_priority: 2, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" }, gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1, supported_ratios: ["3:4", "1:1", "4:3", "9:16"], reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 }, prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null, }, { model_id: modelIds[2], display_name: "GPT Image 2", enabled: true, is_default: false, recommendation_priority: 3, route_profile: { endpoint: "https://mock.invalid/v1/images", mode: "sync" }, gateway_account_ref: "mock-gateway", error_mapping_profile: defaultErrorMapping, credit_cost: 1, supported_ratios: ["3:4", "1:1", "4:3", "9:16"], reference_limits: { max_file_bytes: 10_485_760, max_files: 2, max_total_bytes: 20_971_520 }, prompt_max_length: 1_000, safety_source: "provider", contract_validation_status: "unverified", contract_evidence_ref: null, }, ]; function stableJson(value: unknown): string { if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; if (value && typeof value === "object") { return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)) .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`; } return JSON.stringify(value); } function fingerprint(candidate: ModelConfigCandidate) { return createHash("sha256").update(stableJson({ error_mapping_profile: candidate.error_mapping_profile, gateway_account_ref: candidate.gateway_account_ref, prompt_max_length: candidate.prompt_max_length, reference_limits: candidate.reference_limits, route_profile: candidate.route_profile, safety_source: candidate.safety_source, supported_ratios: candidate.supported_ratios, })).digest("hex"); } function profileRef(prefix: "error" | "route", value: Record) { return `${prefix}:${createHash("sha256").update(stableJson(value)).digest("hex")}`; } function isPlainRecord(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); } export function validateModelConfigurationCandidateSet(input: ModelConfigCandidate[]) { if (input.length !== modelIds.length || new Set(input.map((item) => item.model_id)).size !== modelIds.length || input.some((item) => !modelIds.includes(item.model_id as ModelId))) { throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "fixed_model_set" }); } for (const item of input) { if (!Number.isSafeInteger(item.recommendation_priority) || item.recommendation_priority <= 0) { throw new ModelConfigurationError("MODEL_RECOMMENDATION_PRIORITY_INVALID", { field_errors: [{ field: `models.${item.model_id}.recommendation_priority`, message_key: "model.priority.invalid" }], }); } } const byPriority = new Map(); for (const item of input) byPriority.set(item.recommendation_priority, [...(byPriority.get(item.recommendation_priority) ?? []), item]); const duplicate = [...byPriority.values()].find((items) => items.length > 1); if (duplicate) { throw new ModelConfigurationError("MODEL_RECOMMENDATION_PRIORITY_CONFLICT", { conflict_model_ids: duplicate.map((item) => item.model_id), }); } if (input.some((item) => !isPlainRecord(item.route_profile) || !isPlainRecord(item.error_mapping_profile))) { throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "contract_fields_invalid" }); } } function runtimeFor(candidate: ModelConfigCandidate, previous: ModelRuntimeAvailability | undefined, contractChanged: boolean, now: number): ModelRuntimeAvailability { if (!candidate.enabled) return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "configured_disabled" }; if (candidate.contract_validation_status === "blocked" && !contractChanged) { return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_blocked" }; } if (candidate.contract_validation_status !== "verified" || contractChanged) { return { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_unverified" }; } return previous ?? { available_for_new_jobs: false, checked_at: new Date(now).toISOString(), reason: "contract_unverified" }; } export interface ModelConfigurationServiceOptions { clock?: () => number; database: BetterSqlite3.Database; onChanged?: (configSetVersion: number) => void; } export class ModelConfigurationService { readonly database: BetterSqlite3.Database; readonly #clock: () => number; readonly #onChanged: ((configSetVersion: number) => void) | undefined; constructor(options: ModelConfigurationServiceOptions) { this.database = options.database; this.#clock = options.clock ?? Date.now; this.#onChanged = options.onChanged; this.ensureSchema(); } read(): ModelConfigurationView { const current = this.database.prepare(` SELECT c.config_set_id, c.config_set_version FROM model_config_current mc JOIN model_config_sets c ON c.config_set_id = mc.config_set_id WHERE mc.singleton = 1 `).get() as { config_set_id: string; config_set_version: number } | undefined; if (!current) throw new Error("model_config_current_missing"); const rows = this.database.prepare(` SELECT m.model_id, m.enabled, m.is_default, m.recommendation_priority, v.*, r.available_for_new_jobs, r.reason, r.checked_at FROM model_config_set_members m JOIN model_config_versions v ON v.model_id = m.model_id AND v.config_version = m.config_version JOIN model_runtime_availability r ON r.model_id = m.model_id WHERE m.config_set_id = ? ORDER BY m.recommendation_priority `).all(current.config_set_id) as Array; const models = rows.map((row) => ({ model_id: row.model_id, display_name: row.display_name, config_version: row.config_version, enabled: row.enabled === 1, is_default: row.is_default === 1, recommendation_priority: row.recommendation_priority, route_profile: JSON.parse(row.route_profile_json) as Record, gateway_account_ref: row.gateway_account_ref, error_mapping_profile: JSON.parse(row.error_mapping_profile_json) as Record, credit_cost: row.credit_cost, supported_ratios: JSON.parse(row.supported_ratios_json) as string[], reference_limits: JSON.parse(row.reference_limits_json) as ModelConfigCandidate["reference_limits"], prompt_max_length: row.prompt_max_length, safety_source: row.safety_source, contract_validation_status: row.contract_validation_status, contract_evidence_ref: row.contract_evidence_ref, runtime_availability: { available_for_new_jobs: row.available_for_new_jobs === 1, checked_at: new Date(row.checked_at).toISOString(), reason: row.reason, }, } satisfies ModelConfigView)); const recommended = models.find((model) => model.enabled && model.contract_validation_status === "verified" && model.runtime_availability.available_for_new_jobs); return { config_set_version: current.config_set_version, configured_default_model_id: models.find((model) => model.enabled && model.is_default)!.model_id as ModelId, recommended_model_id: recommended?.model_id ?? null, models, }; } readModel(modelId: string) { return this.read().models.find((model) => model.model_id === modelId); } replace(input: { actorId: string; expectedConfigSetVersion: number; idempotencyKey: string; models: ModelConfigCandidate[] }) { const requestHash = createHash("sha256").update(JSON.stringify({ expected: input.expectedConfigSetVersion, models: input.models })).digest("hex"); const now = this.#clock(); const result = this.database.transaction(() => { const existing = this.database.prepare("SELECT request_hash, response_json FROM model_config_idempotency WHERE idempotency_key = ?") .get(input.idempotencyKey) as { request_hash: string; response_json: string } | undefined; if (existing) { if (existing.request_hash !== requestHash) throw new ModelConfigurationError("IDEMPOTENCY_KEY_CONFLICT"); return { replayed: true, value: JSON.parse(existing.response_json) as ModelConfigurationView }; } validateModelConfigurationCandidateSet(input.models); const current = this.database.prepare(` SELECT c.config_set_id, c.config_set_version FROM model_config_current mc JOIN model_config_sets c ON c.config_set_id = mc.config_set_id WHERE mc.singleton = 1 `).get() as { config_set_id: string; config_set_version: number }; if (input.expectedConfigSetVersion !== current.config_set_version) { throw new ModelConfigurationError("MODEL_CONFIG_VERSION_CONFLICT", { latest_version: current.config_set_version }); } const previous = this.read(); const oldDefault = previous.models.find((model) => model.is_default && model.enabled); const declaredDefaults = input.models.filter((model) => model.is_default); const nextDefaults = declaredDefaults.filter((model) => model.enabled); const nextDefault = nextDefaults[0]; if (oldDefault && !input.models.find((model) => model.model_id === oldDefault.model_id)?.enabled) { if (declaredDefaults.length === 0) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_REQUIRED"); if (!nextDefault) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID"); if (nextDefault.model_id === oldDefault.model_id) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID"); } if (nextDefaults.length !== 1) throw new ModelConfigurationError("MODEL_DEFAULT_REPLACEMENT_INVALID", { reason: "enabled_default_count" }); const setId = randomUUID(); const nextSetVersion = current.config_set_version + 1; this.database.prepare("INSERT INTO model_config_sets (config_set_id, config_set_version, created_at, created_by) VALUES (?, ?, ?, ?)") .run(setId, nextSetVersion, now, input.actorId); const insertVersion = this.database.prepare(` INSERT INTO model_config_versions ( model_id, config_version, display_name, enabled, is_default, recommendation_priority, route_profile_id, route_profile_json, gateway_account_ref, error_mapping_profile_id, error_mapping_profile_json, credit_cost, supported_ratios_json, reference_limits_json, prompt_max_length, safety_source, contract_validation_status, contract_evidence_ref, contract_fingerprint, created_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const insertMember = this.database.prepare(` INSERT INTO model_config_set_members (config_set_id, model_id, config_version, enabled, is_default, recommendation_priority) VALUES (?, ?, ?, ?, ?, ?) `); for (const candidate of input.models) { const old = previous.models.find((model) => model.model_id === candidate.model_id); const changed = !old || fingerprint(candidate) !== fingerprint(old) || candidate.display_name !== old.display_name || candidate.credit_cost !== old.credit_cost || candidate.enabled !== old.enabled || candidate.is_default !== old.is_default || candidate.recommendation_priority !== old.recommendation_priority || (candidate.contract_validation_status !== undefined && candidate.contract_validation_status !== old.contract_validation_status); const contractChanged = Boolean(old && fingerprint(candidate) !== fingerprint(old)); const configVersion = changed ? (old?.config_version ?? 0) + 1 : old!.config_version; const status: ContractValidationStatus = contractChanged ? "unverified" : candidate.contract_validation_status ?? old?.contract_validation_status ?? "unverified"; const evidence = status === "unverified" ? null : candidate.contract_evidence_ref ?? old?.contract_evidence_ref ?? null; if (changed) { const routeProfileId = profileRef("route", candidate.route_profile); const errorMappingProfileId = profileRef("error", candidate.error_mapping_profile); this.database.prepare("INSERT OR IGNORE INTO gateway_route_profiles (route_profile_id, profile_json, created_at) VALUES (?, ?, ?)") .run(routeProfileId, stableJson(candidate.route_profile), now); this.database.prepare("INSERT OR IGNORE INTO error_mapping_profiles (error_mapping_profile_id, profile_json, created_at) VALUES (?, ?, ?)") .run(errorMappingProfileId, stableJson(candidate.error_mapping_profile), now); insertVersion.run( candidate.model_id, configVersion, candidate.display_name, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority, routeProfileId, stableJson(candidate.route_profile), candidate.gateway_account_ref, errorMappingProfileId, stableJson(candidate.error_mapping_profile), candidate.credit_cost, stableJson(candidate.supported_ratios), stableJson(candidate.reference_limits), candidate.prompt_max_length, candidate.safety_source, status, evidence, fingerprint(candidate), now, ); } insertMember.run(setId, candidate.model_id, configVersion, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority); const runtime = runtimeFor({ ...candidate, contract_validation_status: status }, old?.runtime_availability, contractChanged, now); this.database.prepare(` INSERT INTO model_runtime_availability (model_id, available_for_new_jobs, reason, checked_at, runtime_availability_version) VALUES (?, ?, ?, ?, (SELECT COALESCE(MAX(runtime_availability_version), 0) + 1 FROM model_runtime_availability)) ON CONFLICT(model_id) DO UPDATE SET available_for_new_jobs=excluded.available_for_new_jobs, reason=excluded.reason, checked_at=excluded.checked_at, runtime_availability_version=excluded.runtime_availability_version `).run(candidate.model_id, runtime.available_for_new_jobs ? 1 : 0, runtime.reason, now); } this.database.prepare("UPDATE model_config_current SET config_set_id = ? WHERE singleton = 1").run(setId); const after = this.read(); const occurredAt = now; this.database.prepare(` INSERT INTO admin_operation_logs ( log_id, actor_type, actor_ref, operation_type, target_type, target_ref, result, before_summary, after_summary, occurred_at, expires_at ) VALUES (?, 'super_admin', ?, 'model_configuration_replace', 'model_config_set', ?, 'succeeded', ?, ?, ?, ?) `).run( randomUUID(), input.actorId, setId, serializeAuditSummary({ config_set_version: current.config_set_version }), serializeAuditSummary({ config_set_version: nextSetVersion, model_count: after.models.length }), occurredAt, occurredAt + auditRetentionMilliseconds, ); this.database.prepare(` INSERT INTO outbox_events (event_id, operation_key, topic, aggregate_type, aggregate_id, payload_json, status, created_at, published_at) VALUES (?, ?, 'model_config_changed', 'model_config_set', ?, ?, 'pending', ?, NULL) `).run(randomUUID(), `model-config:${input.idempotencyKey}`, setId, JSON.stringify({ config_set_version: nextSetVersion }), now); this.database.prepare("INSERT INTO model_config_idempotency (idempotency_key, request_hash, response_json, created_at) VALUES (?, ?, ?, ?)") .run(input.idempotencyKey, requestHash, JSON.stringify(after), now); return { replayed: false, value: after }; }).immediate(); if (!result.replayed) this.#onChanged?.(result.value.config_set_version); return result.value; } private ensureSchema() { this.database.exec(` CREATE TABLE IF NOT EXISTS gateway_route_profiles ( route_profile_id TEXT PRIMARY KEY, profile_json TEXT NOT NULL CHECK (json_valid(profile_json)), created_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS error_mapping_profiles ( error_mapping_profile_id TEXT PRIMARY KEY, profile_json TEXT NOT NULL CHECK (json_valid(profile_json)), created_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS model_config_sets ( config_set_id TEXT PRIMARY KEY, config_set_version INTEGER NOT NULL UNIQUE CHECK (config_set_version > 0), created_at INTEGER NOT NULL, created_by TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS model_config_versions ( model_id TEXT NOT NULL CHECK (model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')), config_version INTEGER NOT NULL CHECK (config_version > 0), display_name TEXT NOT NULL, enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)), is_default INTEGER NOT NULL CHECK (is_default IN (0, 1)), recommendation_priority INTEGER NOT NULL CHECK (recommendation_priority > 0), route_profile_id TEXT NOT NULL REFERENCES gateway_route_profiles(route_profile_id), route_profile_json TEXT NOT NULL CHECK (json_valid(route_profile_json)), gateway_account_ref TEXT NOT NULL, error_mapping_profile_id TEXT NOT NULL REFERENCES error_mapping_profiles(error_mapping_profile_id), error_mapping_profile_json TEXT NOT NULL CHECK (json_valid(error_mapping_profile_json)), credit_cost INTEGER NOT NULL CHECK (credit_cost > 0), supported_ratios_json TEXT NOT NULL CHECK (json_valid(supported_ratios_json)), reference_limits_json TEXT NOT NULL CHECK (json_valid(reference_limits_json)), prompt_max_length INTEGER NOT NULL CHECK (prompt_max_length > 0), safety_source TEXT NOT NULL, contract_validation_status TEXT NOT NULL CHECK (contract_validation_status IN ('blocked', 'unverified', 'verified')), contract_evidence_ref TEXT, contract_fingerprint TEXT NOT NULL, created_at INTEGER NOT NULL, PRIMARY KEY (model_id, config_version) ); CREATE TABLE IF NOT EXISTS model_config_set_members ( config_set_id TEXT NOT NULL REFERENCES model_config_sets(config_set_id), model_id TEXT NOT NULL CHECK (model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')), config_version INTEGER NOT NULL, enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)), is_default INTEGER NOT NULL CHECK (is_default IN (0, 1)), recommendation_priority INTEGER NOT NULL CHECK (recommendation_priority > 0), PRIMARY KEY (config_set_id, model_id), FOREIGN KEY (model_id, config_version) REFERENCES model_config_versions(model_id, config_version) ); CREATE UNIQUE INDEX IF NOT EXISTS model_config_set_priority_unique ON model_config_set_members(config_set_id, recommendation_priority); CREATE UNIQUE INDEX IF NOT EXISTS model_config_set_enabled_default_unique ON model_config_set_members(config_set_id) WHERE enabled = 1 AND is_default = 1; CREATE TABLE IF NOT EXISTS model_config_current ( singleton INTEGER PRIMARY KEY CHECK (singleton = 1), config_set_id TEXT NOT NULL REFERENCES model_config_sets(config_set_id) ); CREATE TABLE IF NOT EXISTS model_runtime_availability ( model_id TEXT PRIMARY KEY, available_for_new_jobs INTEGER NOT NULL CHECK (available_for_new_jobs IN (0, 1)), reason TEXT NOT NULL CHECK (reason IN ('available', 'configured_disabled', 'contract_unverified', 'contract_blocked', 'gateway_balance_insufficient', 'gateway_paused', 'worker_degraded')), checked_at INTEGER NOT NULL, runtime_availability_version INTEGER NOT NULL CHECK (runtime_availability_version >= 0) ); CREATE TABLE IF NOT EXISTS model_config_idempotency ( idempotency_key TEXT PRIMARY KEY, request_hash TEXT NOT NULL, response_json TEXT NOT NULL CHECK (json_valid(response_json)), created_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS outbox_events ( event_id TEXT PRIMARY KEY, operation_key TEXT NOT NULL UNIQUE, topic TEXT NOT NULL, aggregate_type TEXT NOT NULL, aggregate_id TEXT NOT NULL, payload_json TEXT NOT NULL CHECK (json_valid(payload_json)), status TEXT NOT NULL, created_at INTEGER NOT NULL, published_at INTEGER ); `); this.database.exec(` DROP TRIGGER IF EXISTS model_config_current_default_guard_insert; DROP TRIGGER IF EXISTS model_config_current_default_guard_update; CREATE TRIGGER model_config_current_default_guard_insert BEFORE INSERT ON model_config_current WHEN (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND enabled = 1 AND is_default = 1) <> 1 OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id) <> 3 OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')) <> 3 BEGIN SELECT RAISE(ABORT, 'model_config_default_invariant'); END; CREATE TRIGGER model_config_current_default_guard_update BEFORE UPDATE OF config_set_id ON model_config_current WHEN (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND enabled = 1 AND is_default = 1) <> 1 OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id) <> 3 OR (SELECT COUNT(*) FROM model_config_set_members WHERE config_set_id = NEW.config_set_id AND model_id IN ('gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview', 'gpt-image-2')) <> 3 BEGIN SELECT RAISE(ABORT, 'model_config_default_invariant'); END; CREATE TRIGGER IF NOT EXISTS model_config_sets_no_update BEFORE UPDATE ON model_config_sets BEGIN SELECT RAISE(ABORT, 'model_config_sets_immutable'); END; CREATE TRIGGER IF NOT EXISTS model_config_sets_no_delete BEFORE DELETE ON model_config_sets BEGIN SELECT RAISE(ABORT, 'model_config_sets_immutable'); END; CREATE TRIGGER IF NOT EXISTS model_config_versions_no_update BEFORE UPDATE ON model_config_versions BEGIN SELECT RAISE(ABORT, 'model_config_versions_immutable'); END; CREATE TRIGGER IF NOT EXISTS model_config_versions_no_delete BEFORE DELETE ON model_config_versions BEGIN SELECT RAISE(ABORT, 'model_config_versions_immutable'); END; CREATE TRIGGER IF NOT EXISTS model_config_members_no_update BEFORE UPDATE ON model_config_set_members BEGIN SELECT RAISE(ABORT, 'model_config_members_immutable'); END; CREATE TRIGGER IF NOT EXISTS model_config_members_no_delete BEFORE DELETE ON model_config_set_members BEGIN SELECT RAISE(ABORT, 'model_config_members_immutable'); END; CREATE TRIGGER IF NOT EXISTS gateway_route_profiles_no_update BEFORE UPDATE ON gateway_route_profiles BEGIN SELECT RAISE(ABORT, 'gateway_route_profiles_immutable'); END; CREATE TRIGGER IF NOT EXISTS gateway_route_profiles_no_delete BEFORE DELETE ON gateway_route_profiles BEGIN SELECT RAISE(ABORT, 'gateway_route_profiles_immutable'); END; CREATE TRIGGER IF NOT EXISTS error_mapping_profiles_no_update BEFORE UPDATE ON error_mapping_profiles BEGIN SELECT RAISE(ABORT, 'error_mapping_profiles_immutable'); END; CREATE TRIGGER IF NOT EXISTS error_mapping_profiles_no_delete BEFORE DELETE ON error_mapping_profiles BEGIN SELECT RAISE(ABORT, 'error_mapping_profiles_immutable'); END; `); const current = this.database.prepare("SELECT config_set_id FROM model_config_current WHERE singleton = 1").get() as { config_set_id: string } | undefined; if (current) return; const seed = this.database.transaction(() => { validateModelConfigurationCandidateSet(seedCandidates); const now = this.#clock(); const setId = randomUUID(); this.database.prepare("INSERT INTO model_config_sets (config_set_id, config_set_version, created_at, created_by) VALUES (?, 1, ?, 'system_seed')") .run(setId, now); const insertVersion = this.database.prepare(` INSERT INTO model_config_versions ( model_id, config_version, display_name, enabled, is_default, recommendation_priority, route_profile_id, route_profile_json, gateway_account_ref, error_mapping_profile_id, error_mapping_profile_json, credit_cost, supported_ratios_json, reference_limits_json, prompt_max_length, safety_source, contract_validation_status, contract_evidence_ref, contract_fingerprint, created_at ) VALUES (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const insertMember = this.database.prepare(` INSERT INTO model_config_set_members (config_set_id, model_id, config_version, enabled, is_default, recommendation_priority) VALUES (?, ?, 1, ?, ?, ?) `); for (const candidate of seedCandidates) { const routeProfileId = profileRef("route", candidate.route_profile); const errorMappingProfileId = profileRef("error", candidate.error_mapping_profile); this.database.prepare("INSERT OR IGNORE INTO gateway_route_profiles (route_profile_id, profile_json, created_at) VALUES (?, ?, ?)") .run(routeProfileId, stableJson(candidate.route_profile), now); this.database.prepare("INSERT OR IGNORE INTO error_mapping_profiles (error_mapping_profile_id, profile_json, created_at) VALUES (?, ?, ?)") .run(errorMappingProfileId, stableJson(candidate.error_mapping_profile), now); insertVersion.run(candidate.model_id, candidate.display_name, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority, routeProfileId, stableJson(candidate.route_profile), candidate.gateway_account_ref, errorMappingProfileId, stableJson(candidate.error_mapping_profile), candidate.credit_cost, stableJson(candidate.supported_ratios), stableJson(candidate.reference_limits), candidate.prompt_max_length, candidate.safety_source, "unverified", null, fingerprint(candidate), now); insertMember.run(setId, candidate.model_id, candidate.enabled ? 1 : 0, candidate.is_default ? 1 : 0, candidate.recommendation_priority); this.database.prepare(` INSERT INTO model_runtime_availability (model_id, available_for_new_jobs, reason, checked_at, runtime_availability_version) VALUES (?, 0, 'contract_unverified', ?, 0) `).run(candidate.model_id, now); } this.database.prepare("INSERT INTO model_config_current (singleton, config_set_id) VALUES (1, ?)").run(setId); }); seed.immediate(); } }