voyage/tests/lib/claimed-order.test.mjs
Kjell Tore Guttormsen e7ac34b93e
test(stats): the recorder finds the one claimed order Voyage runs (red)
20 tests for lib/stats/claimed-order.mjs (new): exactly one claimed order is
an attribution (stem id + the .claim sidecar's claimed-at); zero, several
(an unparseable file still counts), a to: naming another repo, a missing
coord dir or no git repo is null plus a reason - never a guess. Mailboxes
mirror coord-order-claim.sh (basename of the toplevel) plus the worktree's
main repo; _* is reserved; an inherited GIT_DIR and a project_dir outside
cwd cannot steer it.

Red: the module does not exist (20 of 20 fail, each on its own - the module
is loaded per test). Against a null stub in a scratch copy, 18 fail on
behaviour; 2 are guards green on arrival (13 _-prefixed mailbox never read,
14 the recorder only reads).

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

280 lines
13 KiB
JavaScript

// tests/lib/claimed-order.test.mjs
// The recorder that tells /trekbrief which coord-queue order it is running.
//
// It mirrors repo-mailbox's claim contract (coord root, mailbox = basename of the
// git toplevel, `_*` reserved, the claimed file's stem is the order id, a
// `<id>.claim` sidecar carries `claimed-at:`), and it must never guess: exactly
// one claimed order is an attribution, zero or several is `null` plus a reason.
// Every test builds its own coord dir and git repos; nothing reads the real
// queue. The module is loaded per test, so a missing module fails each test on
// its own instead of failing the file at link time.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readdirSync, statSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, dirname } from 'node:path';
import { spawnSync } from 'node:child_process';
const load = () => import('../../lib/stats/claimed-order.mjs');
// --- helpers ---------------------------------------------------------------
function fixture(files) {
const dir = mkdtempSync(join(tmpdir(), 'claimed-order-'));
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 }); };
function orderFile({ id, to, quoted = false }) {
const lines = ['---', 'from: .claude'];
if (to !== undefined) lines.push(`to: ${to}`);
lines.push(`order-id: ${quoted ? `"${id}"` : id}`, `subject: order ${id}`, 'date: 2026-10-01T10:00:00Z', '---', '', `# ORDER ${id}`, '');
return lines.join('\n');
}
const claimFile = (at) => `claimed-at: ${at}\nclaimed-by-pid: 1\n`;
// A claimed order in <mailbox>, with its sidecar unless `claim: false`.
function claimed(mailbox, id, { at = '2026-10-04T10:00:00Z', claim = true, to = mailbox } = {}) {
const files = { [`${mailbox}/orders/claimed/${id}.md`]: orderFile({ id, to }) };
if (claim) files[`${mailbox}/orders/claimed/${id}.claim`] = claimFile(at);
return files;
}
function git(cwd, ...args) {
const r = spawnSync('git', ['-c', 'user.email=t@example.invalid', '-c', 'user.name=t', ...args], { cwd, encoding: 'utf8' });
assert.equal(r.status, 0, `git ${args.join(' ')}: ${r.stderr}`);
return r.stdout.trim();
}
// A git repo whose directory is named `name`, with one commit (a worktree needs a HEAD).
function repo(name) {
const parent = mkdtempSync(join(tmpdir(), 'claimed-order-git-'));
const dir = join(parent, name);
mkdirSync(dir);
git(dir, 'init', '-q');
writeFileSync(join(dir, 'README'), 'x\n');
git(dir, 'add', 'README');
git(dir, 'commit', '-q', '-m', 'init');
return { parent, dir };
}
function snapshot(dir) {
const out = [];
const walk = (d) => {
for (const n of readdirSync(d).sort()) {
const p = join(d, n);
const s = statSync(p);
out.push(`${p} ${s.mtimeMs}`);
if (s.isDirectory()) walk(p);
}
};
walk(dir);
return out.join('\n');
}
// --- findClaimedOrder ----------------------------------------------------------
test('findClaimedOrder: exactly one claimed order gives its order id and its claimed-at', async () => {
const { findClaimedOrder } = await load();
const coord = fixture(claimed('mbx', 'o-1', { at: '2026-10-04T17:10:51Z' }));
try {
assert.deepEqual(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }),
{ order_id: 'o-1', order_claimed_at: '2026-10-04T17:10:51Z', order_reason: null });
} finally { cleanup(coord); }
});
test('findClaimedOrder: no claimed/ directory gives null and none-claimed, never a guess', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ 'mbx/orders/o-1.md': orderFile({ id: 'o-1', to: 'mbx' }) });
try {
assert.deepEqual(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }),
{ order_id: null, order_claimed_at: null, order_reason: 'none-claimed' });
} finally { cleanup(coord); }
});
test('findClaimedOrder: an empty claimed/ gives null and none-claimed', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ 'mbx/orders/claimed/.keep': '' });
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_reason, 'none-claimed');
} finally { cleanup(coord); }
});
test('findClaimedOrder: two claimed orders give null and several-claimed:2 - the older one is never picked', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ ...claimed('mbx', 'o-1', { at: '2026-10-01T00:00:00Z' }), ...claimed('mbx', 'o-2') });
try {
assert.deepEqual(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }),
{ order_id: null, order_claimed_at: null, order_reason: 'several-claimed:2' });
} finally { cleanup(coord); }
});
test('findClaimedOrder: an unparseable claimed .md still counts - "several" is never undercounted', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ ...claimed('mbx', 'o-1'), 'mbx/orders/claimed/o-2.md': 'no frontmatter at all\n' });
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_reason, 'several-claimed:2');
} finally { cleanup(coord); }
});
test('findClaimedOrder: the .claim sidecar and other non-.md files are not orders', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ ...claimed('mbx', 'o-1'), 'mbx/orders/claimed/notes.txt': 'x\n' });
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_id, 'o-1');
} finally { cleanup(coord); }
});
test('findClaimedOrder: pending orders/ and archive/ are not claimed', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({
'mbx/orders/o-1.md': orderFile({ id: 'o-1', to: 'mbx' }),
'mbx/orders/archive/o-2.md': orderFile({ id: 'o-2', to: 'mbx' }),
});
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_reason, 'none-claimed');
} finally { cleanup(coord); }
});
test("findClaimedOrder: another mailbox's claimed order is never ours", async () => {
const { findClaimedOrder } = await load();
const coord = fixture(claimed('other', 'o-1'));
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_reason, 'none-claimed');
} finally { cleanup(coord); }
});
test('findClaimedOrder: a missing coord dir gives null and coord-missing, without throwing', async () => {
const { findClaimedOrder } = await load();
const r = findClaimedOrder({ coordDir: join(tmpdir(), 'claimed-order-does-not-exist-'), mailboxes: ['mbx'] });
assert.deepEqual(r, { order_id: null, order_claimed_at: null, order_reason: 'coord-missing' });
});
test('findClaimedOrder: a claimed order without its .claim keeps the id, with no-claim-time', async () => {
const { findClaimedOrder } = await load();
const coord = fixture(claimed('mbx', 'o-1', { claim: false }));
try {
assert.deepEqual(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }),
{ order_id: 'o-1', order_claimed_at: null, order_reason: 'no-claim-time' });
} finally { cleanup(coord); }
});
test('findClaimedOrder: a to: that names another repo is to-mismatch; a missing to: is accepted', async () => {
const { findClaimedOrder } = await load();
const wrong = fixture(claimed('mbx', 'o-1', { to: 'elsewhere' }));
const none = fixture(claimed('mbx', 'o-2', { to: undefined }));
try {
assert.deepEqual(findClaimedOrder({ coordDir: wrong, mailboxes: ['mbx'] }),
{ order_id: null, order_claimed_at: null, order_reason: 'to-mismatch' });
assert.equal(findClaimedOrder({ coordDir: none, mailboxes: ['mbx'] }).order_id, 'o-2');
} finally { cleanup(wrong, none); }
});
test('findClaimedOrder: the id is the file stem, also when the frontmatter quotes order-id', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({
'mbx/orders/claimed/o-1.md': orderFile({ id: 'o-1', to: 'mbx', quoted: true }),
'mbx/orders/claimed/o-1.claim': claimFile('2026-10-04T10:00:00Z'),
});
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] }).order_id, 'o-1');
} finally { cleanup(coord); }
});
test('findClaimedOrder: a _-prefixed mailbox is never read (the claim script reserves the namespace)', async () => {
const { findClaimedOrder } = await load();
const coord = fixture(claimed('_retired', 'o-1'));
try {
assert.equal(findClaimedOrder({ coordDir: coord, mailboxes: ['_retired'] }).order_id, null);
} finally { cleanup(coord); }
});
test('findClaimedOrder: it only reads - the coord dir is identical before and after', async () => {
const { findClaimedOrder } = await load();
const coord = fixture({ ...claimed('mbx', 'o-1'), ...claimed('other', 'o-2') });
try {
const before = snapshot(coord);
findClaimedOrder({ coordDir: coord, mailboxes: ['mbx', 'other'] });
findClaimedOrder({ coordDir: coord, mailboxes: ['mbx'] });
assert.equal(snapshot(coord), before);
} finally { cleanup(coord); }
});
test('findClaimedOrder: one claimed order across two mailbox names is found; one in each is several', async () => {
const { findClaimedOrder } = await load();
const one = fixture(claimed('main-repo', 'o-1'));
const two = fixture({ ...claimed('main-repo', 'o-1'), ...claimed('wt-name', 'o-2') });
try {
assert.equal(findClaimedOrder({ coordDir: one, mailboxes: ['wt-name', 'main-repo'] }).order_id, 'o-1');
assert.equal(findClaimedOrder({ coordDir: two, mailboxes: ['wt-name', 'main-repo'] }).order_reason, 'several-claimed:2');
} finally { cleanup(one, two); }
});
// --- resolveCoordDir -------------------------------------------------------------
test('resolveCoordDir: CLAUDE_COORD_DIR wins, else HOME/.claude/coord from the given env', async () => {
const { resolveCoordDir } = await load();
assert.equal(resolveCoordDir({ CLAUDE_COORD_DIR: '/x/coord', HOME: '/h' }), '/x/coord');
assert.equal(resolveCoordDir({ HOME: '/h' }), join('/h', '.claude', 'coord'));
assert.equal(resolveCoordDir({ CLAUDE_COORD_DIR: '', HOME: '/h' }), join('/h', '.claude', 'coord'));
});
// --- resolveMailboxes ------------------------------------------------------------
test('resolveMailboxes: a repo gives its basename; a worktree gives its own and the main repo name; outside git gives []', async () => {
const { resolveMailboxes } = await load();
const main = repo('main-repo');
const outside = mkdtempSync(join(tmpdir(), 'claimed-order-nogit-'));
try {
assert.deepEqual(resolveMailboxes(main.dir, { env: {} }), ['main-repo']);
const wt = join(main.parent, 'wt-name');
git(main.dir, 'worktree', 'add', '-q', '-b', 'wt-branch', wt);
assert.deepEqual([...resolveMailboxes(wt, { env: {} })].sort(), ['main-repo', 'wt-name']);
assert.deepEqual(resolveMailboxes(outside, { env: {} }), []);
} finally { cleanup(main.parent, outside); }
});
test('resolveMailboxes: an inherited GIT_DIR pointing at another repo is ignored', async () => {
const { resolveMailboxes } = await load();
const mine = repo('mine');
const theirs = repo('theirs');
try {
const env = { GIT_DIR: join(theirs.dir, '.git'), GIT_WORK_TREE: theirs.dir };
assert.deepEqual(resolveMailboxes(mine.dir, { env }), ['mine']);
} finally { cleanup(mine.parent, theirs.parent); }
});
// --- attributeOrder --------------------------------------------------------------
test('attributeOrder: outside git the mailbox is unresolved - null, never a guess', async () => {
const { attributeOrder } = await load();
const outside = mkdtempSync(join(tmpdir(), 'claimed-order-nogit-'));
const coord = fixture(claimed('mbx', 'o-1'));
try {
assert.deepEqual(attributeOrder({ cwd: outside, env: { CLAUDE_COORD_DIR: coord, HOME: outside } }),
{ order_id: null, order_claimed_at: null, order_reason: 'mailbox-unresolved' });
} finally { cleanup(outside, coord); }
});
test('attributeOrder: finds the claimed order of the cwd repo; a projectDir outside cwd cannot steer it elsewhere', async () => {
const { attributeOrder } = await load();
const a = repo('repo-a');
const b = repo('repo-b');
const coord = fixture(claimed('repo-b', 'o-1'));
try {
const env = { CLAUDE_COORD_DIR: coord, HOME: a.parent };
// Positive control: the fixture is findable from repo-b itself.
assert.equal(attributeOrder({ cwd: b.dir, env }).order_id, 'o-1');
// From repo-a, a project_dir that walks out of cwd into repo-b is ignored.
assert.equal(attributeOrder({ cwd: a.dir, env, projectDir: b.dir }).order_reason, 'none-claimed');
assert.equal(attributeOrder({ cwd: a.dir, env, projectDir: '../../' + b.parent.split('/').pop() + '/repo-b' }).order_reason, 'none-claimed');
} finally { cleanup(a.parent, b.parent, coord); }
});