Files
stack/agents/filbert/work/queue-57/out/mutants/run.mjs
T

65 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Filbert's row 57 mutants: each edits one file in the mutant worktree, runs
// the bus and webui suites, and restores the file. Usage: node run.mjs <worktree>
import { readFileSync, writeFileSync, appendFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';
import { join } from 'node:path';
const W = process.argv[2];
const OUT = new URL('.', import.meta.url).pathname;
const B = 'packages/bus/src/broker.mjs';
const S = 'packages/webui/src/serve.mjs';
const V = 'packages/bus/src/views.mjs';
const mutants = [
['role-allowed', B, "if (!s.human && !s.reader) fail('human-required');", ''],
['roles-with-human', B, "AND route_to<>'human' AND", 'AND'],
['roles-with-closed', B, ` AND NOT EXISTS(SELECT 1 FROM decision_events x WHERE x.decision=d.id AND x.op IN \${CLOSED}) ORDER BY seq`, ' ORDER BY seq'],
['roles-other-business', B, "WHERE business=? AND route_to<>'human'", "WHERE ? IS NOT NULL AND route_to<>'human'"],
['recent-other-business', B, 'WHERE d.business=? ORDER BY x.seq DESC', 'WHERE ? IS NOT NULL ORDER BY x.seq DESC'],
['recent-oldest-first', B, 'ORDER BY x.seq DESC LIMIT', 'ORDER BY x.seq ASC LIMIT'],
['recent-by-raise', B, 'ORDER BY x.seq DESC LIMIT', 'ORDER BY d.seq DESC LIMIT'],
['recent-no-limit', B, ' LIMIT ${RECENT}`', '`'],
['recent-limit-plus-one', B, ' LIMIT ${RECENT}`', ' LIMIT ${RECENT + 1}`'],
['recent-resolved-only', B, `JOIN decision_events x ON x.decision=d.id AND x.op IN \${CLOSED}`, `JOIN decision_events x ON x.decision=d.id AND x.op IN ('resolved')`],
['recent-no-closed', B, '({ ...this.#decisionView(d), closed: this.#closed(d.id) })', '({ ...this.#decisionView(d) })'],
['loose-keys', B, "keys(a, ['list'], ['list']);\n if (a.list === 'roles')", "keys(a, ['list', 'limit'], ['list']);\n if (a.list === 'roles')"],
['unknown-list-empty', B, " .map((d) => ({ ...this.#decisionView(d), closed: this.#closed(d.id) }));\n fail('invalid-request');", " .map((d) => ({ ...this.#decisionView(d), closed: this.#closed(d.id) }));\n return [];"],
['reader-refused', B, "'trail', 'decisions'].includes(request.verb))", "'trail'].includes(request.verb))"],
['web-no-list-check', S, "if (!DECISION_LISTS.includes(arg)) return", 'if (false) return'],
['web-no-verb', S, "const BUS_VERBS = ['inbox', 'tasks', 'agents', 'trail', 'decisions'];", "const BUS_VERBS = ['inbox', 'tasks', 'agents', 'trail'];"],
['views-fixed-list', V, "decisions: (list) => client.call('decisions', { list }),", "decisions: () => client.call('decisions', { list: 'roles' }),"],
];
const suites = [
['bus', ['--test', 'packages/bus/tests/*.test.mjs'], W],
['webui', ['--test', 'tests/'], join(W, 'packages/webui')],
];
const env = { ...process.env, TMPDIR: process.env.HOME + '/filbert-scratch/tmp', DOCKER_HOST: 'unix:///nonexistent.sock' };
const log = join(OUT, process.argv[4] || 'result.txt');
writeFileSync(log, '');
const only = process.argv[3] ? process.argv[3].split(',') : null;
for (const [name, file, from, to] of mutants) {
if (only && !only.includes(name)) continue;
const path = join(W, file);
const orig = readFileSync(path, 'utf8');
if (orig.split(from).length !== 2) {
appendFileSync(log, `${name}: PATTERN NOT UNIQUE\n`);
continue;
}
writeFileSync(path, orig.replace(from, to));
const parts = [];
try {
for (const [label, args, cwd] of suites) {
const r = spawnSync('node', args, { cwd, env, encoding: 'utf8', timeout: 600000 });
const out = r.stdout + r.stderr;
writeFileSync(join(OUT, `${name}.${label}.log`), out);
const fail = (out.match(/^ℹ fail (\d+)/m) || [])[1];
const fails = [...out.matchAll(/^\s*✖ (.+?) \(\d/gm)].map((m) => m[1]).filter((t) => !/^tests?\//.test(t));
parts.push(`${label} rc=${r.status} fail=${fail} ${[...new Set(fails)].slice(0, 4).join(' | ')}`);
}
} finally {
writeFileSync(path, orig);
}
appendFileSync(log, `${name}: ${parts.join(' ; ')}\n`);
}
appendFileSync(log, 'done\n');