@riddledc/riddle-proof 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-IQIEOQZF.js → chunk-5FHUOSNO.js} +5 -0
- package/dist/{chunk-P3FUU5X4.js → chunk-F65YYXVO.js} +1 -1
- package/dist/chunk-UON7C6N4.js +684 -0
- package/dist/engine-harness.cjs +924 -0
- package/dist/engine-harness.d.cts +69 -0
- package/dist/engine-harness.d.ts +69 -0
- package/dist/engine-harness.js +12 -0
- package/dist/index.cjs +676 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -2
- package/dist/openclaw.cjs +10 -0
- package/dist/openclaw.d.cts +5 -0
- package/dist/openclaw.d.ts +5 -0
- package/dist/openclaw.js +6 -1
- package/dist/runner.cjs +5 -0
- package/dist/runner.js +2 -2
- package/dist/state.cjs +5 -0
- package/dist/state.js +1 -1
- package/dist/types.d.cts +5 -0
- package/dist/types.d.ts +5 -0
- package/package.json +7 -2
|
@@ -63,6 +63,11 @@ function normalizeRunParams(input) {
|
|
|
63
63
|
color_scheme: input.color_scheme,
|
|
64
64
|
wait_for_selector: input.wait_for_selector,
|
|
65
65
|
ship_mode: input.ship_mode,
|
|
66
|
+
engine_state_path: input.engine_state_path,
|
|
67
|
+
harness_state_path: input.harness_state_path,
|
|
68
|
+
max_iterations: input.max_iterations,
|
|
69
|
+
auto_approve: input.auto_approve,
|
|
70
|
+
dry_run: input.dry_run,
|
|
66
71
|
integration_context: normalizeIntegrationContext(input.integration_context)
|
|
67
72
|
});
|
|
68
73
|
}
|
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendRunEvent,
|
|
3
|
+
appendStageHeartbeat,
|
|
4
|
+
createRunState,
|
|
5
|
+
createRunStatusSnapshot,
|
|
6
|
+
normalizeRunParams,
|
|
7
|
+
setRunStatus
|
|
8
|
+
} from "./chunk-5FHUOSNO.js";
|
|
9
|
+
import {
|
|
10
|
+
applyTerminalMetadata,
|
|
11
|
+
compactRecord,
|
|
12
|
+
createRunResult,
|
|
13
|
+
nonEmptyString,
|
|
14
|
+
normalizeTerminalMetadata,
|
|
15
|
+
recordValue
|
|
16
|
+
} from "./chunk-5DC6YXN4.js";
|
|
17
|
+
|
|
18
|
+
// src/engine-harness.ts
|
|
19
|
+
import { execFileSync } from "child_process";
|
|
20
|
+
import {
|
|
21
|
+
existsSync,
|
|
22
|
+
mkdirSync,
|
|
23
|
+
readFileSync,
|
|
24
|
+
statSync,
|
|
25
|
+
unlinkSync,
|
|
26
|
+
writeFileSync
|
|
27
|
+
} from "fs";
|
|
28
|
+
import path from "path";
|
|
29
|
+
import crypto from "crypto";
|
|
30
|
+
function timestamp() {
|
|
31
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
32
|
+
}
|
|
33
|
+
function createHarnessStatePath(stateDir) {
|
|
34
|
+
const stamp = timestamp().replace(/\D/g, "").slice(0, 14) || "unknown";
|
|
35
|
+
return path.join(stateDir, `riddle-proof-run-${stamp}-${crypto.randomUUID().slice(0, 8)}.json`);
|
|
36
|
+
}
|
|
37
|
+
function ensureParent(filePath) {
|
|
38
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
function readJson(filePath) {
|
|
41
|
+
if (!filePath || !existsSync(filePath)) return null;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function writeJson(filePath, payload) {
|
|
49
|
+
ensureParent(filePath);
|
|
50
|
+
writeFileSync(filePath, JSON.stringify(payload, null, 2) + "\n");
|
|
51
|
+
}
|
|
52
|
+
function loadRunState(input) {
|
|
53
|
+
if (input.state) return input.state;
|
|
54
|
+
const stateDir = input.config?.stateDir || "/tmp";
|
|
55
|
+
const statePath = input.state_path || input.request.harness_state_path || createHarnessStatePath(stateDir);
|
|
56
|
+
const existing = readJson(statePath);
|
|
57
|
+
if (existing?.version === "riddle-proof.run-state.v1" && Array.isArray(existing.events) && existing.request) {
|
|
58
|
+
return existing;
|
|
59
|
+
}
|
|
60
|
+
return createRunState({
|
|
61
|
+
request: input.request,
|
|
62
|
+
state_path: statePath
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function persist(state) {
|
|
66
|
+
if (state.state_path) writeJson(state.state_path, state);
|
|
67
|
+
}
|
|
68
|
+
function recordEvent(state, event) {
|
|
69
|
+
appendRunEvent(state, event);
|
|
70
|
+
persist(state);
|
|
71
|
+
}
|
|
72
|
+
function heartbeat(state, input) {
|
|
73
|
+
appendStageHeartbeat(state, input);
|
|
74
|
+
persist(state);
|
|
75
|
+
}
|
|
76
|
+
function jsonParam(payload) {
|
|
77
|
+
return JSON.stringify(payload);
|
|
78
|
+
}
|
|
79
|
+
function engineStatePath(result, state) {
|
|
80
|
+
return nonEmptyString(result.state_path) || nonEmptyString(state.request.engine_state_path);
|
|
81
|
+
}
|
|
82
|
+
function fullRiddleState(result, state) {
|
|
83
|
+
return readJson(engineStatePath(result, state)) || recordValue(result.state) || null;
|
|
84
|
+
}
|
|
85
|
+
function workdirFromState(state) {
|
|
86
|
+
return nonEmptyString(state?.after_worktree) || nonEmptyString(state?.worktree_path) || null;
|
|
87
|
+
}
|
|
88
|
+
function hasGitDiff(workdir) {
|
|
89
|
+
if (!workdir || !existsSync(workdir)) return false;
|
|
90
|
+
try {
|
|
91
|
+
const status = execFileSync("git", ["status", "--porcelain"], {
|
|
92
|
+
cwd: workdir,
|
|
93
|
+
encoding: "utf-8",
|
|
94
|
+
timeout: 1e4
|
|
95
|
+
});
|
|
96
|
+
return status.trim().length > 0;
|
|
97
|
+
} catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function removeEmptyToolArtifacts(workdir) {
|
|
102
|
+
if (!workdir || !existsSync(workdir)) return [];
|
|
103
|
+
const artifactPath = path.join(workdir, ".codex");
|
|
104
|
+
if (!existsSync(artifactPath)) return [];
|
|
105
|
+
try {
|
|
106
|
+
const status = execFileSync("git", ["status", "--porcelain", "--", ".codex"], {
|
|
107
|
+
cwd: workdir,
|
|
108
|
+
encoding: "utf-8",
|
|
109
|
+
timeout: 1e4
|
|
110
|
+
}).trim();
|
|
111
|
+
const stat = statSync(artifactPath);
|
|
112
|
+
if (status.startsWith("?? ") && stat.isFile() && stat.size === 0) {
|
|
113
|
+
unlinkSync(artifactPath);
|
|
114
|
+
return [".codex"];
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
function stageFromCheckpoint(result) {
|
|
122
|
+
const explicitStage = nonEmptyString(result.stage);
|
|
123
|
+
if (explicitStage) return explicitStage;
|
|
124
|
+
const checkpoint = String(result.checkpoint || "");
|
|
125
|
+
if (checkpoint.startsWith("recon_")) return "recon";
|
|
126
|
+
if (checkpoint.startsWith("author_")) return "author";
|
|
127
|
+
if (checkpoint.startsWith("implement_")) return "implement";
|
|
128
|
+
if (checkpoint.startsWith("verify_")) return "verify";
|
|
129
|
+
if (checkpoint.startsWith("ship_")) return "ship";
|
|
130
|
+
if (checkpoint.includes("capture")) return "prove";
|
|
131
|
+
return "setup";
|
|
132
|
+
}
|
|
133
|
+
function stageFromWorkflowParams(params) {
|
|
134
|
+
const stage = nonEmptyString(params.advance_stage);
|
|
135
|
+
if (stage) return stage;
|
|
136
|
+
if (params.ship_after_verify) return "ship";
|
|
137
|
+
if (params.proof_assessment_json) return "verify";
|
|
138
|
+
if (params.implementation_notes) return "verify";
|
|
139
|
+
if (params.author_packet_json) return "implement";
|
|
140
|
+
if (params.recon_assessment_json) return "author";
|
|
141
|
+
return "setup";
|
|
142
|
+
}
|
|
143
|
+
function baseContinuation(result) {
|
|
144
|
+
return {
|
|
145
|
+
action: "run",
|
|
146
|
+
state_path: String(result.state_path || ""),
|
|
147
|
+
continue_from_checkpoint: true
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function initialRunParams(request, input, state) {
|
|
151
|
+
return compactRecord({
|
|
152
|
+
action: "run",
|
|
153
|
+
repo: request.repo,
|
|
154
|
+
branch: request.branch,
|
|
155
|
+
change_request: request.change_request,
|
|
156
|
+
commit_message: request.commit_message,
|
|
157
|
+
prod_url: request.prod_url,
|
|
158
|
+
capture_script: request.capture_script,
|
|
159
|
+
success_criteria: request.success_criteria,
|
|
160
|
+
assertions_json: typeof request.assertions === "string" ? request.assertions : request.assertions === void 0 ? void 0 : JSON.stringify(request.assertions),
|
|
161
|
+
verification_mode: request.verification_mode,
|
|
162
|
+
reference: request.reference,
|
|
163
|
+
base_branch: request.base_branch,
|
|
164
|
+
before_ref: request.before_ref,
|
|
165
|
+
allow_static_preview_fallback: request.allow_static_preview_fallback,
|
|
166
|
+
context: request.context,
|
|
167
|
+
reviewer: request.reviewer,
|
|
168
|
+
mode: request.mode,
|
|
169
|
+
build_command: request.build_command,
|
|
170
|
+
build_output: request.build_output,
|
|
171
|
+
server_image: request.server_image,
|
|
172
|
+
server_command: request.server_command,
|
|
173
|
+
server_port: request.server_port,
|
|
174
|
+
server_path: request.server_path,
|
|
175
|
+
use_auth: request.use_auth,
|
|
176
|
+
color_scheme: request.color_scheme,
|
|
177
|
+
wait_for_selector: request.wait_for_selector,
|
|
178
|
+
discord_channel: request.integration_context?.channel_id,
|
|
179
|
+
discord_thread_id: request.integration_context?.thread_id,
|
|
180
|
+
discord_message_id: request.integration_context?.message_id,
|
|
181
|
+
discord_source_url: request.integration_context?.source_url,
|
|
182
|
+
state_path: request.engine_state_path || state.request.engine_state_path,
|
|
183
|
+
auto_approve: input.auto_approve ?? request.auto_approve
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function effectiveShipMode(request, config) {
|
|
187
|
+
return request.ship_mode || config?.defaultShipMode || "ship";
|
|
188
|
+
}
|
|
189
|
+
function checkpointContinueStage(result) {
|
|
190
|
+
const resume = recordValue(result.checkpointContract?.resume);
|
|
191
|
+
return nonEmptyString(resume?.continue_with_stage);
|
|
192
|
+
}
|
|
193
|
+
function recommendedContinuation(result) {
|
|
194
|
+
const continueStage = checkpointContinueStage(result);
|
|
195
|
+
if (!continueStage) return null;
|
|
196
|
+
return {
|
|
197
|
+
action: "run",
|
|
198
|
+
state_path: String(result.state_path || ""),
|
|
199
|
+
advance_stage: continueStage
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function defaultAwaitingStageContinuation(result) {
|
|
203
|
+
const contract = recordValue(result.checkpointContract) || {};
|
|
204
|
+
const stage = nonEmptyString(contract.stage) || nonEmptyString(result.stage) || "";
|
|
205
|
+
const nextStage = stage === "setup" ? "recon" : stage === "recon" ? "author" : stage === "author" ? "implement" : stage === "implement" || stage === "verify" ? "verify" : "";
|
|
206
|
+
if (!nextStage) return null;
|
|
207
|
+
return {
|
|
208
|
+
action: "run",
|
|
209
|
+
state_path: String(result.state_path || ""),
|
|
210
|
+
advance_stage: nextStage
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function isReadyShipGate(result) {
|
|
214
|
+
const gate = recordValue(result.shipGate) || recordValue(result.checkpointContract?.ship_gate);
|
|
215
|
+
return Boolean(gate && gate.ok === true);
|
|
216
|
+
}
|
|
217
|
+
function proofAssessmentRequestsShip(payload) {
|
|
218
|
+
const decision = String(payload.decision || "");
|
|
219
|
+
const recommendedStage = String(payload.recommended_stage || "");
|
|
220
|
+
const continueStage = String(payload.continue_with_stage || "");
|
|
221
|
+
return decision === "ready_to_ship" || recommendedStage === "ship" || continueStage === "ship";
|
|
222
|
+
}
|
|
223
|
+
function proofAssessmentContinuation(request, result, payload, config) {
|
|
224
|
+
const proof_assessment_json = jsonParam(payload);
|
|
225
|
+
if (effectiveShipMode(request, config) === "ship" || !proofAssessmentRequestsShip(payload)) {
|
|
226
|
+
return { ...baseContinuation(result), proof_assessment_json };
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
action: "run",
|
|
230
|
+
state_path: String(result.state_path || ""),
|
|
231
|
+
advance_stage: "verify",
|
|
232
|
+
proof_assessment_json
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function contextFor(request, state, result) {
|
|
236
|
+
return {
|
|
237
|
+
request,
|
|
238
|
+
state,
|
|
239
|
+
engineResult: result,
|
|
240
|
+
fullRiddleState: fullRiddleState(result, state),
|
|
241
|
+
checkpoint: String(result.checkpoint || "unknown")
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function requirePayload(action, payload, state, result) {
|
|
245
|
+
if (payload.blocker || payload.ok === false) {
|
|
246
|
+
return payload.blocker || {
|
|
247
|
+
code: `${action}_blocked`,
|
|
248
|
+
checkpoint: result.checkpoint || null,
|
|
249
|
+
message: payload.summary || `${action} did not return a usable payload.`
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (!payload.payload || typeof payload.payload !== "object") {
|
|
253
|
+
return {
|
|
254
|
+
code: `${action}_missing_payload`,
|
|
255
|
+
checkpoint: result.checkpoint || null,
|
|
256
|
+
message: `${action} did not return the JSON payload required by the riddle-proof checkpoint.`,
|
|
257
|
+
details: {
|
|
258
|
+
run_id: state.run_id,
|
|
259
|
+
state_path: state.state_path
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
function terminalResult(state, status, result, summary, raw = {}) {
|
|
266
|
+
setRunStatus(state, status);
|
|
267
|
+
const metadata = normalizeTerminalMetadata({
|
|
268
|
+
riddleState: result ? fullRiddleState(result, state) : null,
|
|
269
|
+
engineResult: result
|
|
270
|
+
});
|
|
271
|
+
applyTerminalMetadata(state, metadata);
|
|
272
|
+
persist(state);
|
|
273
|
+
return createRunResult({
|
|
274
|
+
state,
|
|
275
|
+
status,
|
|
276
|
+
last_summary: summary,
|
|
277
|
+
metadata,
|
|
278
|
+
raw: {
|
|
279
|
+
engine_state_path: result?.state_path || state.request.engine_state_path || null,
|
|
280
|
+
last_result: result,
|
|
281
|
+
...raw
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function blockerResult(state, result, blocker) {
|
|
286
|
+
state.blocker = blocker;
|
|
287
|
+
recordEvent(state, {
|
|
288
|
+
kind: "run.blocked",
|
|
289
|
+
checkpoint: blocker.checkpoint || result?.checkpoint || null,
|
|
290
|
+
stage: stageFromCheckpoint(result || {}),
|
|
291
|
+
summary: blocker.message,
|
|
292
|
+
details: {
|
|
293
|
+
code: blocker.code,
|
|
294
|
+
...blocker.details
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
setRunStatus(state, "blocked");
|
|
298
|
+
persist(state);
|
|
299
|
+
return createRunResult({
|
|
300
|
+
state,
|
|
301
|
+
status: "blocked",
|
|
302
|
+
last_summary: blocker.message,
|
|
303
|
+
raw: {
|
|
304
|
+
engine_state_path: result?.state_path || state.request.engine_state_path || null,
|
|
305
|
+
last_result: result
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function disabledAdapterPayload(action, context) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
blocker: {
|
|
313
|
+
code: "agent_adapter_not_configured",
|
|
314
|
+
checkpoint: context.checkpoint,
|
|
315
|
+
message: `No agent adapter is configured for ${action}. The engine harness reached the checkpoint safely and stopped before faking agent output.`,
|
|
316
|
+
details: {
|
|
317
|
+
run_id: context.state.run_id,
|
|
318
|
+
state_path: context.state.state_path,
|
|
319
|
+
engine_state_path: context.engineResult.state_path || null,
|
|
320
|
+
checkpointContract: context.engineResult.checkpointContract || null
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function createDisabledRiddleProofAgentAdapter() {
|
|
326
|
+
return {
|
|
327
|
+
assessRecon: (context) => Promise.resolve(disabledAdapterPayload("recon assessment", context)),
|
|
328
|
+
authorProofPacket: (context) => Promise.resolve(disabledAdapterPayload("proof packet authoring", context)),
|
|
329
|
+
implementChange: (context) => Promise.resolve(disabledAdapterPayload("implementation", context)),
|
|
330
|
+
assessProof: (context) => Promise.resolve(disabledAdapterPayload("proof assessment", context))
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
async function resolveEngine(input) {
|
|
334
|
+
if (typeof input.engine === "function") return input.engine();
|
|
335
|
+
if (input.engine) return input.engine;
|
|
336
|
+
const moduleUrl = input.config?.riddleEngineModuleUrl;
|
|
337
|
+
if (!moduleUrl) {
|
|
338
|
+
throw new Error("No riddle engine adapter or riddleEngineModuleUrl is configured.");
|
|
339
|
+
}
|
|
340
|
+
const mod = await import(moduleUrl);
|
|
341
|
+
if (typeof mod.createRiddleProofEngine !== "function") {
|
|
342
|
+
throw new Error(`Riddle engine module does not export createRiddleProofEngine: ${moduleUrl}`);
|
|
343
|
+
}
|
|
344
|
+
return mod.createRiddleProofEngine({
|
|
345
|
+
riddleProofDir: input.config?.riddleProofDir,
|
|
346
|
+
defaultReviewer: input.config?.defaultReviewer
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
async function handleImplementation(request, state, result, agent) {
|
|
350
|
+
const context = contextFor(request, state, result);
|
|
351
|
+
const workdir = workdirFromState(context.fullRiddleState);
|
|
352
|
+
state.worktree_path = workdir || state.worktree_path;
|
|
353
|
+
state.branch = nonEmptyString(context.fullRiddleState?.branch) || state.branch;
|
|
354
|
+
persist(state);
|
|
355
|
+
if (!workdir || !existsSync(workdir)) {
|
|
356
|
+
return {
|
|
357
|
+
blocker: {
|
|
358
|
+
code: "implementation_worktree_missing",
|
|
359
|
+
checkpoint: result.checkpoint || null,
|
|
360
|
+
message: "The Riddle Proof engine state does not include an isolated after worktree that exists on disk.",
|
|
361
|
+
details: {
|
|
362
|
+
worktree_path: workdir || null,
|
|
363
|
+
engine_state_path: result.state_path || null
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
const implementation = await agent.implementChange({ ...context, workdir });
|
|
369
|
+
if (implementation.blocker || implementation.ok === false) {
|
|
370
|
+
return {
|
|
371
|
+
blocker: implementation.blocker || {
|
|
372
|
+
code: "implementation_blocked",
|
|
373
|
+
checkpoint: result.checkpoint || null,
|
|
374
|
+
message: implementation.summary || "Implementation adapter did not complete."
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const cleanedArtifacts = removeEmptyToolArtifacts(workdir);
|
|
379
|
+
const diffDetected = implementation.diffDetected === true || hasGitDiff(workdir);
|
|
380
|
+
if (!diffDetected) {
|
|
381
|
+
return {
|
|
382
|
+
blocker: {
|
|
383
|
+
code: "implementation_diff_missing",
|
|
384
|
+
checkpoint: result.checkpoint || null,
|
|
385
|
+
message: "The implementation adapter returned, but the after worktree has no detectable git diff. The harness will not advance to verify.",
|
|
386
|
+
details: { worktree_path: workdir || null }
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
recordEvent(state, {
|
|
391
|
+
kind: "agent.implementation.completed",
|
|
392
|
+
checkpoint: result.checkpoint || null,
|
|
393
|
+
stage: "implement",
|
|
394
|
+
summary: implementation.summary || "Implementation adapter reported code changes.",
|
|
395
|
+
details: {
|
|
396
|
+
worktree_path: workdir || null,
|
|
397
|
+
diffDetected,
|
|
398
|
+
changed_files: implementation.changedFiles || [],
|
|
399
|
+
cleaned_artifacts: cleanedArtifacts
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
return {
|
|
403
|
+
next: compactRecord({
|
|
404
|
+
...baseContinuation(result),
|
|
405
|
+
advance_stage: "implement",
|
|
406
|
+
implementation_notes: implementation.implementationNotes || implementation.summary
|
|
407
|
+
})
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
async function routeCheckpoint(request, state, result, agent, input) {
|
|
411
|
+
const checkpoint = String(result.checkpoint || "");
|
|
412
|
+
const context = contextFor(request, state, result);
|
|
413
|
+
if (!checkpoint) {
|
|
414
|
+
return {
|
|
415
|
+
terminal: terminalResult(state, "completed", result, result.summary || "Riddle Proof engine completed.")
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if ([
|
|
419
|
+
"recon_human_escalation",
|
|
420
|
+
"verify_human_escalation",
|
|
421
|
+
"ship_gate_blocked",
|
|
422
|
+
"verify_required",
|
|
423
|
+
"verify_supervisor_judgment_required"
|
|
424
|
+
].includes(checkpoint) && result.ok === false) {
|
|
425
|
+
return {
|
|
426
|
+
blocker: {
|
|
427
|
+
code: checkpoint,
|
|
428
|
+
checkpoint,
|
|
429
|
+
message: result.summary || `Riddle Proof blocked at ${checkpoint}.`,
|
|
430
|
+
details: { checkpointContract: result.checkpointContract || null }
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if (checkpoint === "ship_review") {
|
|
435
|
+
return {
|
|
436
|
+
terminal: terminalResult(state, "shipped", result, result.summary || "Riddle Proof shipped.")
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
if (checkpoint === "verify_ship_ready") {
|
|
440
|
+
const shipMode = effectiveShipMode(request, input.config);
|
|
441
|
+
if (shipMode === "ship") {
|
|
442
|
+
if (!isReadyShipGate(result)) {
|
|
443
|
+
return {
|
|
444
|
+
blocker: {
|
|
445
|
+
code: "ship_gate_not_ready",
|
|
446
|
+
checkpoint,
|
|
447
|
+
message: "The harness reached verify_ship_ready, but the ship gate is not passing. It will not call ship.",
|
|
448
|
+
details: { shipGate: result.shipGate || result.checkpointContract?.ship_gate || null }
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
return { next: { ...baseContinuation(result), ship_after_verify: true } };
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
terminal: terminalResult(state, "ready_to_ship", result, result.summary || "Riddle Proof is ready to ship.", {
|
|
456
|
+
ship_held: true
|
|
457
|
+
})
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (input.dry_run || request.dry_run) {
|
|
461
|
+
return {
|
|
462
|
+
blocker: {
|
|
463
|
+
code: "dry_run_checkpoint",
|
|
464
|
+
checkpoint,
|
|
465
|
+
message: "Dry run stopped before applying agent input to the Riddle Proof workflow.",
|
|
466
|
+
details: { checkpointContract: result.checkpointContract || null }
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (checkpoint === "recon_supervisor_judgment") {
|
|
471
|
+
const assessment = await agent.assessRecon(context);
|
|
472
|
+
const blocker = requirePayload("recon_assessment", assessment, state, result);
|
|
473
|
+
if (blocker) return { blocker };
|
|
474
|
+
recordEvent(state, {
|
|
475
|
+
kind: "agent.recon_assessment.completed",
|
|
476
|
+
checkpoint,
|
|
477
|
+
stage: "recon",
|
|
478
|
+
summary: assessment.summary,
|
|
479
|
+
details: { payload: assessment.payload }
|
|
480
|
+
});
|
|
481
|
+
return {
|
|
482
|
+
next: { ...baseContinuation(result), recon_assessment_json: jsonParam(assessment.payload) }
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
const continueStage = checkpointContinueStage(result);
|
|
486
|
+
const checkpointContinuesToAuthor = continueStage === "author";
|
|
487
|
+
if (checkpoint === "author_supervisor_judgment" || checkpoint === "verify_capture_retry" || checkpoint === "verify_agent_retry" && checkpointContinuesToAuthor) {
|
|
488
|
+
const packet = await agent.authorProofPacket(context);
|
|
489
|
+
const blocker = requirePayload("author_packet", packet, state, result);
|
|
490
|
+
if (blocker) return { blocker };
|
|
491
|
+
recordEvent(state, {
|
|
492
|
+
kind: "agent.author_packet.completed",
|
|
493
|
+
checkpoint,
|
|
494
|
+
stage: "author",
|
|
495
|
+
summary: packet.summary,
|
|
496
|
+
details: { payload: packet.payload }
|
|
497
|
+
});
|
|
498
|
+
return {
|
|
499
|
+
next: { ...baseContinuation(result), author_packet_json: jsonParam(packet.payload) }
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
if (checkpoint === "implement_changes_missing" || checkpoint === "implement_required" || checkpoint === "verify_agent_retry" && continueStage === "implement") {
|
|
503
|
+
return handleImplementation(request, state, result, agent);
|
|
504
|
+
}
|
|
505
|
+
if (checkpoint === "implement_review") {
|
|
506
|
+
return { next: { action: "run", state_path: String(result.state_path || ""), advance_stage: "verify" } };
|
|
507
|
+
}
|
|
508
|
+
if (checkpoint === "verify_supervisor_judgment") {
|
|
509
|
+
const assessment = await agent.assessProof(context);
|
|
510
|
+
const blocker = requirePayload("proof_assessment", assessment, state, result);
|
|
511
|
+
if (blocker) return { blocker };
|
|
512
|
+
const payload = assessment.payload;
|
|
513
|
+
recordEvent(state, {
|
|
514
|
+
kind: "agent.proof_assessment.completed",
|
|
515
|
+
checkpoint,
|
|
516
|
+
stage: "verify",
|
|
517
|
+
summary: assessment.summary,
|
|
518
|
+
details: { payload }
|
|
519
|
+
});
|
|
520
|
+
return { next: proofAssessmentContinuation(request, result, payload, input.config) };
|
|
521
|
+
}
|
|
522
|
+
if (checkpoint === "verify_agent_retry") {
|
|
523
|
+
const next = recommendedContinuation(result);
|
|
524
|
+
if (next) return { next };
|
|
525
|
+
}
|
|
526
|
+
if (checkpoint === "awaiting_stage_advance") {
|
|
527
|
+
const next = recommendedContinuation(result) || defaultAwaitingStageContinuation(result);
|
|
528
|
+
if (next) {
|
|
529
|
+
if (String(next.advance_stage || "") === "ship" && effectiveShipMode(request, input.config) !== "ship") {
|
|
530
|
+
return {
|
|
531
|
+
terminal: terminalResult(state, "ready_to_ship", result, result.summary || "Riddle Proof is ready to ship.", {
|
|
532
|
+
ship_held: true
|
|
533
|
+
})
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
return { next };
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (checkpoint.endsWith("_review")) {
|
|
540
|
+
const next = recommendedContinuation(result);
|
|
541
|
+
if (next) return { next };
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
blocker: {
|
|
545
|
+
code: "unhandled_checkpoint",
|
|
546
|
+
checkpoint,
|
|
547
|
+
message: `The harness does not yet know how to safely continue checkpoint ${checkpoint}.`,
|
|
548
|
+
details: { checkpointContract: result.checkpointContract || null }
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function readRiddleProofRunStatus(state_path) {
|
|
553
|
+
const state = readJson(state_path);
|
|
554
|
+
if (state?.version !== "riddle-proof.run-state.v1" || !Array.isArray(state.events)) return null;
|
|
555
|
+
return createRunStatusSnapshot(state);
|
|
556
|
+
}
|
|
557
|
+
async function runRiddleProofEngineHarness(input) {
|
|
558
|
+
const state = loadRunState(input);
|
|
559
|
+
state.request = normalizeRunParams({ ...state.request, ...input.request });
|
|
560
|
+
const request = state.request;
|
|
561
|
+
const agent = input.agent || createDisabledRiddleProofAgentAdapter();
|
|
562
|
+
const maxIterations = Math.max(
|
|
563
|
+
1,
|
|
564
|
+
Math.trunc(input.max_iterations ?? request.max_iterations ?? input.config?.defaultMaxIterations ?? 8)
|
|
565
|
+
);
|
|
566
|
+
state.status = "running";
|
|
567
|
+
state.ok = void 0;
|
|
568
|
+
state.blocker = void 0;
|
|
569
|
+
persist(state);
|
|
570
|
+
recordEvent(state, {
|
|
571
|
+
kind: "engine_harness.started",
|
|
572
|
+
checkpoint: "engine_harness_started",
|
|
573
|
+
stage: "setup",
|
|
574
|
+
summary: "Riddle Proof engine harness started.",
|
|
575
|
+
details: {
|
|
576
|
+
run_id: state.run_id,
|
|
577
|
+
state_path: state.state_path,
|
|
578
|
+
engine_state_path: request.engine_state_path || null,
|
|
579
|
+
max_iterations: maxIterations,
|
|
580
|
+
ship_mode: effectiveShipMode(request, input.config)
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
let engine;
|
|
584
|
+
try {
|
|
585
|
+
engine = await resolveEngine(input);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
588
|
+
return blockerResult(state, null, {
|
|
589
|
+
code: "riddle_engine_not_configured",
|
|
590
|
+
checkpoint: "engine_resolve_failed",
|
|
591
|
+
message
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
let nextParams = input.resume_params || initialRunParams(request, input, state);
|
|
595
|
+
let lastResult = null;
|
|
596
|
+
for (let index = 0; index < maxIterations; index += 1) {
|
|
597
|
+
state.iterations += 1;
|
|
598
|
+
const stage = stageFromWorkflowParams(nextParams);
|
|
599
|
+
heartbeat(state, {
|
|
600
|
+
stage,
|
|
601
|
+
summary: `${stage} stage is active.`,
|
|
602
|
+
details: {
|
|
603
|
+
iteration: state.iterations,
|
|
604
|
+
run_id: state.run_id,
|
|
605
|
+
state_path: state.state_path,
|
|
606
|
+
engine_state_path: nextParams.state_path || null,
|
|
607
|
+
worktree_path: state.worktree_path || null,
|
|
608
|
+
branch: state.branch || null
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
recordEvent(state, {
|
|
612
|
+
kind: "engine.call",
|
|
613
|
+
checkpoint: "engine_call",
|
|
614
|
+
stage,
|
|
615
|
+
summary: "Calling Riddle Proof engine.",
|
|
616
|
+
details: { params: nextParams }
|
|
617
|
+
});
|
|
618
|
+
let result;
|
|
619
|
+
try {
|
|
620
|
+
result = await engine.execute(nextParams);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
623
|
+
return blockerResult(state, lastResult, {
|
|
624
|
+
code: "riddle_engine_exception",
|
|
625
|
+
checkpoint: "engine_call_failed",
|
|
626
|
+
message
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
lastResult = result;
|
|
630
|
+
const engineState = engineStatePath(result, state);
|
|
631
|
+
if (engineState) state.request.engine_state_path = engineState;
|
|
632
|
+
state.last_checkpoint = result.checkpoint || state.last_checkpoint || null;
|
|
633
|
+
const resultStage = stageFromCheckpoint(result);
|
|
634
|
+
heartbeat(state, {
|
|
635
|
+
stage: resultStage,
|
|
636
|
+
summary: `${resultStage} stage is active.`,
|
|
637
|
+
details: {
|
|
638
|
+
iteration: state.iterations,
|
|
639
|
+
run_id: state.run_id,
|
|
640
|
+
state_path: state.state_path,
|
|
641
|
+
engine_state_path: engineState || null,
|
|
642
|
+
checkpoint: result.checkpoint || null
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
recordEvent(state, {
|
|
646
|
+
kind: "engine.result",
|
|
647
|
+
checkpoint: result.checkpoint || null,
|
|
648
|
+
stage: resultStage,
|
|
649
|
+
summary: result.summary,
|
|
650
|
+
details: {
|
|
651
|
+
ok: result.ok ?? null,
|
|
652
|
+
engine_state_path: engineState || null,
|
|
653
|
+
checkpoint: result.checkpoint || null
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
const routed = await routeCheckpoint(request, state, result, agent, input);
|
|
657
|
+
if (routed.terminal) return routed.terminal;
|
|
658
|
+
if (routed.blocker) return blockerResult(state, result, routed.blocker);
|
|
659
|
+
if (!routed.next) {
|
|
660
|
+
return blockerResult(state, result, {
|
|
661
|
+
code: "missing_next_step",
|
|
662
|
+
checkpoint: result.checkpoint || null,
|
|
663
|
+
message: "The harness route returned no next step."
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
nextParams = routed.next;
|
|
667
|
+
}
|
|
668
|
+
return blockerResult(state, lastResult, {
|
|
669
|
+
code: "max_iterations_reached",
|
|
670
|
+
checkpoint: lastResult?.checkpoint || null,
|
|
671
|
+
message: `The harness reached max_iterations=${maxIterations} before the proof was ready or shipped.`,
|
|
672
|
+
details: {
|
|
673
|
+
nextParams,
|
|
674
|
+
lastCheckpoint: lastResult?.checkpoint || null,
|
|
675
|
+
lastSummary: lastResult?.summary || null
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export {
|
|
681
|
+
createDisabledRiddleProofAgentAdapter,
|
|
682
|
+
readRiddleProofRunStatus,
|
|
683
|
+
runRiddleProofEngineHarness
|
|
684
|
+
};
|