/trekreview of e7ac34b..3f073b7 (WARN, 1 MAJOR, finding 986c939f93808a274b5e4ecd2c5318fd422a3be4): baseDir's accepting branch was never exercised, though every production /trekbrief record carries project_dir. One unit test (attributeOrder from a non-git parent with projectDir inside it) and one end-to-end landing test (the Phase 7 line with a record carrying project_dir). Both pass on HEAD and both fail on the always-cwd mutant (measured, then reverted). Suite 1364 (1362/0/2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
294 lines
14 KiB
JavaScript
294 lines
14 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); }
|
|
});
|
|
|
|
test('attributeOrder: a projectDir inside cwd moves the lookup to the repo that holds it', async () => {
|
|
const { attributeOrder } = await load();
|
|
const m = repo('mbx');
|
|
const coord = fixture(claimed('mbx', 'o-1'));
|
|
try {
|
|
mkdirSync(join(m.dir, '.claude', 'projects', 'x'), { recursive: true });
|
|
const env = { CLAUDE_COORD_DIR: coord, HOME: m.parent };
|
|
// Control: cwd (the repo's parent) is outside git, so without projectDir there is no mailbox.
|
|
assert.equal(attributeOrder({ cwd: m.parent, env }).order_reason, 'mailbox-unresolved');
|
|
assert.deepEqual(attributeOrder({ cwd: m.parent, env, projectDir: 'mbx/.claude/projects/x' }),
|
|
{ order_id: 'o-1', order_claimed_at: '2026-10-04T10:00:00Z', order_reason: null });
|
|
} finally { cleanup(m.parent, coord); }
|
|
});
|