#!/usr/bin/env node /** * A-P3b — flywheel generation-over-generation on REAL data, compounding, with a * promotion rule strong enough that a win is genuinely PROVEN: * * BENCHMARK (frozen held-out) : a LARGE self-supervised self-retrieval set * harvested from the real store (N big enough that a mean gain can clear * the accept/v1+sig bootstrap significance term). Split disjointly into * TRAIN (selection only) / HELD (frozen gate) / CANARY (deployment slice). * GUARD (redblue) : the 10 human-labeled ADR-081 queries — a * candidate must NOT regress human relevance (no Goodhart drift). * CANARY : a separate harvested slice — no catastrophic * per-item regression (deployment safety, distinct from the held-out). * * Selection on TRAIN, promotion gated on the FROZEN HELD-OUT (no leakage), * multi-axis grid Evolve, winner → next baseline (compounding). Emits a real * evolve-proof receipt bundle per generation; proves the run with * reconstructLineage + mutationEffectiveness + detectPlateau. $0. * * Usage: node scripts/flywheel-generations.mjs [--generations N] [--sample M] [--dir ] */ import { mkdirSync, writeFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join, resolve } from 'node:path'; import { performance } from 'node:perf_hooks'; const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); const CLI_ROOT = resolve(SCRIPT_DIR, '..'); const d = (p) => join(CLI_ROOT, 'dist/src', p); const { runRealEvolveRound, reconstructLineage, mutationEffectiveness, detectPlateau, verifyReceiptBundle } = await import(`file://${d('services/evolve-proof.js')}`); const { harvestSelfSupervisedTasks } = await import(`file://${d('services/harness-corpus-harvester.js')}`); const neural = await import(`file://${d('mcp-tools/neural-tools.js')}`); const tool = neural.neuralTools.find((t) => t.name === 'neural_patterns'); if (!tool) { console.error('neural_patterns unavailable'); process.exit(1); } const arg = (f, dflt) => { const i = process.argv.indexOf(f); return i > -1 ? process.argv[i + 1] : dflt; }; const MAX_GEN = Number(arg('--generations', 5)); const SAMPLE = Number(arg('--sample', 120)); const projectRoot = resolve(arg('--dir', CLI_ROOT)); const NOW0 = 1_700_000_200_000; const FROZEN = 'harvested-selfsup-frozen-v1'; // ── Human relevance guard (ADR-081) ─────────────────────────────────────────── const RAW = [ ['how was the Opus model alias fixed', ['opus 4.8', 'opus alias', 'opus model alias', '#2232']], ['self-learning wiring task-completed pretrain', ['self-learning', 'adr-074', '#2245', 'task-completed']], ['deterministic codemod engine var-to-const', ['deterministic tier-1 codemod', 'adr-143', 'codemod', 'var-to-const']], ['MCP server orphan leak parent-death', ['mcp orphan', 'parent-death', '#2234', 'orphan on every claude']], ['unified learning stats aggregator', ['unified learning-stats', 'adr-075']], ['structured distillation 4-field schema', ['structured distillation', 'adr-076', '4-field schema']], ['SQL injection migrate.ts table identifier', ['sql injection', 'migrate.ts', 'agentdb', 'cve']], ['recall@k HNSW benchmark harness', ['hnsw', 'recall@k', 'benchmark intelligence']], ['Q-learning encoder keyword block', ['q-state encoder', 'keyword block', '#2239', 'q-encoder']], ['security hardening crypto random IDs', ['cwe-347', 'crypto.randomuuid', 'random id', 'crypto random']], ]; const ANCHOR = RAW.map(([q, labels], i) => ({ id: `anchor-${i}`, q, labels })); const isRel = (name, labels) => !!name && labels.some((s) => String(name).toLowerCase().includes(s.toLowerCase())); function ndcg3(names, labels) { const rel = names.slice(0, 3).map((n) => isRel(n, labels)); const dcg = rel.reduce((a, r, i) => a + (r ? 1 / Math.log2(i + 2) : 0), 0); const num = rel.filter(Boolean).length; if (!num) return 0; let idcg = 0; for (let i = 0; i < num; i++) idcg += 1 / Math.log2(i + 2); return dcg / idcg; } // ── Large frozen self-supervised benchmark, split disjointly ────────────────── const patterns = neural.getStorePatterns(); const harvested = harvestSelfSupervisedTasks(patterns, { sample: SAMPLE }); const nTrain = Math.floor(harvested.length * 0.4), nHeld = Math.floor(harvested.length * 0.4); const TRAIN = harvested.slice(0, nTrain); const HELD = harvested.slice(nTrain, nTrain + nHeld); // FROZEN — never used for selection const CANARY = harvested.slice(nTrain + nHeld); // separate deployment slice console.log(`store=${patterns.length} harvested=${harvested.length} → train=${TRAIN.length} held=${HELD.length} canary=${CANARY.length} anchor=${ANCHOR.length}`); if (HELD.length < 20) { console.error('held-out too small for significance — need a bigger store/sample'); process.exit(1); } const key = (c) => `a${c.alpha}_sw${c.subjectWeight}_mmr${c.mmrLambda}_bw${c.bodyWeight}_tp${c.typePenaltyFactor}`; const cache = new Map(); async function ranked(qid, q, cfg) { const ck = `${qid}::${key(cfg)}`; if (cache.has(ck)) return cache.get(ck); const r = await tool.handler({ action: 'search', query: q, mode: 'hybrid', limit: 5, rerank: false, ...cfg }); const out = (r.results || []).slice(0, 5).map((m) => ({ id: m?.id ?? '', name: m?.name ?? '' })); cache.set(ck, out); return out; } const rr = (items, targetId) => { const i = items.findIndex((x) => x.id === targetId); return i >= 0 ? 1 / (i + 1) : 0; }; // self-retrieval reciprocal rank for a harvested task async function selfRR(task, cfg) { return rr(await ranked(task.id, task.input.q, cfg), task.expected); } const meanSelfRR = async (tasks, cfg) => { let s = 0; for (const t of tasks) s += await selfRR(t, cfg); return s / tasks.length; }; async function anchorMean(cfg) { let s = 0; for (const a of ANCHOR) s += ndcg3((await ranked(a.id, a.q, cfg)).map((x) => x.name), a.labels); return s / ANCHOR.length; } const DEFAULTS = { alpha: 0.5, subjectWeight: 2, mmrLambda: 0.7, bodyWeight: 1, typePenaltyFactor: 1 }; function coarseGrid() { const g = []; for (const alpha of [0.3, 0.5, 0.7]) for (const subjectWeight of [1, 2, 3]) for (const mmrLambda of [0.5, 0.7, 0.9]) for (const bodyWeight of [1, 1.5]) for (const typePenaltyFactor of [1, 0.5]) g.push({ alpha, subjectWeight, mmrLambda, bodyWeight, typePenaltyFactor }); return g; } function localGrid(c) { const ax = { alpha: [c.alpha, +(c.alpha - 0.1).toFixed(2), +(c.alpha + 0.1).toFixed(2)].filter((v) => v > 0 && v < 1), subjectWeight: [...new Set([c.subjectWeight, Math.max(0.5, c.subjectWeight - 0.5), c.subjectWeight + 0.5])], mmrLambda: [c.mmrLambda, +(c.mmrLambda - 0.1).toFixed(2), +(c.mmrLambda + 0.1).toFixed(2)].filter((v) => v >= 0 && v <= 1), bodyWeight: [...new Set([c.bodyWeight, Math.max(0.5, c.bodyWeight - 0.5), c.bodyWeight + 0.5])], typePenaltyFactor: [...new Set([c.typePenaltyFactor, Math.max(0.25, c.typePenaltyFactor - 0.25), Math.min(1, c.typePenaltyFactor + 0.25)])] }; const g = [], u = new Set(); for (const alpha of ax.alpha) for (const subjectWeight of ax.subjectWeight) for (const mmrLambda of ax.mmrLambda) for (const bodyWeight of ax.bodyWeight) for (const typePenaltyFactor of ax.typePenaltyFactor) { const cfg = { alpha, subjectWeight, mmrLambda, bodyWeight, typePenaltyFactor }; if (u.has(key(cfg))) continue; u.add(key(cfg)); g.push(cfg); } return g; } const bundles = []; let champion = DEFAULTS, parent = null, promotions = 0; const anchorBaseline = await anchorMean(DEFAULTS); const t0 = performance.now(); for (let gen = 0; gen < MAX_GEN && promotions < 2; gen++) { const grid = gen === 0 ? coarseGrid() : localGrid(champion); // CONSTRAINED (multi-objective Pareto) selection: maximize self-retrieval on // TRAIN *subject to* not regressing the human anchor — so we never pick a // config that games the cheap metric at relevance's expense. Honest, not gaming. const champTrain = await meanSelfRR(TRAIN, champion); let cand = champion, candTrain = champTrain, considered = 0; for (const c of grid) { if (key(c) === key(champion)) continue; if ((await anchorMean(c)) < anchorBaseline - 0.02) continue; // constraint: no anchor regression considered++; const s = await meanSelfRR(TRAIN, c); if (s > candTrain + 1e-9) { candTrain = s; cand = c; } } // frozen held-out measurement (self-retrieval RR per task) const holdout = []; for (const t of HELD) holdout.push({ taskId: t.id, baselineScore: await selfRR(t, champion), candidateScore: await selfRR(t, cand) }); // separate canary slice: catastrophic per-item regression (> 0.5 RR drop) let cRoll = 0; for (const t of CANARY) { if ((await selfRR(t, cand)) < (await selfRR(t, champion)) - 0.5) cRoll++; } const canaryRollbackRate = CANARY.length ? cRoll / CANARY.length : 0; // human-relevance guard: no anchor regression const candAnchor = await anchorMean(cand); const redblue = candAnchor >= anchorBaseline - 0.02 ? 'PASS' : 'FAIL'; const bundle = runRealEvolveRound({ baseline: champion, candidate: cand, holdout, generation: gen, parent, branch: 'main', now: NOW0 + gen * 1000, redblue, canaryRollbackRate, corpus: FROZEN }); bundles.push(bundle); const p = bundle.decisionReceipt.promoted; console.log(`gen ${gen}: cand=${key(cand)} anchorSafeConsidered=${considered} heldΔ=${bundle.deltas.benchmark.toFixed(4)} CIlow=${bundle.decisionReceipt.deltaCILow.toFixed(4)} sig=${bundle.decisionReceipt.significant} canaryRoll=${canaryRollbackRate.toFixed(3)} anchor=${candAnchor.toFixed(3)}(base ${anchorBaseline.toFixed(3)}) redblue=${redblue} promoted=${p} ${p ? '' : bundle.decisionReceipt.reason}`); if (p) { champion = cand; parent = bundle.candidateManifestHash; promotions++; } } const elapsed = ((performance.now() - t0) / 1000).toFixed(0); const lineage = reconstructLineage(bundles); const plateau = detectPlateau(bundles, { window: 3 }); console.log(`\n=== REAL LINEAGE (${elapsed}s, ${bundles.length} gens) ===`); console.log(`promotions=${lineage.promotions} rejections=${lineage.rejections} lineageIntact=${lineage.lineageIntact} allReplayable=${lineage.allReplayable} rootHash=${(lineage.rootHash || '').slice(0, 22)}…`); console.log('mutationEffectiveness:', JSON.stringify(mutationEffectiveness(bundles))); console.log('plateau:', plateau.status, '-', plateau.rationale); console.log('independent replay:', bundles.map((b, i) => `g${i}:${verifyReceiptBundle(b).valid}`).join(' ')); const outDir = join(projectRoot, '.claude', 'evolve-proof'); mkdirSync(outDir, { recursive: true }); bundles.forEach((b, i) => writeFileSync(join(outDir, `real-generation-${i}.json`), JSON.stringify(b, null, 2) + '\n')); const milestone = lineage.promotions >= 2 && lineage.lineageIntact && lineage.allReplayable; console.log('='.repeat(70)); console.log(milestone ? `MILESTONE MET: ${lineage.promotions} real, significant, independently-replayable promotions chained to the immutable root — the flywheel turns.` : `MILESTONE NOT MET: ${lineage.promotions} promotion(s); plateau=${plateau.status}. Honest — no faked pass.`); process.exit(milestone ? 0 : 3);