import { VOICE_POOL } from '@wellformed/shared'; import { config } from '../config.js'; import { openControlDatabase } from '../control/db.js'; import { fitVoice, type VoiceFit } from './fit.js'; import { trustFrom } from './select.js'; import { OBSERVATION_WINDOW_DAYS, pendingCount } from './store.js'; /** * `npm run voice` — what the landing page has learned, if anything. * * A command rather than a screen, on purpose. This is read a handful of times a * year by one person, and a dashboard would be a permanent surface, a new auth * question and a thing to keep working, bought for that. * * Two windows side by side. `all` is every mature impression under the usual * bleed; `recent` refits over only the last N. They should broadly agree. When * they stop agreeing, the most likely explanation is not that a point got better * — it is that the traffic changed and the two windows are now describing two * different audiences. That is the failure this table exists to make visible, * because the bleed is far too slow to absorb it on its own and nothing else * about the page would show it to you. */ const RECENT_WINDOW = 150; function main(): void { const control = openControlDatabase(config.controlDbPath); const all = fitVoice(control); const recent = fitVoice(control, { limit: RECENT_WINDOW }); const pending = pendingCount(control); const sharpness = Math.round((trustFrom(all.weight) / 6) * 100); console.log(''); console.log(` ${all.observations} mature impressions, ${all.converted} of them signups.`); console.log( ` ${pending} more seen but not yet ${OBSERVATION_WINDOW_DAYS} days old, so not counted yet.`, ); console.log( ` Mean durable use ${all.meanR.toFixed(3)} (sd ${all.sdR.toFixed(3)}), effective n ${all.weight.toFixed(1)}.`, ); console.log( ` ${VOICE_POOL.length} selling points, solved through ${all.rank} latent ` + `dimension${all.rank === 1 ? '' : 's'} — all the evidence has paid for.`, ); console.log(` The sampler is ${sharpness}% of the way from uniform to decided.`); if (all.rank === 0) { console.log(' Nothing is estimated yet, so all nine are drawn evenly. As intended.'); } console.log(''); console.log(` ${'id'.padEnd(16)} ${col('all')} ${col('recent')} ${col('shown')} selling point`); const ranked = [...VOICE_POOL].sort((a, b) => effect(all, b.id) - effect(all, a.id)); for (const point of ranked) { console.log( ` ${point.id.padEnd(16)} ${col(signed(effect(all, point.id)))} ` + `${col(signed(effect(recent, point.id)))} ` + `${col(`${Math.round((all.rate[point.id] ?? 0) * 100)}%`)} ` + summarise(point.heading.en), ); } console.log(''); console.log(` Effects are in standard deviations of the reward. Recent = last ${RECENT_WINDOW}.`); console.log(''); } /** Weights are only meaningful relative to the spread of the reward. */ function effect(fit: VoiceFit, id: string): number { if (!(fit.sdR > 1e-9)) return 0; return (fit.weights[id] ?? 0) / fit.sdR; } function signed(value: number): string { return (value >= 0 ? '+' : '') + value.toFixed(3); } function col(text: string): string { return text.padStart(8); } function summarise(text: string): string { const flat = text.replace(/\s+/g, ' ').trim(); return flat.length > 58 ? `${flat.slice(0, 57)}…` : flat; } main();