Reject local review model drift

This commit is contained in:
Claude
2026-08-21 19:49:45 -04:00
parent c648a5a6da
commit 6478ce2bfa
2 changed files with 37 additions and 0 deletions
+12
View File
@@ -105,6 +105,7 @@ export async function runReview({ cfg, gitea, adminGitea, db, job, withGlobal, l
tenantId: cfg.tenantId, timeoutMs: cfg.routerTimeoutMs tenantId: cfg.tenantId, timeoutMs: cfg.routerTimeoutMs
}); });
servedModel = out.servedModel; servedModel = out.servedModel;
assertServedModelAllowed(cfg.model, servedModel);
const raw = extractJson(out.content); const raw = extractJson(out.content);
if (!raw) { if (!raw) {
log(`[${fullRepo}@${sha.slice(0, 8)}] unparseable model output (served=${servedModel}): ${JSON.stringify(out.content.slice(0, 400))}`); log(`[${fullRepo}@${sha.slice(0, 8)}] unparseable model output (served=${servedModel}): ${JSON.stringify(out.content.slice(0, 400))}`);
@@ -313,6 +314,17 @@ export async function fetchDiff({ gitea, job, log = () => {}, maxBytes = Infinit
throw allDiffSourcesFailed(tried); throw allDiffSourcesFailed(tried);
} }
export function assertServedModelAllowed(requestedModel, servedModel) {
if (!isLocalModel(requestedModel)) return;
if (!servedModel) return;
if (servedModel === requestedModel) return;
throw new Error(`local model contract violated: requested ${requestedModel}, served ${servedModel}`);
}
function isLocalModel(model) {
return /^ollama(?:-remote)?\//.test(String(model || ''));
}
function allDiffSourcesFailed(tried) { function allDiffSourcesFailed(tried) {
let msg = tried.join(' | '); let msg = tried.join(' | ');
if (msg.length > 1500) msg = msg.slice(0, 1500) + ` …(+${tried.length} sources)`; if (msg.length > 1500) msg = msg.slice(0, 1500) + ` …(+${tried.length} sources)`;
+25
View File
@@ -0,0 +1,25 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { assertServedModelAllowed } from '../src/lib/review.js';
test('local model reviews accept the exact served local model', () => {
assert.doesNotThrow(() =>
assertServedModelAllowed('ollama-remote/qwen2.5-coder:7b', 'ollama-remote/qwen2.5-coder:7b'));
});
test('local model reviews fail on cloud fallback drift', () => {
assert.throws(
() => assertServedModelAllowed('ollama-remote/qwen2.5-coder:7b', 'google/gemini-2.5-flash'),
/local model contract violated/
);
});
test('cloud model reviews allow provider fallback reporting', () => {
assert.doesNotThrow(() =>
assertServedModelAllowed('anthropic/claude-sonnet-4-6', 'google/gemini-2.5-flash'));
});
test('missing served model metadata does not fail local requests', () => {
assert.doesNotThrow(() =>
assertServedModelAllowed('ollama-remote/qwen2.5-coder:7b', null));
});