docs: add code queue minimax routing guard

This commit is contained in:
Codex
2026-05-21 01:14:15 +00:00
parent acc03b10f4
commit a43c24dd88
6 changed files with 387 additions and 10 deletions
+3
View File
@@ -282,6 +282,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
fileItem("scripts/src/code-queue-liveness-fixtures.ts"),
fileItem("scripts/code-queue-trace-summary-contract-test.ts"),
fileItem("scripts/code-queue-pr-preflight-contract-test.ts"),
fileItem("scripts/code-queue-submit-routing-contract-test.ts"),
fileItem("scripts/src/ci.ts"),
fileItem("scripts/src/e2e.ts"),
fileItem("scripts/deploy-artifact-matrix-contract-test.ts"),
@@ -303,6 +304,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
items.push(commandItem("code-queue:issue3-diagnostics-and-image-preflight", ["bun", "scripts/code-queue-issue3-regression-test.ts"], 30_000));
items.push(commandItem("code-queue:trace-summary-contract", ["bun", "scripts/code-queue-trace-summary-contract-test.ts"], 30_000));
items.push(commandItem("code-queue:pr-preflight-contract", ["bun", "scripts/code-queue-pr-preflight-contract-test.ts"], 30_000));
items.push(commandItem("code-queue:submit-routing-contract", ["bun", "scripts/code-queue-submit-routing-contract-test.ts"], 30_000));
items.push(commandItem("deploy:artifact-matrix-contract", ["bun", "scripts/deploy-artifact-matrix-contract-test.ts"], 30_000));
items.push(commandItem("code-queue:active-run-heartbeat-visible", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:active-run-heartbeat-visible"], 30_000));
items.push(commandItem("code-queue:trace-gap-not-stale", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:trace-gap-not-stale"], 30_000));
@@ -320,6 +322,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
items.push(skippedItem("code-queue:issue3-diagnostics-and-image-preflight", "Code Queue issue #3 regression fixtures are opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:trace-summary-contract", "Code Queue trace summary contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:pr-preflight-contract", "Code Queue PR preflight contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:submit-routing-contract", "Code Queue submit routing contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("deploy:artifact-matrix-contract", "deploy artifact matrix contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:liveness-diagnostics-fixtures", "Code Queue liveness diagnostics fixtures are opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("baidu-netdisk:artifact-guard-contract", "Baidu Netdisk artifact guard contract is opt-in with script checks", "--scripts-typecheck or --full"));
+276
View File
@@ -11,6 +11,8 @@ const defaultTextPreviewChars = 12_000;
const defaultTasksLimit = 20;
const maxTasksLimit = 100;
const steerPromptPreviewChars = 320;
const minimaxSubmitModel = "minimax-m2.7";
const gptSubmitModel = "gpt-5.5";
const submitLockWaitMs = 60_000;
const submitLockPollMs = 250;
const submitLockStaleMs = 120_000;
@@ -56,6 +58,43 @@ interface CodexSubmitOptions {
dryRun: boolean;
}
type SubmitRoute = "minimax-opencode" | "gpt-5.5-codex" | "commander-human-only";
type SubmitRouteSignalSeverity = "info" | "warning" | "block";
interface SubmitRouteSignal {
id: string;
severity: SubmitRouteSignalSeverity;
matched: boolean;
evidence: string[];
message: string;
}
interface SubmitRoutingRecommendation {
route: SubmitRoute;
recommendedRunner: "opencode" | "codex" | "commander";
recommendedModel: string | null;
confidence: "medium" | "high";
reason: string;
signals: SubmitRouteSignal[];
riskControls: {
promptSelfContained: boolean;
issueIsNotOnlySource: boolean;
noProdRestartSecretOrDbWrite: boolean;
evidenceRequiredByPrompt: boolean;
commanderMustReviewUnread: true;
};
explicitRequest: {
model: string | null;
runner: "opencode" | "codex" | null;
note: string | null;
};
routingPolicy: {
dryRunOnly: true;
doesNotChangeSubmittedPayload: true;
prodMiniMaxAssumedAvailable: false;
};
}
interface CodexSteerOptions {
prompt: string;
dryRun: boolean;
@@ -532,6 +571,222 @@ function compactQueuedReason(value: unknown): Record<string, unknown> | null {
};
}
function normalizeSubmitModel(value: string | null | undefined): string {
const raw = String(value ?? "").trim();
if (raw.length === 0) return raw;
const lower = raw.toLowerCase();
const leaf = lower.includes("/") ? lower.split("/").at(-1) ?? lower : lower;
if (leaf === minimaxSubmitModel || leaf === "m2.7") return minimaxSubmitModel;
return raw;
}
function submitRunnerForModel(model: string | null | undefined): "opencode" | "codex" | null {
const normalized = normalizeSubmitModel(model);
if (normalized.length === 0) return null;
return normalized === minimaxSubmitModel ? "opencode" : "codex";
}
function regexEvidence(text: string, patterns: RegExp[], limit = 6): string[] {
const evidence: string[] = [];
for (const pattern of patterns) {
for (const match of text.matchAll(pattern)) {
const value = String(match[0] ?? "").trim().replace(/\s+/gu, " ");
if (value.length > 0 && !evidence.includes(value)) evidence.push(value);
if (evidence.length >= limit) return evidence;
}
}
return evidence;
}
function regexEvidenceWithoutNegatedContext(text: string, patterns: RegExp[], limit = 6): string[] {
const evidence: string[] = [];
for (const pattern of patterns) {
for (const match of text.matchAll(pattern)) {
const index = match.index ?? 0;
const context = text.slice(Math.max(0, index - 36), Math.min(text.length, index + String(match[0] ?? "").length + 36));
if (/(?:|||||||avoid|forbid|forbidden|do not|don't|must not|no\s+)/iu.test(context)) continue;
const value = String(match[0] ?? "").trim().replace(/\s+/gu, " ");
if (value.length > 0 && !evidence.includes(value)) evidence.push(value);
if (evidence.length >= limit) return evidence;
}
}
return evidence;
}
function routeSignal(id: string, severity: SubmitRouteSignalSeverity, evidence: string[], message: string): SubmitRouteSignal {
return { id, severity, matched: evidence.length > 0, evidence, message };
}
function submitRoutingRecommendation(options: CodexSubmitOptions): SubmitRoutingRecommendation {
const prompt = options.prompt;
const lower = prompt.toLowerCase();
const prodOrStateMutation = regexEvidenceWithoutNegatedContext(lower, [
/\bprod(?:uction)?\b/gu,
/\brestart(?:ing|ed)?\b/gu,
/\brebuild(?:ing|ed)?\b/gu,
/\bdeploy(?:ment|ing|ed)?\b/gu,
/\bserver\s+rebuild\b/gu,
/\bdeploy\s+apply\b/gu,
/\binterrupt\b|\bcancel\b/gu,
/\bsecret\b|\btoken\b|\bapi[_-]?key\b|\bcredential\b/gu,
/\bpostgres(?:ql)?\b|\bpsql\b|\bdatabase\b|\bdb\b|\bsql\b|\bmigration\b/gu,
]);
const runtimeCore = regexEvidence(lower, [
/\bcode[- ]queue\s+(?:runtime|scheduler|backend|execution|runner)\b/gu,
/\bbackend-core\b/gu,
/\bprovider-gateway\b/gu,
/\bk3sctl-adapter\b/gu,
/\bruntime-preflight\b/gu,
/\bactive\s+run\b/gu,
]);
const issueReference = regexEvidence(lower, [
/\bgithub\s+issue\b/gu,
/\bissue\s+#?\d+\b/gu,
/#\d+/gu,
/\bgh\s+issue\s+view\b/gu,
]);
const issueOnly = regexEvidence(lower, [
/\bread\s+(?:the\s+)?issue\b/gu,
/\bsee\s+(?:github\s+)?issue\b/gu,
/\bfrom\s+issue\s+#?\d+\b/gu,
/\bissue\s+(?:has|contains)\s+(?:the\s+)?(?:full|complete)\s+(?:context|requirements?)\b/gu,
/\s*(?:github\s*)?issue/gu,
/\s*(?:github\s*)?issue/gu,
]);
const issueAuxiliaryGuard = regexEvidence(prompt, [
/issue[^\n]*/giu,
/issue[^\n]*/giu,
/issue[^\n]*not[^\n]*only[^\n]*source/giu,
/issue[^\n]*auxiliary[^\n]*reference/giu,
]);
const lowRiskEvidence = regexEvidence(lower, [
/\bdry-run\b/gu,
/\bpreflight\b/gu,
/\bcontract\s+test\b/gu,
/\btypecheck\b/gu,
/\bdocs?\b|\bdocumentation\b/gu,
/\bread[- ]?only\b/gu,
//gu,
//gu,
//gu,
]);
const evidenceRequest = regexEvidence(lower, [
/\bevidence\b/gu,
/\bverification\b|\bverified\b|\bvalidate\b|\bvalidation\b/gu,
/\btest(?:s|ed|ing)?\b/gu,
/\bdry-run\b/gu,
/\bcommit\b/gu,
//gu,
//gu,
//gu,
]);
const selfContainedHints = regexEvidence(prompt, [
/[:]/gu,
/[:]/gu,
/[:]/gu,
/[:]/gu,
/final response/giu,
//gu,
/ prompt/gu,
]);
const destructiveWords = regexEvidenceWithoutNegatedContext(lower, [
/\brm\s+-rf\b/gu,
/\bgit\s+reset\s+--hard\b/gu,
/\bgit\s+checkout\s+--\b/gu,
/\bdrop\s+table\b/gu,
/\btruncate\s+table\b/gu,
/\bdelete\s+from\b/gu,
]);
const crossModule = regexEvidence(lower, [
/\bcross[- ]module\b/gu,
/\barchitecture\b|\barchitectural\b/gu,
/\brelease\/v1\b/gu,
/\bci\/cd\b/gu,
/\brollout\b|\brollback\b/gu,
//gu,
//gu,
/|/gu,
]);
const model = normalizeSubmitModel(options.model);
const explicitRunner = submitRunnerForModel(model);
const promptSelfContained = prompt.length >= 700 || selfContainedHints.length >= 3;
const issueIsNotOnlySource = issueReference.length === 0 || issueAuxiliaryGuard.length > 0 || issueOnly.length === 0 && prompt.length >= 500;
const noProdRestartSecretOrDbWrite = prodOrStateMutation.length === 0 && destructiveWords.length === 0;
const evidenceRequiredByPrompt = evidenceRequest.length > 0;
const signals = [
routeSignal("prod-state-secret-db-write", "block", [...prodOrStateMutation, ...destructiveWords], "Mentions production/state mutation, restart, secrets, DB writes, or destructive commands."),
routeSignal("runtime-core", "warning", runtimeCore, "Touches Code Queue runtime, backend-core, provider-gateway, k3s adapter, or active run behavior."),
routeSignal("issue-source-risk", "warning", issueOnly, "Prompt appears to rely on GitHub issue reading as task context."),
routeSignal("issue-auxiliary-source-guard", "info", issueAuxiliaryGuard, "Prompt explicitly says GitHub issue is auxiliary and not the only source."),
routeSignal("cross-module-release", "warning", crossModule, "Mentions cross-module architecture, CI/CD rollout, release line, or rollback work."),
routeSignal("low-risk-verifiable", "info", lowRiskEvidence, "Mentions low-risk or verifiable work such as docs, read-only checks, dry-run, preflight, or contract tests."),
routeSignal("evidence-requested", "info", evidenceRequest, "Prompt asks for tests, validation, commit, or evidence."),
routeSignal("self-contained-hints", "info", selfContainedHints, "Prompt includes explicit task sections that make it easier to verify without reading an issue."),
];
let route: SubmitRoute = "gpt-5.5-codex";
let recommendedRunner: SubmitRoutingRecommendation["recommendedRunner"] = "codex";
let recommendedModel: string | null = gptSubmitModel;
let confidence: SubmitRoutingRecommendation["confidence"] = "medium";
let reason = "Default to GPT-5.5 when the prompt is not clearly low-risk and self-contained.";
if (prodOrStateMutation.length > 0 || destructiveWords.length > 0) {
route = "commander-human-only";
recommendedRunner = "commander";
recommendedModel = null;
confidence = "high";
reason = "This task mentions production/state mutation, restart, secrets, DB writes, or destructive operations; keep it with the commander or a human.";
} else if (runtimeCore.length > 0 || crossModule.length > 0) {
route = "gpt-5.5-codex";
confidence = "high";
reason = "This task touches runtime/core/cross-module or release-governance surfaces, so it should stay on GPT-5.5.";
} else if (promptSelfContained && issueIsNotOnlySource && evidenceRequiredByPrompt && lowRiskEvidence.length > 0) {
route = "minimax-opencode";
recommendedRunner = "opencode";
recommendedModel = minimaxSubmitModel;
confidence = "high";
reason = "The prompt looks self-contained, low-risk, and asks for verifiable evidence; it is a MiniMax/OpenCode candidate if the runner smoke is currently green.";
} else if (lowRiskEvidence.length > 0 && issueIsNotOnlySource && noProdRestartSecretOrDbWrite) {
route = "minimax-opencode";
recommendedRunner = "opencode";
recommendedModel = minimaxSubmitModel;
confidence = "medium";
reason = "The prompt has low-risk signals, but the commander should tighten self-contained context and evidence requirements before relying on MiniMax.";
}
const explicitNote = model.length === 0
? null
: explicitRunner === recommendedRunner
? "Explicit --model matches the dry-run recommendation."
: "Explicit --model differs from the dry-run recommendation; this dry-run does not rewrite the payload.";
return {
route,
recommendedRunner,
recommendedModel,
confidence,
reason,
signals,
riskControls: {
promptSelfContained,
issueIsNotOnlySource,
noProdRestartSecretOrDbWrite,
evidenceRequiredByPrompt,
commanderMustReviewUnread: true,
},
explicitRequest: {
model: model.length === 0 ? null : model,
runner: explicitRunner,
note: explicitNote,
},
routingPolicy: {
dryRunOnly: true,
doesNotChangeSubmittedPayload: true,
prodMiniMaxAssumedAvailable: false,
},
};
}
function compactSchedulerHeartbeat(value: unknown): Record<string, unknown> | null {
const record = asRecord(value);
if (record === null) return null;
@@ -2149,6 +2404,21 @@ export function codexPrPreflightQueryForTest(optionArgs: string[], fetcher: Code
return codeQueuePrPreflight(optionArgs, fetcher);
}
export function codexSubmitRoutingRecommendationForTest(prompt: string, model?: string): SubmitRoutingRecommendation {
return submitRoutingRecommendation({
prompt,
model,
queueId: undefined,
providerId: undefined,
cwd: undefined,
reasoningEffort: undefined,
executionMode: undefined,
maxAttempts: undefined,
referenceTaskIds: [],
dryRun: true,
});
}
function codexSubmitTask(args: string[]): unknown {
const options = parseSubmitOptions(args);
const payload = submitPayload(options);
@@ -2156,10 +2426,16 @@ function codexSubmitTask(args: string[]): unknown {
return {
ok: true,
dryRun: true,
routingRecommendation: submitRoutingRecommendation(options),
request: {
...payload,
prompt: textView(options.prompt, true, 3000),
},
commands: {
submitAsRequested: "remove --dry-run to submit exactly this payload",
minimaxCandidate: `bun scripts/cli.ts codex submit --prompt-file <path> --model ${minimaxSubmitModel} --dry-run`,
gptCandidate: `bun scripts/cli.ts codex submit --prompt-file <path> --model ${gptSubmitModel} --dry-run`,
},
};
}
const locked = runWithSubmitLock(() => unwrapCodexResponse(coreInternalFetch(codeQueueProxyPath("/api/tasks"), { method: "POST", body: payload })));