export function baselineRowKey({ metricType, context, windowDays }) { return `${metricType}|${context}|${windowDays}`; } export function serializeBaselineRow(base, computedAt = Date.now()) { return { metricType: base.metricType, context: base.context, windowDays: base.windowDays, computedAt, sampleCount: base.sampleCount, mean: base.mean, stddev: base.stddev, p25: base.p25 ?? null, p75: base.p75 ?? null, typicalLow: base.min ?? null, typicalHigh: base.max ?? null, maturity: base.maturity, }; } export function baselineToApiShape(row) { return { metricType: row.metricType, context: row.context, windowDays: row.windowDays, sampleCount: row.sampleCount, maturity: row.maturity, mean: row.mean, stddev: row.stddev, min: row.typicalLow, max: row.typicalHigh, computedAt: row.computedAt, }; } export function mapPgBaselineRow(row, userId) { return { id: Number(row.id), userId: String(userId), metricType: row.metric_type, context: row.context, windowDays: Number(row.window_days), computedAt: row.computed_at ? new Date(row.computed_at).getTime() : Date.now(), sampleCount: Number(row.sample_count ?? 0), mean: row.mean_val != null ? Number(row.mean_val) : null, stddev: row.std_val != null ? Number(row.std_val) : null, p25: row.p25_val != null ? Number(row.p25_val) : null, p75: row.p75_val != null ? Number(row.p75_val) : null, typicalLow: row.typical_low != null ? Number(row.typical_low) : null, typicalHigh: row.typical_high != null ? Number(row.typical_high) : null, maturity: row.maturity, }; } export function mapBaselineToPgPayload(row) { return { metric_type: row.metricType, context: row.context, window_days: row.windowDays, computed_at: new Date(row.computedAt ?? Date.now()).toISOString(), sample_count: row.sampleCount, mean_val: row.mean, std_val: row.stddev, p25_val: row.p25, p75_val: row.p75, typical_low: row.typicalLow, typical_high: row.typicalHigh, maturity: row.maturity, }; }