voyage/tests/scripts/yardstick.test.mjs
Kjell Tore Guttormsen ee4d748639
test(yardstick): use counts an order only when a Voyage record names its id (red)
measureUse({ queue, runs, cutoff, countingSince }): runs come from
orderRuns(stats) - trekbrief-stats.jsonl only. YES = a trekbrief record names
the order's id under one slug that names no other order; declared NO = a
new-work order carrying <!-- arbeidsform: ordre --> on its own line; no
record or a disputed record = NOT MEASURED, never a no (PM 04.10, point 1).
countingSince null -> NOT COUNTABLE, every order not measured; the window
starts at the latest of cutoff, MARKER_SINCE and the counting start.
facts.ordersNamedByARecord is the known-positive diagnostic (SC8).

Existing use tests get countingSince = MARKER_SINCE (their window unchanged)
and records instead of slugs; their denominators now read YES + declared NO.
Replaced: "a new-work order without a slug leaves the numerator NOT
MEASURED" - the slug join it guarded is gone. New exports are read through a
namespace import, so the trust/interrupts/mutants tests still run.

Red: 24 of 43 fail (every use test, the two measureAll tests, the symlink
CLI test); 19 pass, none of them new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 19:52:22 +02:00

660 lines
32 KiB
JavaScript

// tests/scripts/yardstick.test.mjs
// The yardstick prints Voyage's three numbers (use · trust · interrupts) with
// denominators read from their SOURCE, plus a fourth row that asks whether the
// end-state gate itself can be fooled by a signature-preserving mutant.
//
// Like the gate's own test, these tests pin the MECHANICS in both directions
// against throwaway fixtures - every number can be countable and can be not
// countable, the mutant row can read felled and not felled. They deliberately
// do NOT assert that the real data is red today: the yardstick is supposed to
// turn green, and a test that pins today's distance would fail on the day the
// work is done. Nothing here reads the real order queue or the real stats.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, symlinkSync } from 'node:fs';
import { spawnSync } from 'node:child_process';
import { tmpdir } from 'node:os';
import { join, dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
DEFAULT_CUTOFF,
MARKER_SINCE,
loadStats,
readOrders,
measureUse,
measureTrust,
measureInterrupts,
emitterCallSites,
buildM9Tree,
measureMutants,
measureAll,
render,
main,
} from '../../scripts/yardstick.mjs';
// New exports are read through the namespace, so a missing one fails its own
// tests instead of failing this whole file at link time.
import * as Y from '../../scripts/yardstick.mjs';
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
// --- helpers ---------------------------------------------------------------
function fixture(files) {
const dir = mkdtempSync(join(tmpdir(), 'yardstick-'));
for (const [rel, body] of Object.entries(files)) {
const p = join(dir, rel);
mkdirSync(dirname(p), { recursive: true });
writeFileSync(p, body);
}
return dir;
}
const cleanup = (...dirs) => { for (const d of dirs) rmSync(d, { recursive: true, force: true }); };
const jsonl = (...rows) => `${rows.map((r) => (typeof r === 'string' ? r : JSON.stringify(r))).join('\n')}\n`;
// `marker` writes the order's solution-choice marker the way dispatch does: an
// HTML comment on its own line in the body, `<!-- loesningsvalg: <value>; grunn=... -->`.
// `arbeidsform` writes `<!-- arbeidsform: <value> -->` on its own line, as dispatch does.
function order({ id, date, workClass, slug, marker, arbeidsform, extra = '' }) {
const lines = ['---', 'from: .claude', 'to: some-repo', `order-id: ${id}`, `subject: order ${id}`, `date: ${date}`];
if (workClass !== undefined) lines.push(`work-class: ${workClass}`);
if (slug !== undefined) lines.push(`slug: ${slug}`);
lines.push('---');
if (arbeidsform !== undefined) lines.push(`<!-- arbeidsform: ${arbeidsform} -->`);
if (marker !== undefined) lines.push(`<!-- loesningsvalg: ${marker}; grunn=fixture -->`);
lines.push('', `# ORDER ${id}`, extra, '');
return lines.join('\n');
}
const review = (ts, verdict, slug = 's') => ({ ts, slug, verdict });
// A /trekbrief stats record naming the order it ran (the writer adds order_*).
const briefRun = ({ order_id, slug = 's', ts = '2026-10-04T10:00:00Z' }) => ({ ts, slug, order_id, order_claimed_at: ts, order_reason: order_id ? null : 'none-claimed' });
// The runs index the yardstick joins on, built from stats files `{ name: [records] }`.
function runsFrom(files = {}) {
const dir = fixture(Object.fromEntries(Object.entries(files).map(([n, recs]) => [n, jsonl(...recs)])));
try { return Y.orderRuns(loadStats(dir)); } finally { cleanup(dir); }
}
const runsOf = (...records) => runsFrom(records.length ? { 'trekbrief-stats.jsonl': records } : {});
// measureUse over a fixture queue; counting starts at MARKER_SINCE unless the test says otherwise.
function use(files, { records = [], runs, cutoff = DEFAULT_CUTOFF, countingSince = MARKER_SINCE } = {}) {
const coord = fixture(files);
try {
return measureUse({ queue: readOrders(coord), runs: runs ?? runsOf(...records), cutoff, countingSince });
} finally { cleanup(coord); }
}
// --- the stats loader --------------------------------------------------------
test('loadStats: an invalid JSON line is COUNTED, never silently dropped', () => {
const dir = fixture({
'trekreview-stats.jsonl': jsonl(review('2026-09-01T00:00:00Z', 'ALLOW'), '{not json', '', review('2026-09-02T00:00:00Z', 'BLOCK')),
});
try {
const stats = loadStats(dir);
const f = stats.files.find((x) => x.name === 'trekreview-stats.jsonl');
assert.equal(f.lines, 3, 'blank lines are not lines; the invalid one is');
assert.equal(f.records.length, 2);
assert.deepEqual(f.invalid, [2], 'the invalid line is reported by its line number');
} finally { cleanup(dir); }
});
test('loadStats: a missing data directory is reported, not read as zero', () => {
const stats = loadStats(join(tmpdir(), 'yardstick-no-such-dir-8f3a'));
assert.equal(stats.missing, true);
assert.deepEqual(stats.files, []);
});
// --- 2 · TRUST ---------------------------------------------------------------
test('trust: the ALLOW streak is read in ts order, not file order', () => {
// File order ends on ALLOW, ALLOW; chronologically the last review is a BLOCK.
const dir = fixture({
'trekreview-stats.jsonl': jsonl(
review('2026-09-01T00:00:00Z', 'ALLOW'),
review('2026-09-05T00:00:00Z', 'BLOCK'),
review('2026-09-02T00:00:00Z', 'ALLOW'),
review('2026-09-03T00:00:00Z', 'ALLOW'),
),
});
try {
const row = measureTrust(loadStats(dir));
assert.equal(row.countable, true);
assert.equal(row.denominator, 4);
assert.equal(row.value, 0, 'the chronologically last review is a BLOCK');
assert.equal(row.facts.longestStreak, 3);
assert.deepEqual(row.facts.verdicts, { ALLOW: 3, BLOCK: 1 });
assert.equal(row.facts.last.verdict, 'BLOCK');
} finally { cleanup(dir); }
});
test('trust: both spacings of the verdict field count the same (it is read as JSON, not grepped)', () => {
const dir = fixture({
'trekreview-stats.jsonl': jsonl(
'{"ts": "2026-09-01T00:00:00Z", "slug": "a", "verdict": "BLOCK"}',
'{"ts":"2026-09-02T00:00:00Z","slug":"b","verdict":"ALLOW"}',
),
});
try {
const row = measureTrust(loadStats(dir));
assert.deepEqual(row.facts.verdicts, { BLOCK: 1, ALLOW: 1 });
assert.equal(row.value, 1);
} finally { cleanup(dir); }
});
test('trust: an invalid line is left out of n and said out loud', () => {
const dir = fixture({
'trekreview-stats.jsonl': jsonl(review('2026-09-01T00:00:00Z', 'ALLOW'), '{"ts": oops'),
});
try {
const row = measureTrust(loadStats(dir));
assert.equal(row.denominator, 1);
assert.equal(row.facts.invalid, 1);
assert.match(row.detail, /1 invalid line/);
} finally { cleanup(dir); }
});
test('trust: an empty or missing review file is NOT countable', () => {
const empty = fixture({ 'trekreview-stats.jsonl': '' });
const none = fixture({ 'trekplan-stats.jsonl': jsonl({ ts: '2026-09-01T00:00:00Z', slug: 'x' }) });
try {
for (const dir of [empty, none]) {
const row = measureTrust(loadStats(dir));
assert.equal(row.countable, false, dir);
assert.equal(row.value, null);
assert.ok(row.detail.length > 0, 'the row must say WHY it cannot be counted');
}
} finally { cleanup(empty, none); }
});
// --- 1 · USE -----------------------------------------------------------------
test('use: orders are read from orders/, archive/ and claimed/, and nothing else', () => {
const coord = fixture({
'repo-a/orders/o1.md': order({ id: 'o1', date: '2026-09-22T10:00:00Z' }),
'repo-a/orders/archive/o2.md': order({ id: 'o2', date: '2026-09-01T10:00:00Z' }),
'repo-b/orders/claimed/o3.md': order({ id: 'o3', date: '2026-09-22T10:00:00Z' }),
'repo-b/orders/claimed/o3.claim': 'claimed',
'repo-b/inbox/m1.md': order({ id: 'm1', date: '2026-09-22T10:00:00Z' }),
'repo-b/orders/broken.md': 'no frontmatter at all\n',
});
try {
const q = readOrders(coord);
assert.equal(q.files, 4, 'three orders and one unreadable file, all .md under */orders/');
assert.equal(q.orders.length, 3);
assert.equal(q.unreadable.length, 1);
} finally { cleanup(coord); }
});
test('use: a dot-mailbox is a mailbox - its orders count, and the detail names it', () => {
// Measured 2026-09-22: a hand count over `coord/*/orders` came out lower than
// the yardstick, because the shell's `*` skips dot-directories and the queue
// does not. The detail names them, so the next re-measure can reconcile.
const coord = fixture({
'r/orders/o1.md': order({ id: 'o1', date: '2026-09-22T10:00:00Z' }),
'.pm/orders/archive/o2.md': order({ id: 'o2', date: '2026-09-22T10:00:00Z' }),
});
try {
const q = readOrders(coord);
assert.equal(q.orders.length, 2);
const row = measureUse({ queue: q, runs: runsOf(), cutoff: DEFAULT_CUTOFF, countingSince: MARKER_SINCE });
assert.match(row.detail, /2 order files in 2 mailboxes/);
assert.match(row.detail, /dot-mailboxes .pm 1/);
} finally { cleanup(coord); }
});
test('use: the marker is counted from 2026-09-28, the day pre-order-loesningsvalg.sh began enforcing it', () => {
assert.equal(MARKER_SINCE, '2026-09-28');
});
test('use: no order carrying a loesningsvalg marker means NOT COUNTABLE, not 0 %', () => {
const row = use({
'r/orders/o1.md': order({ id: 'o1', date: '2026-09-29T10:00:00Z' }),
'r/orders/o2.md': order({ id: 'o2', date: '2026-09-30T10:00:00Z' }),
});
assert.equal(row.countable, false);
assert.equal(row.value, null);
assert.equal(row.denominator, 0);
assert.equal(row.facts.scanned, 2);
assert.equal(row.facts.withMarker, 0);
assert.equal(row.facts.notMeasured, 2, 'an unmarked order is not measured - never a no');
assert.match(row.detail, /0 of 2 orders carry a loesningsvalg marker/);
assert.match(row.detail, /2 not measured/);
});
test('use: plan and prove are NEW work, ikke-nytt is not; unmarked and pre-2026-09-28 orders are not measured', () => {
const row = use({
'r/orders/plan.md': order({ id: 'plan', date: '2026-09-28T00:00:00Z', marker: 'plan' }),
'r/orders/archive/prove.md': order({ id: 'prove', date: '2026-10-01T00:00:00Z', marker: 'prove' }),
'r/orders/claimed/ikke.md': order({ id: 'ikke', date: '2026-10-01T00:00:00Z', marker: 'ikke-nytt' }),
'r/orders/none.md': order({ id: 'none', date: '2026-10-01T00:00:00Z' }),
'r/orders/early.md': order({ id: 'early', date: '2026-09-27T23:59:59Z', marker: 'plan' }),
}, { records: [briefRun({ order_id: 'plan' }), briefRun({ order_id: 'ikke', slug: 'other' }), briefRun({ order_id: 'early', slug: 'old' })] });
assert.equal(row.facts.newWork, 2, 'plan and prove');
assert.equal(row.facts.notNew, 1);
assert.equal(row.facts.beforeMarker, 1);
assert.equal(row.facts.unmarked, 1);
assert.equal(row.facts.withVoyageRun, 1, 'plan has a trekbrief record naming it');
assert.equal(row.facts.noRecord, 1, 'prove has none - not measured, never a no');
assert.equal(row.countable, true);
assert.equal(row.value, 1);
assert.equal(row.denominator, 1, 'YES + declared NO; prove is not measured');
assert.equal(row.facts.notMeasured, 3, 'unmarked, before 2026-09-28, and prove without a record');
assert.match(row.detail, /value = 1 of 1 measured/);
});
test('use: work-class in the frontmatter no longer decides anything - only the marker does', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', workClass: 'new' }),
'r/orders/b.md': order({ id: 'b', date: '2026-09-29T00:00:00Z', workClass: 'maintenance', marker: 'prove' }),
}, { records: [briefRun({ order_id: 'a' }), briefRun({ order_id: 'b', slug: 'b' })] });
assert.equal(row.facts.newWork, 1, 'b is new by its marker; a has no marker and is not measured');
assert.equal(row.value, 1);
assert.equal(row.denominator, 1);
assert.equal(row.facts.notMeasured, 1);
});
test('use: only a marker on its own line counts - a mention in prose or an unknown value is not measured', () => {
const row = use({
'r/orders/prose.md': order({ id: 'prose', date: '2026-09-29T00:00:00Z', extra: 'Count from the marker `<!-- loesningsvalg: plan -->` in the body.' }),
'r/orders/odd.md': order({ id: 'odd', date: '2026-09-29T00:00:00Z', marker: 'kanskje' }),
'r/orders/both.md': order({ id: 'both', date: '2026-09-29T00:00:00Z', marker: 'ikke-nytt', extra: 'Prose names `<!-- loesningsvalg: plan -->` too.' }),
});
assert.equal(row.denominator, 0);
assert.equal(row.facts.notNew, 1, 'both: the line marker wins over the prose mention');
assert.equal(row.facts.notMeasured, 2, 'prose has no marker; kanskje is no known value');
assert.equal(row.countable, false);
});
test('use: a cutoff later than 2026-09-28 moves the start of the count', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/b.md': order({ id: 'b', date: '2026-10-02T00:00:00Z', marker: 'plan' }),
}, { cutoff: '2026-10-01', records: [briefRun({ order_id: 'a' }), briefRun({ order_id: 'b', slug: 'b' })] });
assert.equal(row.facts.newWork, 1);
assert.equal(row.facts.beforeMarker, 1);
assert.equal(row.value, 1, 'b only');
assert.match(row.source, /from 2026-10-01/);
});
// --- use: the order-id join (source C) -------------------------------------------
test('use: a new-work order is YES only when a trekbrief record names its order id', () => {
const row = use({ 'r/orders/o.md': order({ id: 'o', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
{ records: [briefRun({ order_id: 'o' })] });
assert.equal(row.countable, true);
assert.equal(row.value, 1);
assert.equal(row.denominator, 1);
assert.equal(row.facts.withVoyageRun, 1);
assert.deepEqual(row.facts.matched, ['o']);
});
test('use: no record, or a record naming another id, is NOT MEASURED - never a no', () => {
const row = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
{ records: [briefRun({ order_id: 'zzz' })] });
assert.equal(row.facts.noRecord, 1);
assert.equal(row.facts.withVoyageRun, 0);
assert.equal(row.countable, false);
assert.equal(row.value, null);
assert.equal(row.denominator, 0);
assert.equal(row.facts.notMeasured, 1);
});
test('use: an equal slug alone no longer matches - only the order id does', () => {
const row = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan', slug: 'feat-a' }) },
{ records: [briefRun({ order_id: null, slug: 'feat-a' }), briefRun({ order_id: 'other', slug: 'feat-a' })] });
assert.equal(row.facts.withVoyageRun, 0);
assert.equal(row.facts.noRecord, 1);
});
test('use: an order id in another stats file does not count - only /trekbrief records the order', () => {
const row = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
{ runs: runsFrom({ 'trekplan-stats.jsonl': [{ ts: 't', slug: 's', order_id: 'a' }] }) });
assert.equal(row.facts.withVoyageRun, 0);
assert.equal(row.facts.noRecord, 1);
});
test('use: two records with the same id and slug count once; the same id under two slugs is disputed', () => {
const once = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
{ records: [briefRun({ order_id: 'a' }), briefRun({ order_id: 'a', ts: '2026-10-05T00:00:00Z' })] });
assert.equal(once.value, 1);
assert.equal(once.denominator, 1);
const two = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
{ records: [briefRun({ order_id: 'a', slug: 'x' }), briefRun({ order_id: 'a', slug: 'y' })] });
assert.equal(two.facts.disputed, 1);
assert.equal(two.facts.withVoyageRun, 0);
assert.equal(two.countable, false, 'a disputed order is not measured');
});
test('use: one slug naming two order ids makes both disputed - a brief cannot run two orders', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/b.md': order({ id: 'b', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
}, { records: [briefRun({ order_id: 'a', slug: 'one' }), briefRun({ order_id: 'b', slug: 'one' })] });
assert.equal(row.facts.disputed, 2);
assert.equal(row.facts.withVoyageRun, 0);
});
test('use: arbeidsform: ordre is a declared NO even with a record; arbeidsform: voyage with a record is YES', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan', arbeidsform: 'ordre' }),
'r/orders/b.md': order({ id: 'b', date: '2026-09-29T00:00:00Z', marker: 'plan', arbeidsform: 'voyage' }),
}, { records: [briefRun({ order_id: 'a', slug: 'a' }), briefRun({ order_id: 'b', slug: 'b' })] });
assert.equal(row.facts.declaredNo, 1);
assert.equal(row.facts.withVoyageRun, 1);
assert.deepEqual(row.facts.matched, ['b']);
assert.equal(row.value, 1);
assert.equal(row.denominator, 2);
});
test('use: a veto marker mentioned mid-line in prose does not veto', () => {
const row = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan', extra: 'Not this: `<!-- arbeidsform: ordre -->` in a sentence.' }) },
{ records: [briefRun({ order_id: 'a' })] });
assert.equal(row.facts.declaredNo, 0);
assert.equal(row.value, 1);
});
test('use: arbeidsform: ordre on an ikke-nytt or unmarked order adds nothing to the denominator', () => {
const row = use({
'r/orders/y.md': order({ id: 'y', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/i.md': order({ id: 'i', date: '2026-09-29T00:00:00Z', marker: 'ikke-nytt', arbeidsform: 'ordre' }),
'r/orders/u.md': order({ id: 'u', date: '2026-09-29T00:00:00Z', arbeidsform: 'ordre' }),
}, { records: [briefRun({ order_id: 'y' })] });
assert.equal(row.facts.declaredNo, 0);
assert.equal(row.denominator, 1);
});
test('use: arbeidsform: voyage without a record is NOT MEASURED - the declaration is never the source', () => {
const row = use({ 'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan', arbeidsform: 'voyage' }) });
assert.equal(row.facts.withVoyageRun, 0);
assert.equal(row.facts.noRecord, 1);
assert.equal(row.countable, false);
});
test('use: orders before the counting start are NOT MEASURED; an order dated exactly on it counts', () => {
const row = use({
'r/orders/early.md': order({ id: 'early', date: '2026-10-01T23:59:59Z', marker: 'plan' }),
'r/orders/on.md': order({ id: 'on', date: '2026-10-02T00:00:00Z', marker: 'plan' }),
}, { countingSince: '2026-10-02', records: [briefRun({ order_id: 'early', slug: 'e' }), briefRun({ order_id: 'on' })] });
assert.equal(row.facts.beforeMarker, 1);
assert.equal(row.value, 1);
assert.equal(row.denominator, 1);
assert.deepEqual(row.facts.matched, ['on']);
});
test('use: with no counting start the row is NOT COUNTABLE and every order is NOT MEASURED', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/b.md': order({ id: 'b', date: '2026-09-29T00:00:00Z', marker: 'plan', arbeidsform: 'ordre' }),
}, { countingSince: null, records: [briefRun({ order_id: 'a' })] });
assert.equal(row.countable, false);
assert.equal(row.value, null);
assert.equal(row.facts.notMeasured, row.facts.scanned);
assert.equal(row.facts.countingSince, null);
assert.match(row.detail, /counting has not started/);
assert.match(row.source, /counting not started/);
});
test('use: the window starts at the latest of the cutoff, MARKER_SINCE and the counting start', () => {
const files = { 'r/orders/a.md': order({ id: 'a', date: '2026-10-04T00:00:00Z', marker: 'plan' }) };
assert.match(use(files, { cutoff: '2026-10-05', countingSince: '2026-10-03' }).source, /from 2026-10-05/);
assert.match(use(files, { cutoff: '2026-09-21', countingSince: '2026-10-03' }).source, /from 2026-10-03/);
});
test('use: the exact outcome over YES, declared NO, no record and disputed', () => {
const row = use({
'r/orders/y.md': order({ id: 'y', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/n.md': order({ id: 'n', date: '2026-09-29T00:00:00Z', marker: 'prove', arbeidsform: 'ordre' }),
'r/orders/r.md': order({ id: 'r', date: '2026-09-29T00:00:00Z', marker: 'plan', arbeidsform: 'voyage' }),
'r/orders/d.md': order({ id: 'd', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/u.md': order({ id: 'u', date: '2026-09-29T00:00:00Z' }),
'r/orders/e.md': order({ id: 'e', date: '2026-09-01T00:00:00Z', marker: 'plan' }),
}, { records: [briefRun({ order_id: 'y', slug: 'y' }), briefRun({ order_id: 'd', slug: 'd1' }), briefRun({ order_id: 'd', slug: 'd2' })] });
assert.equal(row.countable, true);
assert.equal(row.value, 1);
assert.equal(row.denominator, 2, 'y (YES) + n (declared NO)');
assert.equal(row.facts.withVoyageRun, 1);
assert.equal(row.facts.declaredNo, 1);
assert.equal(row.facts.noRecord, 1);
assert.equal(row.facts.disputed, 1);
assert.equal(row.facts.notMeasured, 4, 'r (no record) + d (disputed) + u (unmarked) + e (before the window)');
assert.match(row.detail, /value = 1 of 2 measured/);
});
test('use: ordersNamedByARecord counts named orders even before counting starts (the known-positive check)', () => {
const row = use({
'r/orders/a.md': order({ id: 'a', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
'r/orders/b.md': order({ id: 'b', date: '2026-09-29T00:00:00Z', marker: 'plan' }),
}, { countingSince: null, records: [briefRun({ order_id: 'a' })] });
assert.equal(row.countable, false);
assert.equal(row.facts.ordersNamedByARecord, 1);
});
// --- 3 · INTERRUPTS ----------------------------------------------------------
test('interrupts: no user_input record means NOT COUNTABLE, with the line denominator stated', () => {
const dir = fixture({
'trekexecute-stats.jsonl': jsonl({ ts: 't', session_id: 's', success: true }, { ts: 't', event: 'main-merge-gate', payload: {} }),
'trekplan-stats.jsonl': jsonl({ ts: 't', slug: 'x' }),
});
try {
const row = measureInterrupts({ stats: loadStats(dir), callSites: { sites: [], scanned: 3 } });
assert.equal(row.countable, false);
assert.equal(row.facts.lines, 3);
assert.equal(row.facts.userInput, 0);
assert.match(row.detail, /0 user_input records of 3 lines in 2 files/);
assert.match(row.detail, /0 emitter call sites/);
} finally { cleanup(dir); }
});
test('interrupts: user_input WITHOUT a slug or run id is still not countable per delivery', () => {
const dir = fixture({
'trekexecute-stats.jsonl': jsonl({ ts: 't', event: 'user_input', payload: { question: 'q' } }),
});
try {
const row = measureInterrupts({ stats: loadStats(dir), callSites: { sites: [], scanned: 1 } });
assert.equal(row.countable, false);
assert.equal(row.facts.userInput, 1);
assert.equal(row.facts.withDelivery, 0);
} finally { cleanup(dir); }
});
test('interrupts: user_input carrying a slug or run id is countable, per delivery', () => {
const dir = fixture({
'trekexecute-stats.jsonl': jsonl(
{ ts: 't1', event: 'user_input', payload: { slug: 'feat-a' } },
{ ts: 't2', event: 'user_input', payload: { slug: 'feat-a' } },
{ ts: 't3', event: 'user_input', payload: { run_id: 'r-9' } },
),
});
try {
const row = measureInterrupts({ stats: loadStats(dir), callSites: { sites: [], scanned: 1 } });
assert.equal(row.countable, true);
assert.equal(row.value, 3);
assert.deepEqual(row.facts.perDelivery, { 'feat-a': 2, 'r-9': 1 });
} finally { cleanup(dir); }
});
test('emitterCallSites: counts user_input emissions outside lib/stats/ and tests/ only', () => {
const root = fixture({
'commands/a.md': 'node ${CLAUDE_PLUGIN_ROOT}/lib/stats/event-emit.mjs \\\n --event user_input \\\n',
'commands/b.md': 'the emitter knows user_input as an event name - prose, not a call\n',
'lib/util/x.mjs': "emitEvent('user_input', { slug });\n",
'lib/stats/event-emit.mjs': "emit('user_input', {});\n",
'tests/lib/y.test.mjs': "emit('user_input', {});\n",
'hooks/scripts/h.mjs': "spawnSync('node', [EMIT, '--event', 'user_input']);\n",
});
try {
const r = emitterCallSites(root);
assert.deepEqual(r.sites.map((s) => s.file).sort(), ['commands/a.md', 'hooks/scripts/h.mjs', 'lib/util/x.mjs']);
assert.equal(r.scanned, 4, 'commands/a.md, commands/b.md, lib/util/x.mjs, hooks/scripts/h.mjs');
} finally { cleanup(root); }
});
// --- 4 · the signature-preserving mutant (M9) ----------------------------------
const MODULE = 'export function verdict(code) { return { status: code === 0 ? "PASSED" : "FAILED" }; }\n';
const STRONG_TEST = [
"import { test } from 'node:test';",
"import { strict as assert } from 'node:assert';",
"import { verdict } from '../lib/m.mjs';",
"test('verdict fells a failing exit', () => { assert.equal(verdict(1).status, 'FAILED'); });",
'',
].join('\n');
const behaviourRegistry = {
defects: [{
id: 'D-X', probe: 'behaviour',
check: [{ test: 'tests/t.test.mjs', name: 'verdict fells a failing exit', expect: 'fails', stubs: ['lib/m.mjs'] }],
}],
experiments: [],
};
test('buildM9Tree: every export keeps its name and returns {status:"PASSED"}; every named test only checks typeof', async () => {
const root = fixture({ 'lib/m.mjs': MODULE, 'tests/t.test.mjs': STRONG_TEST });
const m9 = buildM9Tree(root, behaviourRegistry);
try {
const mod = readFileSync(join(m9, 'lib', 'm.mjs'), 'utf8');
assert.match(mod, /export function verdict\(\) \{ return \{ status: 'PASSED' \}; \}/);
const t = readFileSync(join(m9, 'tests', 't.test.mjs'), 'utf8');
assert.match(t, /verdict fells a failing exit/);
assert.match(t, /typeof/);
assert.doesNotMatch(t, /FAILED/, 'the mutant test asserts nothing about behaviour');
assert.equal(readFileSync(join(root, 'lib', 'm.mjs'), 'utf8'), MODULE, 'the measured tree is never touched');
} finally { cleanup(root, m9); }
});
test('mutants: a gate that CLOSES the probe on M9 has felled 0 of 1', () => {
const root = fixture({ 'lib/m.mjs': MODULE, 'tests/t.test.mjs': STRONG_TEST });
try {
const row = measureMutants(root, {
registry: behaviourRegistry,
evaluate: () => ({ status: 'closed', detail: '' }),
runTest: () => true,
});
assert.equal(row.countable, true);
assert.equal(row.value, 0);
assert.equal(row.denominator, 1);
assert.match(row.detail, /D-X closed/);
} finally { cleanup(root); }
});
test('mutants: a gate that refuses to close the probe on M9 has felled 1 of 1', () => {
const root = fixture({ 'lib/m.mjs': MODULE, 'tests/t.test.mjs': STRONG_TEST });
try {
const row = measureMutants(root, {
registry: behaviourRegistry,
evaluate: () => ({ status: 'not-fellable', detail: 'still passes against a signature-preserving mutant' }),
runTest: () => true,
});
assert.equal(row.value, 1);
assert.equal(row.denominator, 1);
} finally { cleanup(root); }
});
test('mutants: a mutant whose own tests do not pass is not LIVE, so the row cannot be counted', () => {
// Without this control a broken fixture would read as "felled".
const root = fixture({ 'lib/m.mjs': MODULE, 'tests/t.test.mjs': STRONG_TEST });
try {
const row = measureMutants(root, {
registry: behaviourRegistry,
evaluate: () => ({ status: 'not-fellable', detail: 'x' }),
runTest: () => null,
});
assert.equal(row.countable, false);
assert.equal(row.value, null);
assert.match(row.detail, /not live/);
} finally { cleanup(root); }
});
test('mutants: against the REAL gate and registry, M9 is live and the denominator is 1', () => {
// Pins the measurement's shape, not today's value: M9's typeof-only tests
// really do pass on the M9 tree (so "felled" can only come from the gate).
const row = measureMutants(ROOT);
assert.equal(row.countable, true, row.detail);
assert.equal(row.denominator, 1);
assert.ok(row.value === 0 || row.value === 1);
assert.deepEqual(row.facts.entries.sort(), ['D-03', 'D-04']);
});
// --- the whole yardstick -------------------------------------------------------
function world({ orders = {}, stats = {} } = {}) {
const coord = fixture(Object.keys(orders).length ? orders : { 'r/orders/.keep': '' });
const data = fixture(Object.keys(stats).length ? stats : { '.keep': '' });
return { coord, data };
}
test('measureAll + main: RED with exit 1 while any number is not countable', () => {
const { coord, data } = world({
orders: { 'r/orders/o.md': order({ id: 'o', date: '2026-09-22T00:00:00Z' }) },
stats: { 'trekreview-stats.jsonl': jsonl(review('2026-09-01T00:00:00Z', 'ALLOW')) },
});
try {
const result = measureAll({ root: ROOT, coordDir: coord, dataDir: data, cutoff: DEFAULT_CUTOFF });
assert.equal(result.green, false);
assert.equal(result.countable, 1);
const text = render(result);
assert.match(text, /1 of 3 numbers countable/);
assert.match(text, /signature-preserving mutants felled: \d of 1/);
assert.match(text, /verdict: NOT JUDGED/);
for (const id of ['use', 'trust', 'interrupts', 'mutants']) assert.match(text, new RegExp(`\\| ${id} \\|`));
assert.equal(main(['--root', ROOT, '--coord', coord, '--data', data, '--json']), 1);
} finally { cleanup(coord, data); }
});
test('measureAll: all three countable and the mutant felled is still RED until the verdict can be judged', () => {
const { coord, data } = world({
orders: { 'r/orders/o.md': order({ id: 'o', date: '2026-09-29T00:00:00Z', marker: 'plan' }) },
stats: {
'trekbrief-stats.jsonl': jsonl(briefRun({ order_id: 'o', slug: 'a' })),
'trekreview-stats.jsonl': jsonl(review('2026-09-01T00:00:00Z', 'ALLOW', 'a')),
'trekexecute-stats.jsonl': jsonl({ ts: 't', event: 'user_input', payload: { slug: 'a' } }),
},
});
try {
const result = measureAll({
root: ROOT, coordDir: coord, dataDir: data, cutoff: DEFAULT_CUTOFF, countingSince: MARKER_SINCE,
mutantOptions: { evaluate: () => ({ status: 'not-fellable', detail: '' }) },
});
assert.equal(result.countable, 3);
assert.equal(result.rows.find((r) => r.id === 'mutants').value, 1);
assert.equal(result.verdict.judged, false);
assert.equal(result.green, false);
} finally { cleanup(coord, data); }
});
test('main: an unknown argument or a malformed cutoff is a usage error (exit 2)', () => {
assert.equal(main(['--nope']), 2);
assert.equal(main(['--cutoff', '21.09.2026']), 2);
});
test('measureAll: without countingSince it uses USE_COUNTING_SINCE, whatever its value', () => {
assert.ok('USE_COUNTING_SINCE' in Y, 'scripts/yardstick.mjs exports USE_COUNTING_SINCE');
const { coord, data } = world({
orders: { 'r/orders/o.md': order({ id: 'o', date: '2026-10-29T00:00:00Z', marker: 'plan' }) },
stats: { 'trekbrief-stats.jsonl': jsonl(briefRun({ order_id: 'o' })) },
});
try {
const all = measureAll({ root: ROOT, coordDir: coord, dataDir: data, cutoff: DEFAULT_CUTOFF,
mutantOptions: { evaluate: () => ({ status: 'not-fellable', detail: '' }) } });
const direct = measureUse({ queue: readOrders(coord), runs: Y.orderRuns(loadStats(data)), cutoff: DEFAULT_CUTOFF,
countingSince: Y.USE_COUNTING_SINCE });
assert.deepEqual(all.rows.find((r) => r.id === 'use'), direct);
} finally { cleanup(coord, data); }
});
test('main: the CLI prints its result when run through a symlink', () => {
const { coord, data } = world();
const links = mkdtempSync(join(tmpdir(), 'yardstick-link-'));
try {
const link = join(links, 'yardstick.mjs');
symlinkSync(join(ROOT, 'scripts', 'yardstick.mjs'), link);
const r = spawnSync(process.execPath, [link, '--coord', coord, '--data', data, '--json'], { encoding: 'utf8', timeout: 120000 });
assert.ok(r.stdout.trim().length > 0, `no output through a symlink (exit ${r.status})`);
assert.ok(Array.isArray(JSON.parse(r.stdout).rows));
} finally { cleanup(coord, data, links); }
});