Regions, competing candidates, five "same" merge, checks compile locally

- Agents list regions (source files or classes: open, done, in flight,
  who claimed them), claim one as a whole and submit it in one batch.
- Several agents may claim a region; each may submit any function of it.
  Candidates are verified and reviewed on their own; the first accepted
  one merges and the others are superseded, the rest of their batches
  goes on. A done task stays done (trigger).
- Peer review: five "same" accept (no human step), three "different"
  send back.
- The server no longer compiles checks (remoteChecks, off by default);
  approved accounts download the compiler package for local checks.
- Tables for game credits and rounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Saty 2026-10-20 02:32:20 +02:00
commit 10f840b18f
8 changed files with 488 additions and 75 deletions

View file

@ -20,7 +20,7 @@ const quiet = { info() {}, error() {}, warn() {} };
before(async () => {
dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'td-test-'));
fs.writeFileSync(path.join(dataDir, 'server.json'), JSON.stringify({ listen: { host: '127.0.0.1', port: 0 }, verifyConcurrency: 1 }));
fs.writeFileSync(path.join(dataDir, 'server.json'), JSON.stringify({ listen: { host: '127.0.0.1', port: 0 }, verifyConcurrency: 1, remoteChecks: true }));
const repoDir = path.join(dataDir, 'repo');
fs.cpSync(path.join(ROOT, 'template'), repoDir, { recursive: true });
const git = (...a) => execFileSync('git', a, { cwd: repoDir, stdio: 'pipe' });
@ -297,12 +297,14 @@ test('changing the password logs out browser sessions', async () => {
await login('erin', 'a brand new password');
});
test('peer review: three other agents must agree, by reading only', async () => {
test('peer review: five "same" accept, three "different" send back, by reading only', async () => {
const author = await activeUser('pauthor');
const r1 = await activeUser('peer1');
const r2 = await activeUser('peer2');
const r3 = await activeUser('peer3');
const r4 = await activeUser('peer4');
const r5 = await activeUser('peer5');
const r6 = await activeUser('peer6');
ctx.merger.pump = async () => {};
const authorId = ctx.accounts.byName('pauthor').id;
@ -319,23 +321,25 @@ test('peer review: three other agents must agree, by reading only', async () =>
assert.ok(!(await call('GET', '/api/peer-reviews', null, author)).body.some((x) => x.attempt_id === attempt), 'authors do not see their own attempts');
const claim = await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r1);
assert.equal(claim.status, 200);
assert.equal(claim.body.required, 3);
assert.equal(claim.body.required, 5);
assert.equal(claim.body.rejectAt, 3);
assert.ok(claim.body.instructions.some((i) => /Do not compile/.test(i)));
assert.equal(JSON.stringify(claim.body).includes('diffRegions'), false, 'no machine verdict in the review context');
assert.equal(claim.body.original.read[0], `td_disassemble ${task.symbol_id}`);
await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r2);
await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r3);
assert.equal((await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r4)).status, 409, 'no more reviewers than needed');
for (const r of [r2, r3, r4, r5]) await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r);
assert.equal((await call('POST', '/api/peer-reviews/claim', { attemptId: attempt }, r6)).status, 409, 'no more reviewers than needed');
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'short' }, r1)).status, 400);
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'all branches and calls agree' }, author)).status, 403);
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'all branches and calls agree' }, r1)).body.state, 'peer_review');
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'same loop bounds and the same return' }, r1)).status, 409, 'one verdict per account');
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'checked every condition and field access' }, r2)).body.state, 'peer_review');
const done = await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'identical behavior, only register use differs' }, r3);
assert.equal(done.body.state, 'in_review');
assert.equal(ctx.tasks.get(task.id).state, 'in_review');
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'identical behavior, only register use differs' }, r3)).body.state, 'peer_review', 'three are not enough to accept');
assert.equal((await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'same calls in the same order, same result' }, r4)).body.state, 'peer_review');
const done = await call('POST', `/api/peer-reviews/${attempt}/verdict`, { verdict: 'same', reason: 'same fields read and written, same return' }, r5);
assert.equal(done.body.state, 'approved', 'five accept it, with no human step');
assert.equal(ctx.tasks.get(task.id).state, 'approved');
assert.ok(ctx.peers.confirmed(attempt));
// One "different" is not enough: it stays in review until three agree, here after a mixed round.
@ -436,16 +440,16 @@ test('five agreeing peers accept a function without human review, also over an o
const clean = make(0x401900);
for (let i = 0; i < 3; i++) await review(clean.attempt, peers[i], 'same');
assert.equal(ctx.store.get('SELECT state FROM attempts WHERE id = ?', clean.attempt).state, 'in_review', 'three send it to a human');
assert.equal((await review(clean.attempt, peers[3], 'same')).state, 'in_review', 'it stays open for more reviewers');
assert.equal(ctx.store.get('SELECT state FROM attempts WHERE id = ?', clean.attempt).state, 'peer_review', 'three are not enough');
assert.equal((await review(clean.attempt, peers[3], 'same')).state, 'peer_review', 'it stays open for more reviewers');
assert.equal((await review(clean.attempt, peers[4], 'same')).state, 'approved', 'five accept it');
assert.equal(ctx.store.get('SELECT state FROM tasks WHERE id = ?', clean.task).state, 'approved');
const contested = make(0x401940);
await review(contested.attempt, peers[0], 'different');
for (let i = 1; i <= 3; i++) await review(contested.attempt, peers[i], 'same');
assert.equal(ctx.store.get('SELECT state FROM attempts WHERE id = ?', contested.attempt).state, 'in_review');
assert.equal((await review(contested.attempt, peers[4], 'same')).state, 'in_review');
assert.equal(ctx.store.get('SELECT state FROM attempts WHERE id = ?', contested.attempt).state, 'peer_review');
assert.equal((await review(contested.attempt, peers[4], 'same')).state, 'peer_review');
assert.equal((await review(contested.attempt, peers[5], 'same')).state, 'approved', 'five "same" accept it over one objection (flagged for later at merge)');
for (const x of [clean, contested]) {
@ -623,7 +627,7 @@ test('the review list skips fully leased functions before applying its limit', a
const author = ctx.accounts.byName('rlauthor');
const viewer = ctx.accounts.byName('rlviewer');
const others = [];
for (let i = 1; i <= 3; i++) {
for (let i = 1; i <= 5; i++) {
await activeUser(`rlpeer${i}`);
others.push(ctx.accounts.byName(`rlpeer${i}`));
}
@ -639,7 +643,7 @@ test('the review list skips fully leased functions before applying its limit', a
const free = make(0x410040);
for (const o of others) ctx.store.run('INSERT INTO peer_leases (attempt_id, reviewer_id, expires_at) VALUES (?, ?, ?)', full.attempt, o.id, now() + 3600_000);
const ids = ctx.peers.available(viewer, 200).map((r) => r.attempt_id);
assert.ok(!ids.includes(full.attempt), 'three reviewers on it already');
assert.ok(!ids.includes(full.attempt), 'five reviewers on it already');
assert.ok(ids.includes(free.attempt));
for (const x of [full, free]) {
ctx.store.run('DELETE FROM peer_leases WHERE attempt_id = ?', x.attempt);
@ -872,7 +876,8 @@ test('approving a batch leaves its functions in peer review alone unless asked',
test('split: the approved part of a batch merges while the rest waits for review', async () => {
const author = await activeUser('sauthor');
const peers = [await activeUser('speer1'), await activeUser('speer2'), await activeUser('speer3')];
const peers = [];
for (let i = 1; i <= 5; i++) peers.push(await activeUser(`speer${i}`));
await ctx.accounts.createUser('sreviewer', 'reviewer', PASSWORD);
const reviewer = await login('sreviewer');
delete ctx.merger.pump;
@ -917,13 +922,14 @@ test('split: the approved part of a batch merges while the rest waits for review
assert.equal(rest.base_commit, head1);
assert.equal(JSON.parse(rest.files_json)['src/split.cpp'], source);
// D passes review later and merges on top.
// D passes review later (five "same", no human step) and merges on top.
const att = (await batchState(s.body.batchId)).functions.find((f) => f.symbol === d).attemptId;
for (const t of peers) {
await call('POST', '/api/peer-reviews/claim', { attemptId: att }, t);
await call('POST', `/api/peer-reviews/${att}/verdict`, { verdict: 'same', reason: 'same branches and return values' }, t);
}
assert.equal((await request('POST', `/api/batches/${s.body.batchId}/review`, { action: 'approve' }, { cookie: reviewer })).status, 200);
assert.equal(ctx.store.get('SELECT state FROM attempts WHERE id = ?', att).state, 'approved');
void reviewer;
await ctx.merger.pump();
assert.equal(ctx.store.get('SELECT state FROM batches WHERE id = ?', s.body.batchId).state, 'merged');
assert.equal(ctx.repo.show(ctx.repo.head(), 'src/split.cpp'), source);
@ -933,7 +939,8 @@ test('split: the approved part of a batch merges while the rest waits for review
test('batches: one compile, auto-approval, peer review, one function sent back, carry-over', async () => {
const author = await activeUser('bauthor');
const peers = [await activeUser('bpeer1'), await activeUser('bpeer2'), await activeUser('bpeer3')];
const peers = [];
for (let i = 1; i <= 5; i++) peers.push(await activeUser(`bpeer${i}`));
await ctx.accounts.createUser('breviewer', 'reviewer', PASSWORD);
const reviewer = await login('breviewer');
delete ctx.merger.pump; // an earlier test stubbed it on the instance; use the real one here
@ -982,7 +989,7 @@ test('batches: one compile, auto-approval, peer review, one function sent back,
// Round 1: a peer claim covers the batch's waiting functions; all three find a difference.
const pc = await call('POST', '/api/peer-reviews/claim', { attemptId: r1[b].attemptId }, peers[0]);
assert.deepEqual(pc.body.functions.map((f) => f.symbol), [b]);
for (const t of peers) {
for (const t of peers.slice(0, 3)) {
await call('POST', '/api/peer-reviews/claim', { attemptId: r1[b].attemptId }, t);
await call('POST', `/api/peer-reviews/${r1[b].attemptId}/verdict`, { verdict: 'different', reason: 'the original checks the flag first, this does not' }, t);
}
@ -995,9 +1002,9 @@ test('batches: one compile, auto-approval, peer review, one function sent back,
assert.equal(ctx.store.get('SELECT state FROM tasks WHERE symbol_id = ?', a).state, 'done');
assert.equal((await batchState(s1.body.batchId)).state, 'returned');
// Round 2: the author fixes B (new fingerprint) and resubmits it; three peers confirm.
// Round 2: the author fixes B (new fingerprint) and resubmits it; five peers confirm.
bHash = 'hash-b-2';
const objector = await activeUser('bpeer4');
const objector = await activeUser('bpeer6');
const taskOfB = claim.body.tasks.find((t) => t.symbol === b).task;
assert.equal((await call('POST', '/api/tasks/claim', { taskId: taskOfB }, author)).status, 200);
const s2 = await call('POST', '/api/batches', { taskIds: [taskOfB], baseCommit: ctx.repo.head(), files: { 'src/batch.cpp': source } }, author);
@ -1009,11 +1016,8 @@ test('batches: one compile, auto-approval, peer review, one function sent back,
await call('POST', '/api/peer-reviews/claim', { attemptId: r2[b].attemptId }, t);
await call('POST', `/api/peer-reviews/${r2[b].attemptId}/verdict`, { verdict: 'same', reason: 'now checks the flag first like the original' }, t);
}
assert.equal((await batchState(s2.body.batchId)).functions.find((f) => f.symbol === b).state, 'in_review');
// One human click for the batch; one merge commit.
const rev = await request('POST', `/api/batches/${s2.body.batchId}/review`, { action: 'approve' }, { cookie: reviewer });
assert.equal(rev.status, 200, JSON.stringify(rev.body));
assert.equal((await batchState(s2.body.batchId)).functions.find((f) => f.symbol === b).state, 'approved', 'five "same" accept it over one objection');
void reviewer;
// Nothing on main changed since verification: the merge reuses that compile.
let compiles = 0;
const counted = ctx.verifier.check;
@ -1041,3 +1045,77 @@ test('batches: one compile, auto-approval, peer review, one function sent back,
ctx.verifier.check = realCheck;
});
test('regions: two agents claim one file, the first accepted candidate merges, the other is superseded', async () => {
const first = await activeUser('rgfirst');
const second = await activeUser('rgsecond');
delete ctx.merger.pump;
const v = ctx.store.currentVersion();
const e = ctx.store.ensureSymbol({ kind: 'function', versionId: v.id, addr: 0x402700, size: 8, unit: 'src/region.cpp' }).symbol.id;
const f = ctx.store.ensureSymbol({ kind: 'function', versionId: v.id, addr: 0x402740, size: 8, unit: 'src/region.cpp' }).symbol.id;
ctx.tasks.generate();
// Stubbed compiler: whoever's file has "return 7" in fe matches; fe of the other candidate does not.
const realCheck = ctx.verifier.check;
ctx.verifier.check = async (files) => {
const text = files['src/region.cpp'] ?? '';
const functions = [];
if (text.includes('int fe()')) functions.push({ id: e, status: text.includes('return 7') ? STATUS.EXACT : STATUS.MISMATCH, score: text.includes('return 7') ? 1 : 0.8, file: 'src/region.cpp', codeHash: text.includes('return 7') ? 'e-good' : 'e-other', relocations: [], size: { ours: 8, original: 8 } });
if (text.includes('int ff()')) functions.push({ id: f, status: STATUS.MISMATCH, score: 0.9, file: 'src/region.cpp', codeHash: 'f-1', relocations: [], size: { ours: 8, original: 8 } });
return { check: { annotationErrors: [], units: [{ file: 'src/region.cpp', compiled: true, lintErrors: [], unannotated: [], bindings: {}, inferred: [], includes: [], errors: [], functions }] }, rec: { conflicts: [], unknown: [], learned: [], learnedAddresses: [] }, changedHeaders: [], units: ['src/region.cpp'] };
};
const list = (await call('GET', '/api/regions?prefix=src/region', null, first)).body;
const region = list.regions.find((r) => r.key === 'src/region.cpp');
assert.deepEqual([region.open, region.free], [2, true], 'unclaimed and open');
const c1 = await call('POST', '/api/regions/claim', { kind: 'unit', key: 'src/region.cpp' }, first);
assert.equal(c1.status, 200, JSON.stringify(c1.body));
assert.equal(c1.body.leased.length, 2, 'the whole region at once');
const c2 = await call('POST', '/api/regions/claim', { kind: 'unit', key: 'src/region.cpp' }, second);
assert.equal(c2.status, 200);
assert.deepEqual(c2.body.alsoClaimedBy, ['rgfirst']);
assert.ok(c2.body.functions.every((x) => x.shared), 'held by the first agent, shared with the second');
assert.equal((await call('GET', '/api/regions?prefix=src/region', null, first)).body.regions[0].free, false);
const taskOf = (sym) => c1.body.functions.find((x) => x.symbol === sym).taskId;
const head = ctx.repo.head();
const batchState = async (id, token) => (await call('GET', `/api/batches/${id}`, null, token)).body;
const settle = (id, token) => waitFor(async () => { const st = await batchState(id, token); return !['queued', 'verifying'].includes(st.state) && st; });
// The second agent's candidate of fe matches; the first agent's does not.
const s2 = await call('POST', '/api/batches', { taskIds: [taskOf(e)], baseCommit: head, files: { 'src/region.cpp': `// FUNCTION: ${e}\nint fe() { return 7; }\n` } }, second);
assert.equal(s2.status, 200, JSON.stringify(s2.body));
assert.equal(s2.body.attempts[0].competing, true);
assert.equal(ctx.tasks.get(taskOf(e)).state, 'leased', 'a competing candidate leaves the holder\'s lease alone');
const s1 = await call('POST', '/api/batches', { taskIds: [taskOf(e), taskOf(f)], baseCommit: head, files: { 'src/region.cpp': `// FUNCTION: ${e}\nint fe() { return 6; }\n\n// FUNCTION: ${f}\nint ff() { return 8; }\n` } }, first);
assert.equal(s1.status, 200, JSON.stringify(s1.body));
await settle(s2.body.batchId, second);
await settle(s1.body.batchId, first);
await ctx.merger.pump();
assert.equal((await batchState(s2.body.batchId, second)).state, 'merged');
assert.equal(ctx.tasks.get(taskOf(e)).state, 'done');
const loser = (await batchState(s1.body.batchId, first)).functions.find((x) => x.symbol === e);
assert.equal(loser.state, 'superseded', 'the other candidate of the merged function is not needed any more');
assert.equal((await batchState(s1.body.batchId, first)).functions.find((x) => x.symbol === f).state, 'peer_review', 'the rest of its batch goes on');
// A done function stays done whatever a late candidate does.
ctx.store.run(`UPDATE tasks SET state = 'needs_cleanup' WHERE id = ?`, taskOf(e));
assert.equal(ctx.tasks.get(taskOf(e)).state, 'done');
assert.equal((await call('POST', '/api/regions/release', { kind: 'unit', key: 'src/region.cpp' }, second)).status, 200);
ctx.store.run(`UPDATE attempts SET state = 'rejected' WHERE batch_id = ?`, s1.body.batchId);
ctx.store.run(`UPDATE tasks SET state = 'done' WHERE id = ?`, taskOf(f));
ctx.store.run('DELETE FROM region_claims');
ctx.verifier.check = realCheck;
});
test('the server does not compile checks unless remoteChecks is on', async () => {
const user = await activeUser('rcuser');
ctx.config.remoteChecks = false;
const r = await call('POST', '/api/check', { baseCommit: ctx.repo.head(), files: {} }, user);
assert.equal(r.status, 410);
assert.match(r.body.error, /td toolchain install/);
ctx.config.remoteChecks = true;
});