feat: require concrete evidence for progress claims

This commit is contained in:
Eve
2026-04-23 15:22:02 +08:00
parent 17449fa519
commit 180619cf87
3 changed files with 59 additions and 13 deletions

View File

@@ -85,6 +85,19 @@ async function runLongTaskWrapper(workspaceDir: string, ctx: any): Promise<any |
return runJsonScript(wrapperPath, workspaceDir, input, LONG_TASK_WRAPPER_TIMEOUT_MS);
}
function buildProgressEvidence(wrapperResult: any): Record<string, unknown> | null {
const progressEvidence: Record<string, unknown> = {};
const taskName = typeof wrapperResult?.taskRecord?.task_name === "string"
? wrapperResult.taskRecord.task_name.trim()
: "";
if (wrapperResult?.silentLaunchOk === true && taskName) {
progressEvidence.sessionKey = taskName;
}
return Object.keys(progressEvidence).length > 0 ? progressEvidence : null;
}
function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
if (!wrapperResult || wrapperResult.classification !== "long_task") {
return { classification: wrapperResult?.classification ?? "general_chat" };
@@ -92,6 +105,7 @@ function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
const needsOwnerDecision = wrapperResult.needsOwnerDecision === true;
const silentCandidate = wrapperResult.silentCandidate === true;
const progressEvidence = buildProgressEvidence(wrapperResult);
const requiredNextAction = typeof wrapperResult.requiredNextAction === "string"
? wrapperResult.requiredNextAction.trim()
: "";
@@ -130,6 +144,11 @@ function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
claimedProgression: claimedProgression,
statusSummary: claimedProgression,
executionEvidence,
progressEvidence,
sessionKey: typeof progressEvidence?.sessionKey === "string" ? progressEvidence.sessionKey : "",
runId: typeof progressEvidence?.runId === "string" ? progressEvidence.runId : "",
modified_files: Array.isArray(progressEvidence?.modified_files) ? progressEvidence.modified_files : [],
verificationResult: typeof progressEvidence?.verificationResult === "string" ? progressEvidence.verificationResult : "",
toolCallEvidence: "",
dispatchEvidence: "",
fileChangeEvidence: "",
@@ -201,8 +220,8 @@ function buildGateLockBlock(gateLockResult: GateLockResult | null): string {
"gateStatus=degraded",
"gateRequired=unknown",
"- ENFORCEMENT: Gate-lock evaluator unavailable; keep existing long-task safeguards in force.",
"- ENFORCEMENT: Do not claim you have progressed into the next task or are already pushing the next step unless you have concrete evidence such as actual dispatch, tool calls, file changes, or a persisted checkpoint artifact.",
"- HARD_GATE: Evaluator unavailable is not permission to claim silent continuation or next-task progression without verifiable evidence.",
"- ENFORCEMENT: Do not claim you have progressed into the next task or are already pushing the next step unless you have concrete progress evidence such as a sessionKey, runId, modified_files record, verification result, actual dispatch, tool calls, file changes, or a persisted checkpoint artifact.",
"- HARD_GATE: Evaluator unavailable is not permission to claim silent continuation or next-task progression without verifiable progress evidence.",
"- HARD_GATE: Fall back to a non-silent, evidence-preserving follow-up if you cannot prove checkpoint state or concrete execution.",
"[/LONG_TASK_GATE_LOCK]",
"",
@@ -219,15 +238,15 @@ function buildGateLockBlock(gateLockResult: GateLockResult | null): string {
return `requiredEvidence=${requirement.evidenceKey ?? "unknown"};fields=${fields};requiredValue=${requirement.requiredValue ?? "unknown"}`;
})),
...((gateLockResult.allowedResponseModes ?? []).map((mode) => `allowedResponseMode=${mode}`)),
"- ENFORCEMENT: Do not claim you have progressed into the next task or are already pushing the next step unless you have concrete evidence such as actual dispatch, tool calls, file changes, or a persisted checkpoint artifact.",
"- ENFORCEMENT: Do not claim you have progressed into the next task or are already pushing the next step unless you have concrete progress evidence such as a sessionKey, runId, modified_files record, verification result, actual dispatch, tool calls, file changes, or a persisted checkpoint artifact.",
"- ENFORCEMENT: Forbidden path: plain-text handoff that pretends the long task is already continuing without an externalized checkpoint.",
"- ENFORCEMENT: Forbidden path: stating you have already entered the next task/step when the record only contains planning language and no concrete execution evidence.",
];
if (gateLockResult.gateStatus === "fail") {
lines.push("- HARD_GATE: Block any plain-text handoff or silent-continuation claim when externalized checkpoint evidence is missing.");
lines.push("- HARD_GATE: Block any reply path that says you already moved into the next task or are advancing the next step without concrete execution evidence.");
lines.push("- HARD_GATE: Do not say you are already on the next task, already dispatched follow-up work, or already progressing in background unless you can point to actual tool execution, file changes, emitted messages, or checkpoint records.");
lines.push("- HARD_GATE: Block any reply path that says you already moved into the next task or are advancing the next step without concrete progress evidence.");
lines.push("- HARD_GATE: Do not say you are already on the next task, already dispatched follow-up work, or already progressing in background unless you can point to a sessionKey, runId, modified_files record, verification result, actual tool execution, file changes, emitted messages, or checkpoint records.");
lines.push("- HARD_GATE: If required evidence is missing, ask for/produce the checkpoint or downgrade to a non-silent, evidence-preserving follow-up.");
lines.push("- HARD_GATE: If owner decision is involved, do not replace button-path closure with plain-text handoff.");
}