/** * Unconfigured-modules check. * * Modules that are imported (or further along the lifecycle) but * have *zero* config rows in the DB — i.e. the user has never run * the configuration interview. Even if all of the module's required * config has defaults, never having gone through the interview is a * useful signal: it means the user hasn't reviewed what's there. * * Reported per-module rather than rolled into `module_configs` * findings so the user sees "X has never been configured" as a * single category, not as N individual missing-required findings. * * `INSTALLED` and `VERIFIED` modules are skipped — they were * configured at deploy time, even if rows have since been deleted. * This check is for *new* imports that haven't been touched yet. */ import type { DriftFinding } from './types'; export interface UnconfiguredModule { id: string; /** Lifecycle state from the modules table (IMPORTED, VALIDATED, …). */ state: string; /** Total number of config rows recorded for this module. */ configCount: number; } export interface UnconfiguredModulesAuditDeps { modules: UnconfiguredModule[]; } const ALREADY_DEPLOYED = new Set(['INSTALLED', 'VERIFIED']); export async function auditUnconfiguredModules( deps: UnconfiguredModulesAuditDeps, ): Promise { const findings: DriftFinding[] = []; for (const m of deps.modules) { if (ALREADY_DEPLOYED.has(m.state)) continue; if (m.configCount > 0) continue; // todo: same reasoning as undeployed_modules — never running the // configuration interview is a next-step reminder, not divergence // from a desired state. Won't escalate the audit verdict beyond // READY. findings.push({ category: 'unconfigured_modules', severity: 'todo', code: 'module_unconfigured', message: `${m.id}: never configured (no config rows in DB)`, details: [ 'Module was imported but the configuration interview has not', 'been run. Defaults will apply for any unset values when you', 'deploy, but reviewing what knobs exist first is recommended.', '', 'To review:', ` celilo module config get ${m.id}`, '', 'To set values manually:', ` celilo module config set ${m.id} `, '', 'Or just run `module deploy` — it triggers the interview', 'automatically if required values are missing.', ].join('\n'), // Not a one-shot — there's no single celilo command to "configure" // a module. Surfacing the modal would mislead. actionable: false, subject: m.id, }); } return findings; }