Files
jason.woltje 4ff4f44c98 lead: commit researcher's untracked evidence (1406 files: queue-101 queue-105 queue-128 queue-134 queue-143 queue-148 queue-183 queue-228)
Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
2026-11-02 15:05:14 -06:00

127 lines
9.9 KiB
JavaScript

// Row 148 round 3 (sage-0617): criterion B, a second reading of the same probe cells. It does not
// replace Mos's x2.2 table (probe-gen.mjs writes that); it sits beside it.
//
// Criterion B flags a cell when EITHER
// Q two consecutive doublings each grow by x3.5 or more (the quadratic signature), or
// C its ratio per doubling is above 2.2 AND above the no-module control's ratio per doubling
// over the same two sizes.
// Q needs the sizes between the two ends. Cells the strict rule did not flag have only the two end
// measurements and a ratio at or below 2.2, so neither clause can fire on them; this script says so in
// its output. Strict-flagged cells that lack the middle sizes get them measured here, one process each.
//
// Usage: node criterion-b.mjs --module F --cells probe-final/cells.jsonl --control control-concat-runs.txt
// --out criterion-b.md [--r2 dir[,dir...]] [--small 64] [--big 1024]
import { readFileSync, writeFileSync, appendFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const args = process.argv.slice(2);
const opt = (name, dflt) => { const i = args.indexOf('--' + name); return i < 0 ? dflt : args[i + 1]; };
const MODULE = resolve(opt('module')), CELLS = resolve(opt('cells')), OUT = resolve(opt('out', 'criterion-b.md'));
const CONTROL = resolve(opt('control')), R2 = opt('r2', '').split(',').filter(Boolean).map(x => resolve(x));
const SMALL = Number(opt('small', '64')), BIG = Number(opt('big', '1024'));
const LIMIT = 2.2, STEP = 3.5, TIMEOUT = 20;
const SELF = resolve(dirname(fileURLToPath(import.meta.url)), 'probe-gen.mjs');
const EXTRA = OUT.replace(/\.md$/, '-cells.jsonl');
writeFileSync(EXTRA, '');
const load = file => readFileSync(file, 'utf8').split('\n').filter(Boolean).map(l => JSON.parse(l));
const key = c => JSON.stringify([c.opener, c.filler, c.term]);
function group(records) {
const m = new Map();
for (const r of records) {
if (!m.has(key(r))) m.set(key(r), { opener: r.opener, filler: r.filler, term: r.term, by: {} });
if (r.status === 'ok') m.get(key(r)).by[r.kib] = r.ms;
}
return [...m.values()];
}
const f1 = x => x === undefined ? '-' : x >= 100 ? x.toFixed(0) : x.toFixed(1);
const chainOf = (c, small, big) => {
const sizes = Object.keys(c.by).map(Number).filter(s => s >= small && s <= big).sort((a, b) => a - b);
const complete = sizes.length > 2 && sizes.every((s, i) => i === 0 || s === sizes[i - 1] * 2);
return complete && sizes[0] === small && sizes.at(-1) === big
? sizes.slice(1).map((s, i) => +(c.by[s] / Math.max(c.by[sizes[i]], 0.001)).toFixed(2)) : null;
};
const quad = chain => chain !== null && chain.some((x, i) => i > 0 && x >= STEP && chain[i - 1] >= STEP);
const ratio = (c, small, big) => (c.by[big] / Math.max(c.by[small], 0.001)) ** (1 / Math.log2(big / small));
// ---- the no-module control: "<KiB> KiB <ms> ms" lines from ctl-concat.mjs, one process each -------
const ctl = readFileSync(CONTROL, 'utf8').split('\n').map(l => l.match(/^(\d+) KiB ([\d.]+) ms/)).filter(Boolean).map(m => ({ kib: +m[1], ms: +m[2] }));
const ctlAt = k => ctl.filter(x => x.kib === k).map(x => x.ms).sort((a, b) => a - b);
// the runs at one size are paired in file order, the ratios sorted for the spread
const ratiosSorted = (() => {
const pairs = []; let last;
for (const x of ctl) { if (x.kib === SMALL) last = x.ms; else if (x.kib === BIG && last !== undefined) { pairs.push((x.ms / last) ** (1 / Math.log2(BIG / SMALL))); last = undefined; } }
return pairs.sort((a, b) => a - b);
})();
const median = a => a[a.length >> 1];
const CTL_RATIO = median(ratiosSorted);
// ---- the 756 cells ---------------------------------------------------------------------------------
const cells = group(load(CELLS)).filter(c => c.by[SMALL] !== undefined && c.by[BIG] !== undefined);
for (const c of cells) c.ratio = ratio(c, SMALL, BIG);
const strict = cells.filter(c => c.ratio > LIMIT);
for (const c of strict) {
for (let s = SMALL * 2; s < BIG; s *= 2) {
if (c.by[s] !== undefined) continue;
const r = spawnSync(process.execPath, [SELF, 'cell', MODULE, c.opener, c.filler, c.term, String(s)], { encoding: 'utf8', timeout: TIMEOUT * 1000, killSignal: 'SIGKILL', maxBuffer: 1 << 20 });
if (r.status !== 0) { appendFileSync(EXTRA, JSON.stringify({ opener: c.opener, filler: c.filler, term: c.term, kib: s, status: 'error', code: r.status }) + '\n'); continue; }
const rec = JSON.parse(r.stdout); c.by[s] = rec.ms;
appendFileSync(EXTRA, JSON.stringify({ opener: c.opener, filler: c.filler, term: c.term, kib: s, status: 'ok', ...rec }) + '\n');
}
c.chain = chainOf(c, SMALL, BIG);
c.q = quad(c.chain);
c.c = c.ratio > LIMIT && c.ratio > CTL_RATIO;
c.cMax = c.ratio > LIMIT && c.ratio > ratiosSorted.at(-1);
}
const flaggedB = strict.filter(c => c.q || c.c);
const flaggedQ = strict.filter(c => c.q);
const flaggedCmax = strict.filter(c => c.q || c.cMax);
const noChain = strict.filter(c => c.chain === null);
const L = [];
L.push('# Criterion B, beside the x2.2 table (sage-0617)', '',
`Same ${cells.length} cells as probe-final/table.md (module ${MODULE}); the x2.2 table is unchanged and still lists ${strict.length} flagged cells.`,
`Criterion B flags a cell when Q: two consecutive doublings each grow by x${STEP} or more, or C: its ratio per doubling is above ${LIMIT} and above the no-module control's ratio over the same sizes (${SMALL} to ${BIG} KiB).`, '',
'Q needs the sizes between the ends. The strict-flagged cells that lacked them were measured here (criterion-b-cells.jsonl). The ' + (cells.length - strict.length) + ' cells at or below x2.2 have only the two end measurements and no step data, so Q is not evaluated on them and C cannot fire; that is a gap in this table, not a finding.', '',
'## The no-module control', '',
`ctl-concat.mjs: split on newline, one regex replace per line, string concatenation; no parser. One process per run, median of 5 repetitions inside it. ${ratiosSorted.length} paired runs at ${SMALL} and ${BIG} KiB.`, '',
'| size | runs (ms, sorted) |', '|---|---|',
`| ${SMALL} KiB | ${ctlAt(SMALL).map(x => x.toFixed(1)).join(', ')} |`,
`| ${BIG} KiB | ${ctlAt(BIG).map(x => x.toFixed(1)).join(', ')} |`, '',
`Ratio per doubling, sorted over the paired runs: ${ratiosSorted.map(x => 'x' + x.toFixed(2)).join(', ')}. Median x${CTL_RATIO.toFixed(2)}, max x${ratiosSorted.at(-1).toFixed(2)}. Clause C uses the median; the max is shown as a sensitivity.`, '',
'## Result on the generated cells', '',
'| reading | flagged cells |', '|---|---|',
`| x${LIMIT} rule alone (Mos's table) | ${strict.length} of ${cells.length} |`,
`| Q only (quadratic signature) | ${flaggedQ.length} of ${cells.length} |`,
`| Q or C, control median x${CTL_RATIO.toFixed(2)} (criterion B) | ${flaggedB.length} of ${cells.length} |`,
`| Q or C, control max x${ratiosSorted.at(-1).toFixed(2)} (sensitivity) | ${flaggedCmax.length} of ${cells.length} |`,
`| strict-flagged cells without a complete step chain | ${noChain.length} |`, '');
if (flaggedB.length) {
L.push('### Cells flagged by criterion B', '', `| cell | ms at ${SMALL} KiB | ms at ${BIG} KiB | ratio | step ratios | Q | C |`, '|---|---|---|---|---|---|---|');
for (const c of flaggedB.sort((a, b) => b.ratio - a.ratio)) L.push(`| ${JSON.stringify(c.opener)} + ${c.filler} + ${c.term} | ${f1(c.by[SMALL])} | ${f1(c.by[BIG])} | x${c.ratio.toFixed(2)} | ${c.chain ? c.chain.map(x => 'x' + x).join(' ') : '-'} | ${c.q ? 'yes' : 'no'} | ${c.c ? 'yes' : 'no'} |`);
L.push('');
}
L.push('### Step ratios of the strict-flagged cells that Q does not flag, largest first (first 20)', '', `| cell | ratio | step ratios |`, '|---|---|---|');
for (const c of strict.filter(c => !c.q).sort((a, b) => Math.max(...(b.chain ?? [0])) - Math.max(...(a.chain ?? [0]))).slice(0, 20)) L.push(`| ${JSON.stringify(c.opener)} + ${c.filler} + ${c.term} | x${c.ratio.toFixed(2)} | ${c.chain ? c.chain.map(x => 'x' + x).join(' ') : '-'} |`);
L.push('', `Largest single step among the strict-flagged cells: x${Math.max(...strict.map(c => Math.max(...(c.chain ?? [0])))).toFixed(2)}.`, '');
// ---- the round 2 module control, same evaluator ----------------------------------------------------
L.push('## Control: the round 2 module (known quadratic in FENCE, ATX, ITEM)', '');
let r2all = [];
for (const d of R2) r2all = r2all.concat(group(load(resolve(d, 'cells.jsonl'))));
if (r2all.length) {
const r2small = Math.min(...r2all.flatMap(c => Object.keys(c.by).map(Number))), r2big = Math.max(...r2all.flatMap(c => Object.keys(c.by).map(Number)));
const r2 = r2all.filter(c => c.by[r2small] !== undefined && c.by[r2big] !== undefined);
for (const c of r2) { c.ratio = ratio(c, r2small, r2big); c.chain = chainOf(c, r2small, r2big); c.q = quad(c.chain); }
const r2flag = r2.filter(c => c.ratio > LIMIT);
L.push(`Sizes ${r2small} to ${r2big} KiB, ${r2.length} cells from the four round 2 control runs (r3/control-r2/*), measured with the same generator.`, '',
`| reading | flagged cells |`, '|---|---|', `| x${LIMIT} rule alone | ${r2flag.length} of ${r2.length} |`, `| Q | ${r2.filter(c => c.q).length} of ${r2.length} (${r2.filter(c => c.chain === null && c.ratio > LIMIT).length} flagged cells have no step chain) |`, '',
`| cell | ms at ${r2small} KiB | ms at ${r2big} KiB | ratio | step ratios | Q |`, '|---|---|---|---|---|---|');
for (const c of r2flag.sort((a, b) => b.ratio - a.ratio).slice(0, 12)) L.push(`| ${JSON.stringify(c.opener)} + ${c.filler} + ${c.term} | ${f1(c.by[r2small])} | ${f1(c.by[r2big])} | x${c.ratio.toFixed(2)} | ${c.chain ? c.chain.map(x => 'x' + x).join(' ') : '-'} | ${c.q ? 'yes' : 'no'} |`);
} else L.push('No round 2 control directories given.');
writeFileSync(OUT, L.join('\n') + '\n');
console.log(`strict ${strict.length}, Q ${flaggedQ.length}, B ${flaggedB.length}, B(max) ${flaggedCmax.length}, noChain ${noChain.length}, control median x${CTL_RATIO.toFixed(2)}`);