fix: emit real checkpoint artifact for wrapper integration
This commit is contained in:
@@ -46,6 +46,23 @@ async function safeReadText(filePath: string): Promise<string | null> {
|
||||
}
|
||||
}
|
||||
|
||||
async function getReadableCheckpointArtifact(workspaceDir: string, wrapperResult: any): Promise<{ relativePath: string; absolutePath: string; content: string; } | null> {
|
||||
const relativePath = typeof wrapperResult?.externalizedCheckpointPath === "string"
|
||||
? wrapperResult.externalizedCheckpointPath.trim()
|
||||
: "";
|
||||
if (!relativePath) return null;
|
||||
|
||||
const absolutePath = path.resolve(workspaceDir, relativePath);
|
||||
try {
|
||||
const raw = await fs.readFile(absolutePath, "utf-8");
|
||||
const content = raw.trim();
|
||||
if (!content) return null;
|
||||
return { relativePath, absolutePath, content };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function runJsonScript(scriptPath: string, workspaceDir: string, input: Record<string, unknown>, timeout: number): Promise<any | null> {
|
||||
let tempInputPath: string | null = null;
|
||||
|
||||
@@ -95,7 +112,7 @@ 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 {
|
||||
function buildProgressEvidence(wrapperResult: any, readableCheckpointArtifact: { relativePath: string; absolutePath: string; content: string; } | null): Record<string, unknown> | null {
|
||||
const candidate = wrapperResult?.progressEvidence;
|
||||
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
||||
return null;
|
||||
@@ -128,6 +145,13 @@ function buildProgressEvidence(wrapperResult: any): Record<string, unknown> | nu
|
||||
progressEvidence.verificationResult = verificationResult;
|
||||
}
|
||||
|
||||
if (readableCheckpointArtifact) {
|
||||
progressEvidence.checkpointPath = readableCheckpointArtifact.relativePath;
|
||||
if (!progressEvidence.verificationResult) {
|
||||
progressEvidence.verificationResult = `checkpoint artifact readable at ${readableCheckpointArtifact.relativePath}`;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(progressEvidence).length > 0 ? progressEvidence : null;
|
||||
}
|
||||
|
||||
@@ -158,14 +182,14 @@ function shouldClaimProgression(wrapperResult: any, progressEvidence: Record<str
|
||||
return wrapperResult.silentLaunchOk === true;
|
||||
}
|
||||
|
||||
function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
|
||||
function buildGateLockInput(wrapperResult: any, readableCheckpointArtifact: { relativePath: string; absolutePath: string; content: string; } | null): Record<string, unknown> {
|
||||
if (!wrapperResult || wrapperResult.classification !== "long_task") {
|
||||
return { classification: wrapperResult?.classification ?? "general_chat" };
|
||||
}
|
||||
|
||||
const needsOwnerDecision = wrapperResult.needsOwnerDecision === true;
|
||||
const silentCandidate = wrapperResult.silentCandidate === true;
|
||||
const progressEvidence = buildProgressEvidence(wrapperResult);
|
||||
const progressEvidence = buildProgressEvidence(wrapperResult, readableCheckpointArtifact);
|
||||
const requiredNextAction = typeof wrapperResult.requiredNextAction === "string"
|
||||
? wrapperResult.requiredNextAction.trim()
|
||||
: "";
|
||||
@@ -197,8 +221,7 @@ function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
|
||||
const progressEvidenceReason = claimedProgression && !progressEvidence
|
||||
? "progression claim requires concrete evidence such as sessionKey, runId, modified_files, or verification result"
|
||||
: "";
|
||||
const hasExternalizedCheckpointEvidence = typeof wrapperResult.externalizedCheckpointPath === "string"
|
||||
&& wrapperResult.externalizedCheckpointPath.trim().length > 0;
|
||||
const hasExternalizedCheckpointEvidence = Boolean(readableCheckpointArtifact);
|
||||
const hasButtonPathClosureEvidence = needsOwnerDecision && wrapperResult.silentLaunchOk === true;
|
||||
|
||||
return {
|
||||
@@ -228,8 +251,8 @@ function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
|
||||
dispatchEvidence: "",
|
||||
fileChangeEvidence: "",
|
||||
verificationEvidence: "",
|
||||
checkpointArtifactEvidence: hasExternalizedCheckpointEvidence ? wrapperResult.externalizedCheckpointPath.trim() : "",
|
||||
externalizedCheckpointPath: hasExternalizedCheckpointEvidence ? wrapperResult.externalizedCheckpointPath.trim() : "",
|
||||
checkpointArtifactEvidence: hasExternalizedCheckpointEvidence ? readableCheckpointArtifact.relativePath : "",
|
||||
externalizedCheckpointPath: hasExternalizedCheckpointEvidence ? readableCheckpointArtifact.relativePath : "",
|
||||
externalizedTrigger: hasExternalizedCheckpointEvidence ? "hook-preflight-checkpoint" : "",
|
||||
handoffMode: hasButtonPathClosureEvidence ? (wrapperResult.handoff?.mode ?? "button_path") : "direct_reply",
|
||||
replyClosureMode: hasButtonPathClosureEvidence ? (wrapperResult.handoff?.mode ?? "button_path") : "direct_reply",
|
||||
@@ -238,7 +261,8 @@ function buildGateLockInput(wrapperResult: any): Record<string, unknown> {
|
||||
|
||||
async function runLongTaskGateLock(workspaceDir: string, wrapperResult: any): Promise<GateLockResult | null> {
|
||||
const gateLockPath = path.join(workspaceDir, "scripts", "long_task_gate_lock.mjs");
|
||||
const input = buildGateLockInput(wrapperResult);
|
||||
const readableCheckpointArtifact = await getReadableCheckpointArtifact(workspaceDir, wrapperResult);
|
||||
const input = buildGateLockInput(wrapperResult, readableCheckpointArtifact);
|
||||
return runJsonScript(gateLockPath, workspaceDir, input, LONG_TASK_GATE_LOCK_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user