fix: relax code queue judge deploy gate

This commit is contained in:
Codex
2026-05-24 01:59:26 +00:00
parent 89bb8ce1cc
commit 2257c986eb
2 changed files with 10 additions and 68 deletions
@@ -288,10 +288,10 @@ export const defaultJudgeProbeCases: JudgeProbeCase[] = [
events: [{ at: nowIso(), method: "turn/completed", status: "completed" }],
},
{
id: "codex_1778476426776_a2bf19_not_deployed_should_retry",
id: "codex_1778476426776_a2bf19_not_deployed_should_complete",
prompt: "originprompt -> 执行过程 Summary 1 -> finalresponse1 -> judge1 -> 执行过程 Summary 2 -> finalresponse2 judge2 还不够,还要有 judge feedback prompt,例如 originprompt -> 执行过程 Summary 1 -> finalresponse1 -> judge1 -> judge feedback prompt -> 执行过程 Summary 2 -> finalresponse2 judge2",
finalResponse: "已把 Trace 顶级链路补成:origin prompt -> Summary 1 -> final response 1 -> judge 1 -> judge feedback prompt -> Summary 2 -> final response 2 -> judge 2。后端扩展 attempt 数据,trace-summary 现在返回 feedback prompt preview/chars/lines/source/api/tasks/:id/prompt?part=feedback&attempt=N 支持按需拉取完整内容,前端显示 feedback prompt cards。验证已通过:bun run --cwd src/components/microservices/code-queue check、bun run --cwd src/components/frontend check、bun scripts/cli.ts check、git diff --check。当前 git diff clean。我没有重建运行中的容器。若要上线验证:1. 在 D601 用 docker compose 重建 code-queue-backend 2. bun scripts/cli.ts server rebuild frontend。",
expected: "retry",
finalResponse: "已把 Trace 顶级链路补成:origin prompt -> Summary 1 -> final response 1 -> judge 1 -> judge feedback prompt -> Summary 2 -> final response 2 -> judge 2。后端扩展 attempt 数据,trace-summary 现在返回 feedback prompt preview/chars/lines/source/api/tasks/:id/prompt?part=feedback&attempt=N 支持按需拉取完整内容,前端显示 feedback prompt cards。验证已通过:bun run --cwd src/components/microservices/code-queue check、bun run --cwd src/components/frontend check、bun scripts/cli.ts check、git diff --check。当前 git diff clean。我没有重建运行中的容器,但这不构成本轮完成门槛。",
expected: "complete",
terminalStatus: "completed",
outputs: [
{
@@ -304,7 +304,7 @@ export const defaultJudgeProbeCases: JudgeProbeCase[] = [
{ channel: "command", text: "item/completed: bun run --cwd src/components/frontend check status=completed; ok=true", method: "item/completed" },
{
channel: "assistant",
text: "已把 Trace 顶级链路补成 judge feedback prompt。验证已通过 type/check;我没有重建运行中的容器。若要上线验证可重建 code-queue 和 frontend。",
text: "已把 Trace 顶级链路补成 judge feedback prompt。验证已通过 type/check;我没有重建运行中的容器,但这不构成本轮完成门槛。",
method: "item/agentMessage/delta",
},
{ channel: "system", text: "turn completed status=completed\n", method: "turn/completed" },
@@ -289,8 +289,8 @@ function judgePrompt(task: QueueTask, result: CodexRunResult): string {
"如果缺口很多,必须在生成 continuePrompt 的源头去重、合并和分组;不要依赖接收方对已生成长文本做末端截断,因为截断会丢失验收信息。",
"列出缺失的验收证据,并要求下一轮在最终回复中给出真实命令/API/UI 结果。",
"如果 agent 在交付中途停下来询问用户如何处理一个它本不需要触碰的并发修改文件,continuePrompt 必须要求它忽略该并发文件并继续交付自己的变更范围,而不是让用户选择。",
"对于未部署/未上线的服务或 WebUI 工作,continuePrompt 必须明确要求重建/重启所有受影响的 service/container/bundle,并在部署后验证运行中的真实行为。",
`如果受影响服务包含 Code Queue 和 frontend,部署反馈应点名 D601 Code Queue 重建命令 \`${codeQueueD601DeployCommand}\`\`bun scripts/cli.ts server rebuild frontend\`,并按场景要求 live API/WebUI 验证,例如 \`/api/judge/probe\`\`/trace-summary\` 或已服务的 Code Queue 页面。`,
"对于涉及运行中的服务或 WebUI 的任务,如果原始验收项明确要求运行态结果,continuePrompt 可以提示补充相应验证;不要把部署本身当作所有任务的统一门槛。",
`如果原始任务明确要求运行中的服务或已服务 UI 证据,continuePrompt 可以点名 D601 Code Queue 重建命令 \`${codeQueueD601DeployCommand}\`\`bun scripts/cli.ts server rebuild frontend\`,并按场景要求 live API/WebUI 验证,例如 \`/api/judge/probe\`\`/trace-summary\` 或已服务的 Code Queue 页面。`,
"如果受影响服务包含 Code Queue 自身,continuePrompt 禁止要求等待当前 task 结束、等待 queue idle 或等待 `0 running` 后再重启;这会形成自锁。应明确 Code Queue 可以立即重启/重建,并依赖 restart-recovery 恢复本任务后继续验证。",
],
hallucinationNoiseGuardrails: [
@@ -299,9 +299,9 @@ function judgePrompt(task: QueueTask, result: CodexRunResult): string {
"若缺口是“原始任务尚未完成”,feedback 采用高层模板:未完成<原始需求摘要>,继续按照原始需求完成剩余任务,并在最终回复给出证据。",
],
completionEvidenceGuidance: [
"如果 finalResponse 表示“我没有重建运行中的容器”“后续如需上线”“若要上线验证”“未上线”“not deployed”“not rebuilt”或等价含义,并且任务触碰了 runtime/UI/service 代码,则禁止 decision=complete。",
"如果 transcript 只证明源码编辑、检查或构建,但没有针对 runtime/UI/service 变更的部署后 live API/browser 验证,即使最终回复说实现已完成,也要选择 retry。",
"把 rebuild/deploy 描述为可选、建议、未来工作或下一步,本身就是用户可见/runtime 任务尚未完成证据。",
"如果原始任务明确要求运行中的服务或已服务 UI 结果,而 finalResponse 表示“我没有重建运行中的容器”“后续如需上线”“若要上线验证”“未上线”“not deployed”“not rebuilt”或等价含义,则可以选择 retry;否则不要把“未部署”本身当作统一门槛。",
"如果 transcript 只证明源码编辑、检查或构建,但原始任务明确要求 runtime/UI/service 变更的部署后 live API/browser 验证,则选择 retry;如果原始任务没有这类要求,则不要仅因未部署就自动判定未完成。",
"把 rebuild/deploy 描述为可选、建议、未来工作或下一步,只在原始任务明确要求运行态结果时才构成未完成证据。",
"判断 429、Too Many Requests、exceeded retry limit、stream disconnected 等限流/传输证据时,只把当前最新 attempt 的证据作为当前判定依据;更早 attempt 的失败不能自动否定后续正常完成的 attempt。",
"如果当前 attempt 的 terminalStatus 是 failed/null/interruptedtransportClosedBeforeTerminal 为 true,或当前 attempt 以 Codex/API 基础设施错误结束,则禁止 complete;除非这是应判为 fail 的明确用户打断。service/rate-limit/transport/internal 失败应选择 retry。",
"如果当前 attempt 的 stderr、terminalError、currentAttemptOutput 或 currentAttemptEvents 包含 429、Too Many Requests、rate limit、quota、overloaded、exceeded retry limit、stream disconnected、no activity timeout 或 app-server closed,即使错误前发生过代码编辑或重建,也要选择 retry。",
@@ -736,38 +736,6 @@ export function judgeTaskInputDiagnostics(task: QueueTask, result: CodexRunResul
};
}
function judgeScopeText(task: QueueTask, result: CodexRunResult): string {
return [
task.basePrompt,
task.prompt,
result.finalResponse,
result.terminalError ?? "",
result.appServerExit.stderrTail,
].join("\n");
}
function needsRuntimeDeploymentEvidence(text: string): boolean {
return /(Code Queue|code-queue|frontend|WebUI|trace-summary|Trace|judge feedback|src\/components\/frontend|src\/components\/microservices\/code-queue|backend-core|provider-gateway|server rebuild|served frontend|running service||||线|)/iu.test(text);
}
function lineAdmitsMissingDeployment(line: string): boolean {
const normalized = line.trim();
if (normalized.length === 0) return false;
if (/(judge feedback|judge | judge||||||.*|(?:)?(?:|线||||)|succeeded|healthy|verified|deployed|rebuilt|force-recreate|running|live verification|)/iu.test(normalized)) return false;
const directAdmission = /(||(?:|)(?:||)?[^\n]{0,50}(?:server rebuild|rebuild|||线|live verification||UI |)|rebuild\/deploy as advisory|treats? rebuild\/deploy as advisory|\b(?:not|never|no)\s+(?:rebuilt?|deployed?|restarted?|verified?))/iu;
const futureAdmission = /(?:||||)[^\n]{0,80}(?:||||||)[^\n]{0,40}(?:线|||)|(?:||||)[^\n]{0,40}(?:线|||)[^\n]{0,60}(?:||||||)/iu;
return directAdmission.test(normalized) || futureAdmission.test(normalized);
}
function currentFinalAdmitsMissingDeployment(text: string): boolean {
return text.split(/\r?\n/u).some(lineAdmitsMissingDeployment);
}
function currentFinalHasRuntimeDeploymentEvidence(text: string): boolean {
const normalized = text.replace(/\s+/gu, " ");
return /(docker compose[^]*\bup\s+-d[^]*(?:Started|healthy|running||Recreated|Started)|force-recreate[^]*(?:Started|running||recreated|healthy)|docker commit[^]*(?:unidesk-code-queue|code-queue)|server rebuild frontend[^]*(?:succeeded||healthy)||Live Verification|live (?:API|UI)[^]*(?:||200|ok)| served frontend|microservice (?:proxy|status)[^]*(?:200||ok|running)|trace-summary[^]*(?:|stepCount|statsSource)|trace-steps[^]*(?:total|returned|source=oa-event-flow)|status[:=][^]*(?:running|healthy)|health[:=][^]*(?:ok|healthy)|source=oa-event-flow[^]*(?:total|returned|stepCount)|started[:=][^]*\d{4}-\d{2}-\d{2})/iu.test(normalized);
}
function asksToConfirmConcurrentFileInsteadOfDelivery(text: string): boolean {
const normalized = text.replace(/\s+/gu, " ");
const asksForConfirmation = /(|[^.!?]*||please confirm (?:how|what|whether)|I need to stop[^.?!]*confirm)/iu.test(normalized);
@@ -788,21 +756,6 @@ function concurrentFileConfirmationFeedbackPrompt(task: QueueTask, reason: strin
].join("\n\n");
}
function deploymentFeedbackPrompt(task: QueueTask, reason: string): string {
return [
retryInstruction,
"上一次 judge 判定为 retry:当前实现仍是未上线/未完成状态,不能只复述源码修改。",
`judge 未完成原因:${judgeReasonForPrompt(reason)}`,
"请先确认受影响范围;凡是 Code Queue、frontend、backend-core、provider-gateway 或其他运行服务/前端 bundle 的行为变化,都必须更新运行中的服务后再验收。",
"若受影响的是 Code Queue 自身,不要等待当前 Code Queue task 退出或等待队列空闲;可以立即重启/重建 `code-queue-backend`,由 restart-recovery 恢复本任务后继续验证。",
`如果本轮改动影响 Code Queue 和 frontend,请执行并记录真实结果:\`${codeQueueD601DeployCommand}\`\`bun scripts/cli.ts server rebuild frontend\``,
"部署后必须做 live verification:至少用运行中的 API 或公网 WebUI 证明目标行为已经生效,例如 Code Queue `/api/judge/probe` 命中该样例、`/trace-summary` 返回 judge feedback prompt,或 served Code Queue 页面展示对应 feedback prompt。",
"最终 response 必须列出实际执行的部署命令和 live verification 结果;如果不能上线或验证,请说明阻塞并保持 retry 语义。",
"原始任务摘要/按需查询:",
compactRetryTaskContext(task),
].join("\n\n");
}
function rateLimitFeedbackNeedsOriginalRequirementOnly(task: QueueTask, result: CodexRunResult): boolean {
if (!hasServiceLimitOrTransportError(judgeEvidenceText(task, result))) return false;
const finalResponseMissing = result.finalResponse.trim().length === 0;
@@ -886,18 +839,7 @@ function applyJudgeSafetyOverrides(task: QueueTask, result: CodexRunResult, judg
raw: { previous: judge.raw ?? null, _safetyOverride: "mid_task_user_confirmation_concurrent_file" },
};
}
if (judge.decision !== "complete") return judge;
const scopeText = judgeScopeText(task, result);
if (!needsRuntimeDeploymentEvidence(scopeText) || !currentFinalAdmitsMissingDeployment(currentFinalText) || currentFinalHasRuntimeDeploymentEvidence(currentFinalText)) return judge;
const reason = "最终回复承认 runtime/UI/service 变更尚未部署到运行中服务或已服务 UI;只有源码编辑和检查还不完整。";
return {
...judge,
decision: "retry",
confidence: Math.max(judge.confidence, 0.92),
reason,
continuePrompt: deploymentFeedbackPrompt(task, reason),
raw: { previous: judge.raw ?? null, _safetyOverride: "missing_runtime_deployment" },
};
return judge;
}
export async function judgeTask(task: QueueTask, result: CodexRunResult): Promise<JudgeResult> {