Spreadsheet-UX op een echte relationele engine

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

3.3 kB Ruw bestand
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();