From aa55f6e61cc5dea04e2fdc03c57a8dc7d5fb935d Mon Sep 17 00:00:00 2001 From: Saty <5752427+SatyPardus@users.noreply.github.com> Date: Sun, 25 Oct 2026 18:14:46 +0100 Subject: [PATCH] Region claims count toward the reviews a long queue asks for The "review first" rule counted only task claims, but new work is claimed by region, so after three reviews an hour an agent could claim any number of regions while the review queue kept growing. Co-Authored-By: Claude Opus 5.5 --- src/server/app.js | 2 +- test/server.test.js | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/server/app.js b/src/server/app.js index 6da5d83..5f07b2e 100644 --- a/src/server/app.js +++ b/src/server/app.js @@ -393,7 +393,7 @@ export function createApp(ctx) { // several times in a row. const per = config.reviewsPerClaim ?? 3; const since = Date.now() - 3600_000; - const claims = store.get(`SELECT COUNT(*) AS n FROM events WHERE user_id = ? AND type IN ('claim', 'claim_batch') AND at > ?`, user.id, since).n; + const claims = store.get(`SELECT COUNT(*) AS n FROM events WHERE user_id = ? AND type IN ('claim', 'claim_batch', 'region_claim') AND at > ?`, user.id, since).n; const done = store.get('SELECT COUNT(*) AS n FROM peer_reviews WHERE reviewer_id = ? AND created_at > ?', user.id, since).n; const need = Math.min(per, (claims + 1) * per - done); if (need <= 0) return; diff --git a/test/server.test.js b/test/server.test.js index a10a9f4..66478da 100644 --- a/test/server.test.js +++ b/test/server.test.js @@ -629,6 +629,27 @@ test('a long review queue makes new claims wait for a few peer reviews', async ( } }); +test('region claims count toward the reviews a long queue asks for', async () => { + await activeUser('rcauthor'); + const author = ctx.accounts.byName('rcauthor'); + const token = await activeUser('rcworker'); + const worker = ctx.accounts.userByApiToken(token); + const saved = ctx.store.get(`SELECT id, state FROM tasks WHERE state != 'done' ORDER BY id LIMIT 1`); + const attempts = [0, 1, 2, 3].map(() => Number(ctx.store.run(`INSERT INTO attempts (task_id, user_id, base_commit, files_json, state, created_at) VALUES (?, ?, ?, '{}', 'peer_review', ?)`, saved.id, author.id, ctx.repo.head(), now()).lastInsertRowid)); + const before = ctx.config.peerReviewFirstAt; + ctx.config.peerReviewFirstAt = 0; + try { + for (const a of attempts.slice(0, 3)) ctx.peers.submit(worker, a, 'same', 'the same branches and calls as the original', null); + ctx.store.event('region_claim', worker.id, { kind: 'unit', key: 'src/rc.cpp', leased: 5, shared: 0 }); + const r = await call('POST', '/api/regions/claim', {}, token); + assert.equal(r.status, 429, 'three reviews paid for the region already claimed, not for the next one'); + } finally { + ctx.config.peerReviewFirstAt = before; + ctx.store.run(`UPDATE attempts SET state = 'superseded' WHERE id IN (${attempts.join(',')})`); + ctx.store.run('UPDATE tasks SET state = ? WHERE id = ?', saved.state, saved.id); + } +}); + test('the review list skips fully leased functions before applying its limit', async () => { await activeUser('rlauthor'); await activeUser('rlviewer');