@riddledc/riddle-proof 0.5.1 → 0.5.3

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/index.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,2585 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/proof-run-core.ts
34
+ function currentDistDir() {
35
+ const meta = typeof import_meta === "object" ? import_meta : {};
36
+ if (typeof meta.url === "string" && meta.url) {
37
+ return import_node_path.default.dirname((0, import_node_url.fileURLToPath)(meta.url));
38
+ }
39
+ if (typeof __dirname === "string") return __dirname;
40
+ return process.cwd();
41
+ }
42
+ function createWorkflowStatePath() {
43
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
44
+ return `/tmp/riddle-proof-state-${stamp}-${(0, import_node_crypto.randomUUID)().slice(0, 8)}.json`;
45
+ }
46
+ function argsPathForStatePath(statePath) {
47
+ const base = import_node_path.default.basename(statePath);
48
+ if (base.startsWith("riddle-proof-state")) {
49
+ return import_node_path.default.join(import_node_path.default.dirname(statePath), base.replace("riddle-proof-state", "riddle-proof-args"));
50
+ }
51
+ return import_node_path.default.join(import_node_path.default.dirname(statePath), `${base}.args.json`);
52
+ }
53
+ function isRiddleProofSkillDir(candidate) {
54
+ return (0, import_node_fs.existsSync)(workflowFile(candidate, "setup"));
55
+ }
56
+ function resolveRiddleProofDir(config = {}) {
57
+ if (config.riddleProofDir) return config.riddleProofDir;
58
+ const candidates = [
59
+ process.env.RIDDLE_PROOF_DIR,
60
+ ...RIDDLE_PROOF_DIR_CANDIDATES
61
+ ].filter((candidate) => Boolean(candidate));
62
+ return candidates.find(isRiddleProofSkillDir) || candidates.find((candidate) => (0, import_node_fs.existsSync)(candidate)) || RIDDLE_PROOF_DIR_CANDIDATES[0];
63
+ }
64
+ function resolveConfig(config = {}, params = {}) {
65
+ const configuredStatePath = config.statePath || "";
66
+ const shouldIsolateWorkflow = !params.state_path && !configuredStatePath && (params.action === "setup" || params.action === "run");
67
+ const statePath = params.state_path || (shouldIsolateWorkflow ? createWorkflowStatePath() : configuredStatePath || "/tmp/riddle-proof-state.json");
68
+ return {
69
+ riddleProofDir: resolveRiddleProofDir(config),
70
+ statePath,
71
+ argsPath: argsPathForStatePath(statePath),
72
+ defaultReviewer: config.defaultReviewer || "davisdiehl"
73
+ };
74
+ }
75
+ function ensureAction(action) {
76
+ if (["setup", "recon", "author", "implement", "verify", "ship", "status", "sync", "run"].includes(action)) {
77
+ return action;
78
+ }
79
+ throw new Error(`Unsupported action: ${action}`);
80
+ }
81
+ function workflowFile(riddleProofDir, action) {
82
+ return import_node_path.default.join(riddleProofDir, "pipelines", `riddle-proof-${action}.lobster`);
83
+ }
84
+ function buildSetupArgs(params, config) {
85
+ if (!params.repo) throw new Error("repo is required for setup/run");
86
+ if (!params.change_request) throw new Error("change_request is required for setup/run");
87
+ const commitMessage = (params.commit_message || params.change_request || "").trim();
88
+ const captureScript = (params.capture_script || "").trim();
89
+ const requestedReference = params.reference || (params.prod_url ? "both" : "before");
90
+ const reference = !params.prod_url && requestedReference !== "before" ? "before" : requestedReference;
91
+ if (!commitMessage) throw new Error("commit_message is required for setup/run");
92
+ return {
93
+ repo: params.repo,
94
+ branch: params.branch || "",
95
+ change_request: params.change_request,
96
+ commit_message: commitMessage,
97
+ prod_url: params.prod_url || "",
98
+ capture_script: captureScript,
99
+ success_criteria: params.success_criteria || "",
100
+ assertions_json: params.assertions_json || "",
101
+ verification_mode: params.verification_mode || "proof",
102
+ reference,
103
+ base_branch: params.base_branch || "main",
104
+ before_ref: params.before_ref || "",
105
+ allow_static_preview_fallback: params.allow_static_preview_fallback ? "true" : "",
106
+ context: params.context || "",
107
+ reviewer: params.reviewer || config.defaultReviewer,
108
+ mode: params.mode || "",
109
+ build_command: params.build_command || "npm run build",
110
+ build_output: params.build_output || "build",
111
+ server_image: params.server_image || "node:20-slim",
112
+ server_command: params.server_command || "npm start",
113
+ server_port: String(params.server_port || 3e3),
114
+ server_path: params.server_path || "",
115
+ server_path_source: params.server_path ? "user" : "",
116
+ use_auth: params.use_auth ? "true" : "",
117
+ auth_localStorage_json: params.auth_localStorage_json || "",
118
+ auth_cookies_json: params.auth_cookies_json || "",
119
+ auth_headers_json: params.auth_headers_json || "",
120
+ color_scheme: params.color_scheme || "",
121
+ wait_for_selector: params.wait_for_selector || "",
122
+ discord_channel: params.discord_channel || "",
123
+ discord_thread_id: params.discord_thread_id || "",
124
+ discord_message_id: params.discord_message_id || "",
125
+ discord_source_url: params.discord_source_url || "",
126
+ leave_draft: params.leave_draft ? "true" : ""
127
+ };
128
+ }
129
+ function readState(statePath) {
130
+ if (!(0, import_node_fs.existsSync)(statePath)) {
131
+ return null;
132
+ }
133
+ return JSON.parse((0, import_node_fs.readFileSync)(statePath, "utf-8"));
134
+ }
135
+ function writeState(statePath, state) {
136
+ (0, import_node_fs.writeFileSync)(statePath, JSON.stringify(state, null, 2));
137
+ }
138
+ function normalizeOptionalString(value) {
139
+ return typeof value === "string" ? value.trim() : void 0;
140
+ }
141
+ function knownEnvironmentIssuesFromNotes(notes) {
142
+ const text = notes.toLowerCase();
143
+ const issues = [];
144
+ if ((text.includes("erofs") || text.includes("read-only file system")) && text.includes("node_modules") && (text.includes(".vite-temp") || text.includes("vite.config"))) {
145
+ issues.push({
146
+ code: "vite_temp_config_erofs",
147
+ source: "implementation_notes",
148
+ severity: "environment",
149
+ summary: "Focused build verification hit the known Vite temp-config EROFS issue in shared node_modules."
150
+ });
151
+ }
152
+ return issues;
153
+ }
154
+ function guardProofEvidenceGlobalAssignments(script) {
155
+ return script.replace(
156
+ /^(\s*)(globalThis|window|self)\.__riddleProofEvidence\s*=\s*([^;\n]+);\s*$/gm,
157
+ (_match, indent, root, expression) => `${indent}try { if (typeof ${root} !== "undefined" && ${root}) ${root}.__riddleProofEvidence = ${expression.trim()}; } catch {}`
158
+ );
159
+ }
160
+ function normalizeCaptureScript(value) {
161
+ const script = normalizeOptionalString(value) || "";
162
+ return script ? guardProofEvidenceGlobalAssignments(script) : "";
163
+ }
164
+ function appendProofSummaryLine(state, line) {
165
+ const text = String(line || "").trim();
166
+ if (!text) return;
167
+ const existing = typeof state.proof_summary === "string" ? state.proof_summary.trim() : "";
168
+ if (existing.includes(text)) return;
169
+ state.proof_summary = existing ? `${existing}
170
+ ${text}` : text;
171
+ }
172
+ function hasAuthoredProofPlan(state = {}) {
173
+ return Boolean((state?.proof_plan || "").trim()) && Boolean((state?.capture_script || "").trim());
174
+ }
175
+ function syncAuthoringState(state = {}) {
176
+ const reconReady = ["ready_for_proof_plan", "completed"].includes(state?.recon_status || "");
177
+ const reconBlocked = ["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "");
178
+ const reconExhausted = state?.recon_status === "exhausted";
179
+ if (reconBlocked) {
180
+ state.author_status = "needs_recon_judgment";
181
+ } else if (reconExhausted) {
182
+ state.author_status = "recon_exhausted";
183
+ } else if (!reconReady) {
184
+ state.author_status = state.author_status || "pending_recon";
185
+ } else if (state.author_status === "ready" || state.proof_plan_status === "ready") {
186
+ state.author_status = "ready";
187
+ } else {
188
+ state.author_status = "needs_authoring";
189
+ }
190
+ if (reconBlocked) {
191
+ state.proof_plan_status = "needs_recon_judgment";
192
+ } else if (reconExhausted) {
193
+ state.proof_plan_status = "recon_exhausted";
194
+ } else if (state.author_status === "ready" || state.proof_plan_status === "ready") {
195
+ state.proof_plan_status = "ready";
196
+ } else if (reconReady) {
197
+ state.proof_plan_status = "needs_authoring";
198
+ } else {
199
+ state.proof_plan_status = state.proof_plan_status || "pending_recon";
200
+ }
201
+ state.author_request = state.author_request || {};
202
+ state.author_summary = state.author_summary || "";
203
+ return state;
204
+ }
205
+ function ensureStageLoopState(state = {}) {
206
+ if (!state || typeof state !== "object") return state;
207
+ syncAuthoringState(state);
208
+ state.explicit_stage_gate = true;
209
+ state.stage_attempts = state.stage_attempts || {};
210
+ for (const stage of WORKFLOW_STAGE_ORDER) {
211
+ const current = state.stage_attempts[stage] || {};
212
+ state.stage_attempts[stage] = {
213
+ count: Number(current.count || 0),
214
+ last_status: current.last_status || null,
215
+ last_checkpoint: current.last_checkpoint || null,
216
+ last_summary: current.last_summary || null,
217
+ last_attempted_at: current.last_attempted_at || null,
218
+ history: Array.isArray(current.history) ? current.history : []
219
+ };
220
+ }
221
+ state.stage_decision_request = state.stage_decision_request || {};
222
+ state.active_checkpoint = state.active_checkpoint || null;
223
+ state.active_checkpoint_stage = state.active_checkpoint_stage || null;
224
+ state.last_requested_advance_stage = state.last_requested_advance_stage || null;
225
+ return state;
226
+ }
227
+ function clearStageDecisionRequest(state = {}) {
228
+ ensureStageLoopState(state);
229
+ state.stage_decision_request = {};
230
+ state.active_checkpoint = null;
231
+ state.active_checkpoint_stage = null;
232
+ return state;
233
+ }
234
+ function recordStageAttempt(state, stage, entry = {}) {
235
+ ensureStageLoopState(state);
236
+ const bucket = state.stage_attempts[stage];
237
+ const attemptNumber = Number(bucket.count || 0) + 1;
238
+ const item = {
239
+ attempt: attemptNumber,
240
+ stage,
241
+ status: entry.status || "completed",
242
+ checkpoint: entry.checkpoint || null,
243
+ summary: entry.summary || null,
244
+ requested_advance_stage: entry.requestedAdvanceStage || null,
245
+ halted_for_approval: Boolean(entry.haltedForApproval),
246
+ auto_approved: Boolean(entry.autoApproved),
247
+ error: entry.error || null,
248
+ details: entry.details || {},
249
+ attempted_at: (/* @__PURE__ */ new Date()).toISOString()
250
+ };
251
+ bucket.count = attemptNumber;
252
+ bucket.last_status = item.status;
253
+ bucket.last_checkpoint = item.checkpoint;
254
+ bucket.last_summary = item.summary;
255
+ bucket.last_attempted_at = item.attempted_at;
256
+ bucket.history = [...bucket.history, item].slice(-25);
257
+ state.stage_attempts[stage] = bucket;
258
+ state.last_requested_advance_stage = entry.requestedAdvanceStage || state.last_requested_advance_stage || null;
259
+ return item;
260
+ }
261
+ function setStageDecisionRequest(state, request) {
262
+ ensureStageLoopState(state);
263
+ const continueWithStage = request.continueWithStage || request.recommendedAdvanceStage || null;
264
+ state.active_checkpoint = request.checkpoint;
265
+ state.active_checkpoint_stage = request.stage;
266
+ state.stage_decision_request = {
267
+ stage: request.stage,
268
+ checkpoint: request.checkpoint,
269
+ summary: request.summary,
270
+ next_actions: request.nextActions || [],
271
+ advance_options: request.advanceOptions || [],
272
+ recommended_advance_stage: request.recommendedAdvanceStage || null,
273
+ continue_from_checkpoint: Boolean(continueWithStage),
274
+ continue_with_stage: continueWithStage,
275
+ blocking: Boolean(request.blocking),
276
+ details: request.details || {},
277
+ checkpoint_contract: request.checkpointContract || null,
278
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
279
+ };
280
+ return state.stage_decision_request;
281
+ }
282
+ function checkpointContinueStage(state) {
283
+ ensureStageLoopState(state);
284
+ const stage = state?.stage_decision_request?.continue_with_stage || state?.stage_decision_request?.recommended_advance_stage || null;
285
+ return WORKFLOW_STAGE_ORDER.includes(stage) ? stage : null;
286
+ }
287
+ function invalidateVerifyEvidence(state = {}) {
288
+ if (!state || typeof state !== "object") {
289
+ return { invalidated: false };
290
+ }
291
+ const hadAfterCdn = typeof state.after_cdn === "string" && state.after_cdn.trim().length > 0;
292
+ const hadVerifyResults = Boolean(state.verify_results && Object.keys(state.verify_results).length > 0);
293
+ const hadMergeRecommendation = typeof state.merge_recommendation === "string" && state.merge_recommendation.trim().length > 0;
294
+ const hadProofSummary = typeof state.proof_summary === "string" && state.proof_summary.trim().length > 0;
295
+ const hadVerifyStatus = typeof state.verify_status === "string" && state.verify_status.trim().length > 0;
296
+ const hadVerifySummary = typeof state.verify_summary === "string" && state.verify_summary.trim().length > 0;
297
+ const hadVerifyDecisionRequest = Boolean(state.verify_decision_request && Object.keys(state.verify_decision_request).length > 0);
298
+ const hadEvidenceNotes = Array.isArray(state.evidence_notes) && state.evidence_notes.length > 0;
299
+ const hadProofAssessment = Boolean(state.proof_assessment && Object.keys(state.proof_assessment).length > 0);
300
+ const hadProofAssessmentRequest = Boolean(state.proof_assessment_request && Object.keys(state.proof_assessment_request).length > 0);
301
+ const invalidated = hadAfterCdn || hadVerifyResults || hadMergeRecommendation || hadProofSummary || hadVerifyStatus || hadVerifySummary || hadVerifyDecisionRequest || hadEvidenceNotes || hadProofAssessment || hadProofAssessmentRequest;
302
+ if (invalidated) {
303
+ state.after_cdn = "";
304
+ state.verify_results = {};
305
+ state.verify_status = "";
306
+ state.verify_summary = "";
307
+ state.verify_decision_request = {};
308
+ state.merge_recommendation = null;
309
+ state.proof_summary = "";
310
+ state.evidence_notes = [];
311
+ state.proof_assessment = {};
312
+ state.proof_assessment_source = null;
313
+ state.proof_assessment_request = {};
314
+ }
315
+ return {
316
+ invalidated,
317
+ hadAfterCdn,
318
+ hadVerifyResults,
319
+ hadMergeRecommendation,
320
+ hadProofSummary,
321
+ hadVerifyStatus,
322
+ hadVerifySummary,
323
+ hadVerifyDecisionRequest,
324
+ hadEvidenceNotes,
325
+ hadProofAssessment,
326
+ hadProofAssessmentRequest
327
+ };
328
+ }
329
+ function normalizedReference(state = {}) {
330
+ const reference = String(state?.requested_reference || state?.reference || "before").trim();
331
+ return reference || "before";
332
+ }
333
+ function normalizedProofAssessment(state = {}) {
334
+ const proofAssessment = state?.proof_assessment || {};
335
+ const source = String(proofAssessment?.source || state?.proof_assessment_source || "").trim().toLowerCase();
336
+ const decision = String(proofAssessment?.decision || "").trim();
337
+ return {
338
+ decision: decision || null,
339
+ source: source || null
340
+ };
341
+ }
342
+ function requiredBaselineLabelsForState(state = {}) {
343
+ const reference = normalizedReference(state);
344
+ const labels = [];
345
+ if (reference === "before" || reference === "both") labels.push("before");
346
+ if (reference === "prod" || reference === "both") labels.push("prod");
347
+ return labels;
348
+ }
349
+ function validateShipGate(state = {}) {
350
+ const reference = normalizedReference(state);
351
+ const prodUrl = String(state?.prod_url || "").trim();
352
+ const beforeCdn = String(state?.before_cdn || "").trim();
353
+ const prodCdn = String(state?.prod_cdn || "").trim();
354
+ const afterCdn = String(state?.after_cdn || "").trim();
355
+ const verifyStatus = String(state?.verify_status || "").trim();
356
+ const proofAssessment = normalizedProofAssessment(state);
357
+ const reasons = [];
358
+ if (!["before", "prod", "both"].includes(reference)) {
359
+ reasons.push(`reference must be before, prod, or both; got ${reference}`);
360
+ }
361
+ const requiredBaselines = requiredBaselineLabelsForState(state);
362
+ if (requiredBaselines.includes("before") && !beforeCdn) {
363
+ reasons.push("before_cdn is required before ship");
364
+ }
365
+ if (requiredBaselines.includes("prod")) {
366
+ if (!prodUrl) {
367
+ reasons.push(`prod_url is required when reference=${reference}`);
368
+ }
369
+ if (!prodCdn) {
370
+ reasons.push("prod_cdn is required before ship");
371
+ }
372
+ }
373
+ if (!afterCdn) {
374
+ reasons.push("after_cdn is required before ship");
375
+ }
376
+ if (verifyStatus !== "evidence_captured") {
377
+ reasons.push("verify_status must be evidence_captured before ship");
378
+ }
379
+ if (!["supervising_agent", "supervisor"].includes(proofAssessment.source || "")) {
380
+ reasons.push("proof_assessment.source must be supervising_agent before ship");
381
+ }
382
+ if (proofAssessment.decision !== "ready_to_ship") {
383
+ reasons.push("proof_assessment.decision must be ready_to_ship before ship");
384
+ }
385
+ return {
386
+ ok: reasons.length === 0,
387
+ reasons,
388
+ required_baselines: requiredBaselines,
389
+ evidence: {
390
+ reference,
391
+ prod_url: prodUrl || null,
392
+ before_cdn: beforeCdn || null,
393
+ prod_cdn: prodCdn || null,
394
+ after_cdn: afterCdn || null,
395
+ verify_status: verifyStatus || null,
396
+ proof_assessment_decision: proofAssessment.decision,
397
+ proof_assessment_source: proofAssessment.source
398
+ }
399
+ };
400
+ }
401
+ function buildCheckpointContract(state, request) {
402
+ const spec = CHECKPOINT_CONTRACT_SPECS[request.checkpoint] || {
403
+ purpose: request.summary
404
+ };
405
+ const continueWithStage = request.continueWithStage || request.recommendedAdvanceStage || null;
406
+ const payload = {
407
+ version: CHECKPOINT_CONTRACT_VERSION,
408
+ checkpoint: request.checkpoint,
409
+ stage: request.stage,
410
+ purpose: spec.purpose,
411
+ summary: request.summary,
412
+ blocking: Boolean(request.blocking),
413
+ next_actions: request.nextActions || [],
414
+ advance_options: request.advanceOptions || [],
415
+ accepted_inputs: spec.accepted_inputs || [],
416
+ response_schema: spec.response_schema || null,
417
+ required_state: spec.required_state || [],
418
+ resume: {
419
+ action: "run",
420
+ state_path: request.statePath || null,
421
+ continue_from_checkpoint: Boolean(continueWithStage),
422
+ continue_with_stage: continueWithStage
423
+ }
424
+ };
425
+ if (spec.include_ship_gate) {
426
+ payload.ship_gate = validateShipGate(state);
427
+ }
428
+ return payload;
429
+ }
430
+ function mergeStateFromParams(statePath, params) {
431
+ const state = readState(statePath);
432
+ if (!state) return null;
433
+ ensureStageLoopState(state);
434
+ const stringFields = [
435
+ "change_request",
436
+ "commit_message",
437
+ "prod_url",
438
+ "capture_script",
439
+ "success_criteria",
440
+ "assertions_json",
441
+ "verification_mode",
442
+ "base_branch",
443
+ "before_ref",
444
+ "context",
445
+ "reviewer",
446
+ "build_command",
447
+ "build_output",
448
+ "server_image",
449
+ "server_command",
450
+ "server_path",
451
+ "wait_for_selector",
452
+ "discord_channel",
453
+ "discord_thread_id",
454
+ "discord_message_id",
455
+ "discord_source_url",
456
+ "auth_localStorage_json",
457
+ "auth_cookies_json",
458
+ "auth_headers_json",
459
+ "proof_plan",
460
+ "implementation_notes"
461
+ ];
462
+ for (const field of stringFields) {
463
+ if (params[field] !== void 0) {
464
+ state[field] = normalizeOptionalString(params[field]);
465
+ }
466
+ }
467
+ if (params.server_path !== void 0) {
468
+ state.server_path_source = "tool_param";
469
+ }
470
+ if (params.implementation_notes !== void 0) {
471
+ const issues = knownEnvironmentIssuesFromNotes(state.implementation_notes || "");
472
+ if (issues.length) state.implementation_environment_issues = issues;
473
+ }
474
+ if (params.reference !== void 0) state.reference = params.reference;
475
+ if (params.mode !== void 0) state.mode = params.mode;
476
+ if (params.allow_static_preview_fallback !== void 0) {
477
+ state.allow_static_preview_fallback = params.allow_static_preview_fallback;
478
+ }
479
+ if (params.server_port !== void 0) state.server_port = String(params.server_port);
480
+ if (params.color_scheme !== void 0) state.color_scheme = params.color_scheme || "";
481
+ if (params.use_auth !== void 0) state.use_auth = params.use_auth ? "true" : "";
482
+ if (params.leave_draft !== void 0) state.leave_draft = params.leave_draft ? "true" : "";
483
+ if (params.advance_stage !== void 0) state.last_requested_advance_stage = params.advance_stage;
484
+ if (params.recon_assessment_json !== void 0) {
485
+ const raw = normalizeOptionalString(params.recon_assessment_json) || "";
486
+ if (!raw) {
487
+ state.recon_assessment = {};
488
+ state.recon_assessment_source = null;
489
+ } else {
490
+ const parsed = JSON.parse(raw);
491
+ state.recon_assessment = {
492
+ ...parsed,
493
+ source: (parsed?.source || "supervising_agent").toString()
494
+ };
495
+ state.recon_assessment_source = state.recon_assessment.source;
496
+ if (parsed?.baseline_understanding && typeof parsed.baseline_understanding === "object") {
497
+ state.recon_baseline_understanding = parsed.baseline_understanding;
498
+ }
499
+ const refined = parsed?.refined_inputs || {};
500
+ if (typeof refined?.server_path === "string") {
501
+ state.server_path = normalizeOptionalString(refined.server_path) || "";
502
+ state.server_path_source = "supervising_agent";
503
+ }
504
+ if (typeof refined?.wait_for_selector === "string") state.wait_for_selector = normalizeOptionalString(refined.wait_for_selector) || "";
505
+ if (typeof refined?.reference === "string" && refined.reference.trim()) state.reference = refined.reference.trim();
506
+ }
507
+ }
508
+ if (params.author_packet_json !== void 0) {
509
+ const raw = normalizeOptionalString(params.author_packet_json) || "";
510
+ if (!raw) {
511
+ state.supervisor_author_packet = null;
512
+ } else {
513
+ const parsed = JSON.parse(raw);
514
+ if (typeof parsed?.capture_script === "string") {
515
+ parsed.capture_script = normalizeCaptureScript(parsed.capture_script);
516
+ }
517
+ state.supervisor_author_packet = parsed;
518
+ if (typeof parsed?.proof_plan === "string") state.proof_plan = normalizeOptionalString(parsed.proof_plan) || "";
519
+ if (typeof parsed?.capture_script === "string") state.capture_script = normalizeCaptureScript(parsed.capture_script);
520
+ if (parsed?.baseline_understanding_used && typeof parsed.baseline_understanding_used === "object") {
521
+ state.author_baseline_understanding_used = parsed.baseline_understanding_used;
522
+ }
523
+ const refined = parsed?.refined_inputs || {};
524
+ if (typeof refined?.server_path === "string") {
525
+ state.server_path = normalizeOptionalString(refined.server_path) || "";
526
+ state.server_path_source = "supervising_agent";
527
+ }
528
+ if (typeof refined?.wait_for_selector === "string") state.wait_for_selector = normalizeOptionalString(refined.wait_for_selector) || "";
529
+ if (typeof refined?.reference === "string" && refined.reference.trim()) state.reference = refined.reference.trim();
530
+ if (typeof parsed?.confidence === "string") state.supervisor_author_confidence = normalizeOptionalString(parsed.confidence) || null;
531
+ if (parsed?.rationale !== void 0) state.supervisor_author_rationale = parsed.rationale;
532
+ if (typeof parsed?.summary === "string") state.supervisor_author_summary = normalizeOptionalString(parsed.summary) || null;
533
+ invalidateVerifyEvidence(state);
534
+ }
535
+ }
536
+ if (params.proof_assessment_json !== void 0) {
537
+ const raw = normalizeOptionalString(params.proof_assessment_json) || "";
538
+ if (!raw) {
539
+ state.proof_assessment = {};
540
+ state.proof_assessment_source = null;
541
+ } else {
542
+ const parsed = JSON.parse(raw);
543
+ state.proof_assessment = {
544
+ ...parsed,
545
+ source: (parsed?.source || "supervising_agent").toString()
546
+ };
547
+ state.proof_assessment_source = state.proof_assessment.source;
548
+ if (typeof parsed?.decision === "string") {
549
+ state.proof_decision = parsed.decision;
550
+ }
551
+ if (typeof parsed?.summary === "string") {
552
+ state.proof_assessment_summary = normalizeOptionalString(parsed.summary) || null;
553
+ }
554
+ if (parsed?.decision === "ready_to_ship") {
555
+ state.merge_recommendation = "ready-to-ship";
556
+ } else if (typeof parsed?.decision === "string" && parsed.decision.trim()) {
557
+ state.merge_recommendation = "do-not-merge";
558
+ }
559
+ appendProofSummaryLine(state, `Supervising proof assessment: ${state.proof_assessment.decision || "unknown"}`);
560
+ if (state.proof_assessment_summary) {
561
+ appendProofSummaryLine(state, `Assessment summary: ${state.proof_assessment_summary}`);
562
+ }
563
+ const reasons = Array.isArray(parsed?.reasons) ? parsed.reasons.filter((item) => typeof item === "string" && item.trim()).slice(0, 4) : [];
564
+ if (reasons.length) {
565
+ appendProofSummaryLine(state, `Assessment reasons: ${reasons.join("; ")}`);
566
+ }
567
+ }
568
+ }
569
+ if (params.assertions_json !== void 0) {
570
+ const raw = normalizeOptionalString(params.assertions_json) || "";
571
+ if (!raw) {
572
+ state.parsed_assertions = null;
573
+ } else {
574
+ state.parsed_assertions = JSON.parse(raw);
575
+ }
576
+ }
577
+ if ((params.proof_plan !== void 0 || params.capture_script !== void 0) && hasAuthoredProofPlan(state)) {
578
+ state.author_summary = state.author_summary || "Proof authoring inputs were updated from tool params.";
579
+ }
580
+ syncAuthoringState(state);
581
+ writeState(statePath, state);
582
+ return state;
583
+ }
584
+ function summarizeState(state) {
585
+ if (!state) {
586
+ return {
587
+ stage: "missing",
588
+ summary: "No riddle-proof state file exists yet.",
589
+ state: null
590
+ };
591
+ }
592
+ ensureStageLoopState(state);
593
+ const attemptCounts = Object.fromEntries(
594
+ WORKFLOW_STAGE_ORDER.map((stage) => [stage, Number(state.stage_attempts?.[stage]?.count || 0)])
595
+ );
596
+ const selected = {
597
+ workspace_ready: Boolean(state.workspace_ready),
598
+ repo: state.repo || null,
599
+ branch: state.branch || null,
600
+ mode: state.mode || null,
601
+ reference: state.reference || null,
602
+ before_ref: state.before_ref || null,
603
+ allow_static_preview_fallback: Boolean(state.allow_static_preview_fallback),
604
+ commit_message: state.commit_message || null,
605
+ author_status: state.author_status || null,
606
+ author_summary: state.author_summary || null,
607
+ author_request: state.author_request || null,
608
+ proof_plan_status: state.proof_plan_status || null,
609
+ proof_plan: state.proof_plan || null,
610
+ proof_plan_request: state.proof_plan_request || null,
611
+ proof_profile_applied: Boolean(state.proof_profile),
612
+ proof_profile: state.proof_profile || null,
613
+ recon_status: state.recon_status || null,
614
+ recon_assessment: state.recon_assessment || null,
615
+ recon_assessment_request: state.recon_assessment_request || null,
616
+ recon_assessment_source: state.recon_assessment_source || null,
617
+ recon_decision_request: state.recon_decision_request || null,
618
+ recon_attempts_used: Array.isArray(state.recon_results?.attempt_history) ? state.recon_results.attempt_history.length : 0,
619
+ recon_attempts_max: state.recon_results?.max_attempts || null,
620
+ recon_hypothesis: state.recon_hypothesis || null,
621
+ implementation_status: state.implementation_status || null,
622
+ implementation_summary: state.implementation_summary || null,
623
+ implementation_environment_issues: state.implementation_environment_issues || [],
624
+ verify_status: state.verify_status || null,
625
+ verify_summary: state.verify_summary || null,
626
+ verify_decision_request: state.verify_decision_request || null,
627
+ proof_assessment: state.proof_assessment || null,
628
+ proof_assessment_request: state.proof_assessment_request || null,
629
+ proof_assessment_source: state.proof_assessment_source || null,
630
+ merge_recommendation: state.merge_recommendation || null,
631
+ before_cdn: state.before_cdn || null,
632
+ after_cdn: state.after_cdn || null,
633
+ prod_cdn: state.prod_cdn || null,
634
+ pr_url: state.pr_url || null,
635
+ pr_branch: state.target_branch || state.branch || null,
636
+ pr_state: state.pr_state || null,
637
+ ship_commit: state.ship_commit || null,
638
+ ship_remote_head: state.ship_remote_head || null,
639
+ merge_commit: state.merge_commit || null,
640
+ merged_at: state.merged_at || null,
641
+ ship_push: state.ship_push || null,
642
+ ship_report: state.ship_report || null,
643
+ cleanup_report: state.cleanup_report || null,
644
+ proof_comment_url: state.proof_comment_url || null,
645
+ proof_assessment_comment_url: state.proof_assessment_comment_url || null,
646
+ marked_ready: typeof state.marked_ready === "boolean" ? state.marked_ready : null,
647
+ left_draft: typeof state.left_draft === "boolean" ? state.left_draft : null,
648
+ ci_status: state.ci_status || null,
649
+ reviewer: state.reviewer || null,
650
+ active_checkpoint: state.active_checkpoint || null,
651
+ active_checkpoint_stage: state.active_checkpoint_stage || null,
652
+ continue_with_stage: checkpointContinueStage(state),
653
+ stage_decision_request: state.stage_decision_request || {},
654
+ stage_attempt_counts: attemptCounts,
655
+ explicit_stage_gate: Boolean(state.explicit_stage_gate),
656
+ last_requested_advance_stage: state.last_requested_advance_stage || null,
657
+ recon_results: state.recon_results || null,
658
+ verify_results: state.verify_results || null
659
+ };
660
+ const parts = [
661
+ state.workspace_ready ? "workspace ready" : "workspace not ready",
662
+ state.mode ? `mode=${state.mode}` : null,
663
+ state.reference ? `reference=${state.reference}` : null,
664
+ state.author_status ? `author=${state.author_status}` : null,
665
+ state.proof_plan_status ? `proof=${state.proof_plan_status}` : null,
666
+ state.recon_status ? `recon=${state.recon_status}` : null,
667
+ state.implementation_status ? `implement=${state.implementation_status}` : null,
668
+ state.verify_status ? `verify=${state.verify_status}` : null,
669
+ state.active_checkpoint ? `checkpoint=${state.active_checkpoint}` : null,
670
+ state.after_cdn ? "after evidence captured" : null,
671
+ state.pr_url ? "PR linked" : null
672
+ ].filter(Boolean);
673
+ return {
674
+ stage: state.stage || (state.after_cdn ? "verified" : state.workspace_ready ? "setup" : "unknown"),
675
+ summary: parts.length ? parts.join(", ") : "State file present.",
676
+ state: selected
677
+ };
678
+ }
679
+ var import_node_fs, import_node_crypto, import_node_path, import_node_url, import_meta, WORKFLOW_STAGE_ORDER, CHECKPOINT_CONTRACT_VERSION, BUNDLED_RIDDLE_PROOF_DIR, RIDDLE_PROOF_DIR_CANDIDATES, CHECKPOINT_CONTRACT_SPECS;
680
+ var init_proof_run_core = __esm({
681
+ "src/proof-run-core.ts"() {
682
+ "use strict";
683
+ import_node_fs = require("fs");
684
+ import_node_crypto = require("crypto");
685
+ import_node_path = __toESM(require("path"), 1);
686
+ import_node_url = require("url");
687
+ import_meta = {};
688
+ WORKFLOW_STAGE_ORDER = ["setup", "recon", "author", "implement", "verify", "ship"];
689
+ CHECKPOINT_CONTRACT_VERSION = "riddle-proof-run.checkpoint.v1";
690
+ BUNDLED_RIDDLE_PROOF_DIR = import_node_path.default.resolve(
691
+ currentDistDir(),
692
+ "..",
693
+ "runtime"
694
+ );
695
+ RIDDLE_PROOF_DIR_CANDIDATES = [
696
+ BUNDLED_RIDDLE_PROOF_DIR
697
+ ];
698
+ CHECKPOINT_CONTRACT_SPECS = {
699
+ setup_review: {
700
+ purpose: "Inspect prepared workspace state before moving into recon."
701
+ },
702
+ recon_supervisor_judgment: {
703
+ purpose: "Supervising agent judges the latest recon attempt and either retries recon, promotes baselines for authoring, or escalates.",
704
+ accepted_inputs: [{
705
+ name: "recon_assessment_json",
706
+ type: "json",
707
+ required: true,
708
+ description: "JSON assessment with decision, summary, baseline_understanding, continue_with_stage, escalation_target, refined_inputs, and reasons."
709
+ }],
710
+ response_schema: {
711
+ decision: ["retry_recon", "ready_for_author", "recon_stuck"],
712
+ summary: "string",
713
+ baseline_understanding: {
714
+ reference: ["before", "prod", "both", "unknown"],
715
+ target_route: "string",
716
+ before_evidence_url: "string",
717
+ visible_before_state: "string",
718
+ relevant_elements: ["string"],
719
+ requested_change: "string",
720
+ proof_focus: "string",
721
+ stop_condition: "string",
722
+ quality_risks: ["string"]
723
+ },
724
+ continue_with_stage: ["recon", "author"],
725
+ escalation_target: ["agent", "human"],
726
+ refined_inputs: {
727
+ server_path: "string",
728
+ wait_for_selector: "string",
729
+ reference: ["before", "prod", "both"]
730
+ },
731
+ reasons: ["string"],
732
+ source: "supervising_agent"
733
+ },
734
+ required_state: ["recon_assessment_request", "recon_results.attempt_history"]
735
+ },
736
+ recon_review: {
737
+ purpose: "Recon baselines were promoted and the workflow is ready for proof authoring."
738
+ },
739
+ recon_human_escalation: {
740
+ purpose: "Recon is explicitly blocked for human direction after supervising-agent escalation."
741
+ },
742
+ author_supervisor_judgment: {
743
+ purpose: "Supervising agent authors the proof packet from recon observations.",
744
+ accepted_inputs: [{
745
+ name: "author_packet_json",
746
+ type: "json",
747
+ required: true,
748
+ description: "JSON proof packet with proof_plan, capture_script, optional refined_inputs, rationale, confidence, and summary."
749
+ }],
750
+ response_schema: {
751
+ proof_plan: "string",
752
+ capture_script: "string",
753
+ baseline_understanding_used: {
754
+ reference: ["before", "prod", "both", "unknown"],
755
+ target_route: "string",
756
+ before_evidence_url: "string",
757
+ visible_before_state: "string",
758
+ relevant_elements: ["string"],
759
+ requested_change: "string",
760
+ proof_focus: "string",
761
+ stop_condition: "string",
762
+ quality_risks: ["string"]
763
+ },
764
+ refined_inputs: {
765
+ server_path: "string",
766
+ wait_for_selector: "string",
767
+ reference: ["before", "prod", "both"]
768
+ },
769
+ rationale: ["string"],
770
+ confidence: "low | medium | high",
771
+ summary: "string"
772
+ },
773
+ required_state: ["author_request", "recon_results.baselines"]
774
+ },
775
+ author_review: {
776
+ purpose: "Proof packet is ready; choose whether to inspect, re-author, implement, or verify."
777
+ },
778
+ implement_changes_missing: {
779
+ purpose: "Implementation stage did not detect material code changes.",
780
+ accepted_inputs: [{
781
+ name: "make_code_changes",
782
+ type: "external_action",
783
+ required: true,
784
+ description: "Make the actual code changes in the after worktree, then resume the implement stage."
785
+ }]
786
+ },
787
+ implement_review: {
788
+ purpose: "Implementation changes were detected and stale verify evidence, if any, was invalidated."
789
+ },
790
+ implement_required: {
791
+ purpose: "Verify cannot run until implementation changes are recorded.",
792
+ accepted_inputs: [{
793
+ name: "make_code_changes",
794
+ type: "external_action",
795
+ required: true,
796
+ description: "Make the requested code change, then advance the run to implement."
797
+ }]
798
+ },
799
+ verify_capture_retry: {
800
+ purpose: "Verify capture was incomplete; the agent loop should revise capture authoring before shipping.",
801
+ accepted_inputs: [{
802
+ name: "author_packet_json",
803
+ type: "json",
804
+ description: "Optional revised proof packet if returning to author."
805
+ }],
806
+ required_state: ["verify_decision_request"]
807
+ },
808
+ verify_supervisor_judgment: {
809
+ purpose: "Supervising agent judges whether captured evidence proves the change is ready to ship.",
810
+ accepted_inputs: [{
811
+ name: "proof_assessment_json",
812
+ type: "json",
813
+ required: true,
814
+ description: "JSON assessment with decision, summary, recommended_stage, continue_with_stage, escalation_target, and reasons."
815
+ }],
816
+ response_schema: {
817
+ decision: ["ready_to_ship", "needs_richer_proof"],
818
+ summary: "string",
819
+ recommended_stage: ["ship", "author", "implement", "recon", "verify"],
820
+ continue_with_stage: ["ship", "author", "implement", "recon", "verify"],
821
+ escalation_target: ["agent", "human"],
822
+ reasons: ["string"],
823
+ source: "supervising_agent"
824
+ },
825
+ required_state: ["before_cdn or prod_cdn", "after_cdn", "proof_assessment_request"],
826
+ include_ship_gate: true
827
+ },
828
+ verify_human_escalation: {
829
+ purpose: "Proof loop is explicitly escalated to the human after supervising-agent judgment."
830
+ },
831
+ verify_agent_retry: {
832
+ purpose: "Supervising agent judged the proof insufficient and kept the workflow inside the internal loop.",
833
+ accepted_inputs: [{
834
+ name: "author_packet_json",
835
+ type: "json",
836
+ description: "Optional revised proof packet if the checkpoint resumes to author."
837
+ }]
838
+ },
839
+ verify_ship_ready: {
840
+ purpose: "Proof assessment is ready_to_ship and the next continuation should enter ship.",
841
+ include_ship_gate: true
842
+ },
843
+ verify_required: {
844
+ purpose: "Ship is blocked until verify captures usable after evidence.",
845
+ include_ship_gate: true
846
+ },
847
+ verify_supervisor_judgment_required: {
848
+ purpose: "Ship is blocked until the supervising agent judges the current evidence ready_to_ship.",
849
+ accepted_inputs: [{
850
+ name: "proof_assessment_json",
851
+ type: "json",
852
+ required: true,
853
+ description: "JSON assessment that must use decision=ready_to_ship before ship can continue."
854
+ }],
855
+ include_ship_gate: true
856
+ },
857
+ ship_gate_blocked: {
858
+ purpose: "Ship is blocked because required baseline, after evidence, or supervising-agent proof approval is missing.",
859
+ include_ship_gate: true
860
+ },
861
+ ship_review: {
862
+ purpose: "Ship completed; inspect the PR, proof comment, and CI status.",
863
+ include_ship_gate: true
864
+ }
865
+ };
866
+ }
867
+ });
868
+
869
+ // src/proof-run-engine.ts
870
+ var proof_run_engine_exports = {};
871
+ __export(proof_run_engine_exports, {
872
+ createRiddleProofEngine: () => createRiddleProofEngine,
873
+ executeWorkflow: () => executeWorkflow
874
+ });
875
+ function snapshotFor(statePath) {
876
+ return summarizeState(readState(statePath));
877
+ }
878
+ function authorReady(state) {
879
+ return state?.author_status === "ready" || state?.proof_plan_status === "ready";
880
+ }
881
+ function implementationReady(state) {
882
+ return ["changes_detected", "completed"].includes(state?.implementation_status || "");
883
+ }
884
+ function stageAfterAuthor(state) {
885
+ return implementationReady(state) ? "verify" : "implement";
886
+ }
887
+ function latestReconAttempt(state) {
888
+ const history = Array.isArray(state?.recon_results?.attempt_history) ? state.recon_results.attempt_history : [];
889
+ return history.length ? history[history.length - 1] : null;
890
+ }
891
+ function latestReconCapturedBaselines(state) {
892
+ const latest = latestReconAttempt(state);
893
+ if (latest?.captured_baselines && typeof latest.captured_baselines === "object") return latest.captured_baselines;
894
+ if (latest?.baselines && typeof latest.baselines === "object") return latest.baselines;
895
+ return state?.recon_results?.baselines || {};
896
+ }
897
+ function requiredReconBaselineLabels(state) {
898
+ const labels = [];
899
+ const reference = state?.requested_reference || state?.reference || "before";
900
+ if (reference === "before" || reference === "both") labels.push("before");
901
+ if ((reference === "prod" || reference === "both") && String(state?.prod_url || "").trim()) labels.push("prod");
902
+ return labels;
903
+ }
904
+ function latestReconHasRequiredBaselines(state) {
905
+ const baselines = latestReconCapturedBaselines(state);
906
+ return requiredReconBaselineLabels(state).every((label) => Boolean((baselines?.[label]?.url || "").trim()));
907
+ }
908
+ function hasReconBaselineUnderstanding(state) {
909
+ const understanding = state?.recon_assessment?.baseline_understanding || state?.recon_baseline_understanding || {};
910
+ return Boolean(
911
+ String(understanding?.visible_before_state || "").trim() && String(understanding?.requested_change || "").trim() && String(understanding?.proof_focus || "").trim() && String(understanding?.stop_condition || "").trim()
912
+ );
913
+ }
914
+ function promoteLatestReconBaselines(state) {
915
+ const baselines = latestReconCapturedBaselines(state);
916
+ state.recon_results = state.recon_results || {};
917
+ state.recon_results.baselines = baselines;
918
+ state.recon_results.selected_attempt = latestReconAttempt(state) || {};
919
+ state.before_cdn = (baselines?.before?.url || "").trim();
920
+ state.prod_cdn = (baselines?.prod?.url || "").trim();
921
+ return baselines;
922
+ }
923
+ function hasSupervisorReconAssessment(state) {
924
+ const reconAssessment2 = state?.recon_assessment || {};
925
+ const source = String(reconAssessment2?.source || state?.recon_assessment_source || "").trim().toLowerCase();
926
+ if (!reconAssessment2?.decision) return false;
927
+ return source === "supervising_agent" || source === "supervisor";
928
+ }
929
+ function reconAssessment(state) {
930
+ const assessment = state?.recon_assessment || {};
931
+ const decision = assessment?.decision || null;
932
+ const continueWithStage = assessment?.continue_with_stage || assessment?.recommended_stage || (decision === "ready_for_author" ? "author" : "recon");
933
+ return {
934
+ decision,
935
+ summary: assessment?.summary || state?.recon_assessment_request?.summary || state?.recon_summary || null,
936
+ recommendedStage: assessment?.recommended_stage || continueWithStage || null,
937
+ continueWithStage: continueWithStage || null,
938
+ escalationTarget: assessment?.escalation_target || "agent",
939
+ reasons: Array.isArray(assessment?.reasons) ? assessment.reasons : [],
940
+ raw: assessment,
941
+ source: String(assessment?.source || state?.recon_assessment_source || "").trim() || null
942
+ };
943
+ }
944
+ function updateState(statePath, mutate) {
945
+ const state = readState(statePath) || {};
946
+ mutate(state);
947
+ writeState(statePath, state);
948
+ return state;
949
+ }
950
+ function nowIso() {
951
+ return (/* @__PURE__ */ new Date()).toISOString();
952
+ }
953
+ function appendRuntimeEventToState(state, event) {
954
+ const events = Array.isArray(state.runtime_events) ? state.runtime_events : [];
955
+ state.runtime_events = [...events, event].slice(-RUNTIME_EVENT_LIMIT);
956
+ state.runtime_updated_at = event.ts;
957
+ }
958
+ function beginRuntimeStep(statePath, action, step, workflowPath) {
959
+ const timer = {
960
+ startedAt: nowIso(),
961
+ startedMs: Date.now()
962
+ };
963
+ updateState(statePath, (state) => {
964
+ const current = {
965
+ step,
966
+ action,
967
+ status: "running",
968
+ started_at: timer.startedAt,
969
+ workflow_file: import_node_path2.default.basename(workflowPath)
970
+ };
971
+ state.current_runtime_step = current;
972
+ appendRuntimeEventToState(state, {
973
+ ts: timer.startedAt,
974
+ kind: "workflow.step.started",
975
+ step,
976
+ action,
977
+ summary: `Started ${step} workflow step.`,
978
+ details: {
979
+ workflow_file: import_node_path2.default.basename(workflowPath)
980
+ }
981
+ });
982
+ });
983
+ return timer;
984
+ }
985
+ function finishRuntimeStep(statePath, action, result, timer) {
986
+ const finishedAt = nowIso();
987
+ const durationMs = Date.now() - timer.startedMs;
988
+ const summary = result.haltedForApproval ? `${result.step} halted for approval.` : result.ok ? `Finished ${result.step} workflow step.` : `${result.step} workflow step failed.`;
989
+ updateState(statePath, (state) => {
990
+ const completed = {
991
+ step: result.step,
992
+ action,
993
+ status: result.haltedForApproval ? "approval_required" : result.ok ? "completed" : "failed",
994
+ started_at: timer.startedAt,
995
+ finished_at: finishedAt,
996
+ duration_ms: durationMs,
997
+ ok: result.ok,
998
+ halted_for_approval: result.haltedForApproval || false,
999
+ auto_approved: result.autoApproved || false,
1000
+ error: result.error || null
1001
+ };
1002
+ state.current_runtime_step = null;
1003
+ state.last_runtime_step = completed;
1004
+ appendRuntimeEventToState(state, {
1005
+ ts: finishedAt,
1006
+ kind: "workflow.step.finished",
1007
+ step: result.step,
1008
+ action,
1009
+ summary,
1010
+ details: completed
1011
+ });
1012
+ });
1013
+ return {
1014
+ ...result,
1015
+ started_at: timer.startedAt,
1016
+ finished_at: finishedAt,
1017
+ duration_ms: durationMs
1018
+ };
1019
+ }
1020
+ function executedStep(res, extra = {}) {
1021
+ const output = {
1022
+ step: res.step,
1023
+ ok: res.ok,
1024
+ haltedForApproval: res.haltedForApproval || false,
1025
+ autoApproved: res.autoApproved || false,
1026
+ ...extra
1027
+ };
1028
+ if (typeof res.duration_ms === "number") output.duration_ms = res.duration_ms;
1029
+ return output;
1030
+ }
1031
+ function hasSupervisorProofAssessment(state) {
1032
+ const proofAssessment = state?.proof_assessment || {};
1033
+ const source = String(proofAssessment?.source || state?.proof_assessment_source || "").trim().toLowerCase();
1034
+ if (!proofAssessment?.decision) return false;
1035
+ return source === "supervising_agent" || source === "supervisor";
1036
+ }
1037
+ function verifyAssessment(state) {
1038
+ const proofAssessment = state?.proof_assessment || {};
1039
+ const verifyDecision = state?.verify_decision_request || {};
1040
+ if (hasSupervisorProofAssessment(state)) {
1041
+ return {
1042
+ decision: proofAssessment?.decision || null,
1043
+ summary: proofAssessment?.summary || verifyDecision?.summary || null,
1044
+ recommendedStage: proofAssessment?.continue_with_stage || proofAssessment?.recommended_stage || verifyDecision?.continue_with_stage || verifyDecision?.recommended_stage || null,
1045
+ continueWithStage: proofAssessment?.continue_with_stage || verifyDecision?.continue_with_stage || proofAssessment?.recommended_stage || verifyDecision?.recommended_stage || null,
1046
+ escalationTarget: proofAssessment?.escalation_target || "agent",
1047
+ reasons: Array.isArray(proofAssessment?.reasons) ? proofAssessment.reasons : [],
1048
+ raw: proofAssessment,
1049
+ source: "supervising_agent"
1050
+ };
1051
+ }
1052
+ if (state?.verify_status === "capture_incomplete") {
1053
+ return {
1054
+ decision: verifyDecision?.capture_quality?.decision || "revise_capture",
1055
+ summary: verifyDecision?.summary || "Verify needs another internal capture iteration before the evidence can be judged.",
1056
+ recommendedStage: verifyDecision?.continue_with_stage || verifyDecision?.recommended_stage || "author",
1057
+ continueWithStage: verifyDecision?.continue_with_stage || verifyDecision?.recommended_stage || "author",
1058
+ escalationTarget: "agent",
1059
+ reasons: Array.isArray(verifyDecision?.capture_quality?.reasons) ? verifyDecision.capture_quality.reasons : [],
1060
+ raw: verifyDecision?.capture_quality || verifyDecision,
1061
+ source: "workflow_capture"
1062
+ };
1063
+ }
1064
+ return {
1065
+ decision: null,
1066
+ summary: verifyDecision?.summary || "Verify captured evidence and is waiting for supervising-agent proof assessment.",
1067
+ recommendedStage: null,
1068
+ continueWithStage: null,
1069
+ escalationTarget: "agent",
1070
+ reasons: [],
1071
+ raw: proofAssessment,
1072
+ source: "awaiting_supervisor"
1073
+ };
1074
+ }
1075
+ function nonConvergenceSignals(state, assessment = verifyAssessment(state)) {
1076
+ const verifyAttempts = Number(state?.stage_attempts?.verify?.count || 0);
1077
+ const authorAttempts = Number(state?.stage_attempts?.author?.count || 0);
1078
+ const reconAttempts = Number(state?.stage_attempts?.recon?.count || 0);
1079
+ const continueStage = assessment.continueWithStage || assessment.recommendedStage || null;
1080
+ return {
1081
+ verifyAttempts,
1082
+ authorAttempts,
1083
+ reconAttempts,
1084
+ continueStage,
1085
+ warning: verifyAttempts >= 4 || continueStage === "author" && verifyAttempts >= 2 && authorAttempts >= 2 || continueStage === "recon" && verifyAttempts >= 2 && reconAttempts >= 2 || continueStage === "implement" && verifyAttempts >= 2
1086
+ };
1087
+ }
1088
+ function shouldEscalateVerifyToHuman(_state, assessment = verifyAssessment(_state)) {
1089
+ return assessment.escalationTarget === "human";
1090
+ }
1091
+ function recommendedAdvanceStage(state) {
1092
+ if (!state?.workspace_ready) return "setup";
1093
+ if (!state?.recon_results || ["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "")) return "recon";
1094
+ if (!authorReady(state)) return "author";
1095
+ if (!implementationReady(state)) return "implement";
1096
+ if (state?.verify_status === "capture_incomplete") return verifyAssessment(state).continueWithStage || verifyAssessment(state).recommendedStage || "author";
1097
+ if (state?.verify_status === "evidence_captured") return verifyAssessment(state).continueWithStage || verifyAssessment(state).recommendedStage;
1098
+ if (!(state?.after_cdn || "").trim()) return "verify";
1099
+ return null;
1100
+ }
1101
+ function normalizeStageRequest(state, requestedAdvanceStage) {
1102
+ if (requestedAdvanceStage) return requestedAdvanceStage;
1103
+ if (!state?.workspace_ready) return null;
1104
+ if (!state?.recon_results || ["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "")) return "recon";
1105
+ return null;
1106
+ }
1107
+ function stringValue(value) {
1108
+ return typeof value === "string" && value.trim() ? value.trim() : "";
1109
+ }
1110
+ function commandResult(command, args, cwd, timeout = 6e4) {
1111
+ try {
1112
+ return {
1113
+ ok: true,
1114
+ stdout: (0, import_node_child_process.execFileSync)(command, args, { cwd, encoding: "utf-8", timeout, stdio: ["ignore", "pipe", "pipe"] }),
1115
+ stderr: ""
1116
+ };
1117
+ } catch (error) {
1118
+ return {
1119
+ ok: false,
1120
+ stdout: String(error?.stdout || ""),
1121
+ stderr: String(error?.stderr || error?.message || "")
1122
+ };
1123
+ }
1124
+ }
1125
+ function repoDirForSync(state) {
1126
+ const candidates = [
1127
+ state?.repo_dir,
1128
+ state?.after_worktree,
1129
+ state?.before_worktree
1130
+ ].map(stringValue).filter(Boolean);
1131
+ return candidates.find((candidate) => (0, import_node_fs2.existsSync)(import_node_path2.default.join(candidate, ".git"))) || "";
1132
+ }
1133
+ function parseWorktreeList(output) {
1134
+ const entries = [];
1135
+ let current = {};
1136
+ for (const line of output.split(/\r?\n/)) {
1137
+ if (!line.trim()) {
1138
+ if (current.worktree) entries.push(current);
1139
+ current = {};
1140
+ continue;
1141
+ }
1142
+ const [key, ...rest] = line.split(" ");
1143
+ const value = rest.join(" ").trim();
1144
+ if (key === "worktree" || key === "HEAD" || key === "branch" || key === "detached") current[key] = value;
1145
+ }
1146
+ if (current.worktree) entries.push(current);
1147
+ return entries;
1148
+ }
1149
+ function gitStdout(cwd, args, timeout = 6e4) {
1150
+ const result = commandResult("git", args, cwd, timeout);
1151
+ return result.ok ? result.stdout.trim() : "";
1152
+ }
1153
+ function shortBranch(ref) {
1154
+ return ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref;
1155
+ }
1156
+ function safeInteger(value) {
1157
+ const parsed = Number.parseInt(value, 10);
1158
+ return Number.isFinite(parsed) ? parsed : null;
1159
+ }
1160
+ function baseCheckoutReport(repoDir, baseBranch, updateRequested, updateAllowed) {
1161
+ const remoteRef = `origin/${baseBranch}`;
1162
+ const report = {
1163
+ requested: updateRequested,
1164
+ repo_dir: repoDir,
1165
+ base_branch: baseBranch,
1166
+ remote_ref: remoteRef,
1167
+ updated: false
1168
+ };
1169
+ const listed = commandResult("git", ["worktree", "list", "--porcelain"], repoDir, 6e4);
1170
+ if (!listed.ok) {
1171
+ report.update_skipped = "worktree_list_failed";
1172
+ report.error = listed.stderr.slice(0, 300);
1173
+ return report;
1174
+ }
1175
+ const worktrees = parseWorktreeList(listed.stdout);
1176
+ const baseRef = `refs/heads/${baseBranch}`;
1177
+ const selected = worktrees.find((entry) => entry.branch === baseRef) || worktrees.find((entry) => import_node_path2.default.resolve(entry.worktree || "") === import_node_path2.default.resolve(repoDir) && shortBranch(entry.branch || "") === baseBranch);
1178
+ if (!selected?.worktree) {
1179
+ report.worktrees_seen = worktrees.map((entry) => ({
1180
+ path: entry.worktree || null,
1181
+ branch: entry.branch ? shortBranch(entry.branch) : null,
1182
+ detached: Boolean(entry.detached)
1183
+ }));
1184
+ report.update_skipped = "base_worktree_not_found";
1185
+ return report;
1186
+ }
1187
+ const baseDir = selected.worktree;
1188
+ const branch = shortBranch(selected.branch || "");
1189
+ const status = commandResult("git", ["status", "--porcelain"], baseDir, 6e4);
1190
+ const clean = status.ok && !status.stdout.trim();
1191
+ const localHead = gitStdout(baseDir, ["rev-parse", "HEAD"]);
1192
+ const remoteHead = gitStdout(baseDir, ["rev-parse", "--verify", remoteRef]);
1193
+ const counts = remoteHead ? gitStdout(baseDir, ["rev-list", "--left-right", "--count", `HEAD...${remoteRef}`]) : "";
1194
+ const [aheadRaw, behindRaw] = counts.split(/\s+/);
1195
+ Object.assign(report, {
1196
+ base_worktree: baseDir,
1197
+ branch: branch || null,
1198
+ clean,
1199
+ local_head: localHead || null,
1200
+ remote_head: remoteHead || null,
1201
+ ahead: safeInteger(aheadRaw || ""),
1202
+ behind: safeInteger(behindRaw || "")
1203
+ });
1204
+ if (!updateRequested) {
1205
+ report.update_skipped = "update_not_requested";
1206
+ return report;
1207
+ }
1208
+ if (!updateAllowed) {
1209
+ report.update_skipped = "fetch_failed";
1210
+ return report;
1211
+ }
1212
+ if (branch !== baseBranch) {
1213
+ report.update_skipped = "base_worktree_not_on_base_branch";
1214
+ return report;
1215
+ }
1216
+ if (!status.ok) {
1217
+ report.update_skipped = "status_failed";
1218
+ report.status_error = status.stderr.slice(0, 300);
1219
+ return report;
1220
+ }
1221
+ if (!clean) {
1222
+ report.update_skipped = "base_worktree_dirty";
1223
+ return report;
1224
+ }
1225
+ if (!remoteHead) {
1226
+ report.update_skipped = "remote_ref_missing";
1227
+ return report;
1228
+ }
1229
+ if (localHead && localHead === remoteHead) {
1230
+ report.update_skipped = "already_current";
1231
+ return report;
1232
+ }
1233
+ const merge = commandResult("git", ["merge", "--ff-only", remoteRef], baseDir, 12e4);
1234
+ if (!merge.ok) {
1235
+ report.update_skipped = "fast_forward_failed";
1236
+ report.update_error = merge.stderr.slice(0, 500);
1237
+ return report;
1238
+ }
1239
+ const updatedHead = gitStdout(baseDir, ["rev-parse", "HEAD"]);
1240
+ const updatedCounts = gitStdout(baseDir, ["rev-list", "--left-right", "--count", `HEAD...${remoteRef}`]);
1241
+ const [updatedAheadRaw, updatedBehindRaw] = updatedCounts.split(/\s+/);
1242
+ report.updated = true;
1243
+ report.local_head = updatedHead || report.local_head;
1244
+ report.ahead = safeInteger(updatedAheadRaw || "");
1245
+ report.behind = safeInteger(updatedBehindRaw || "");
1246
+ report.update_summary = merge.stdout.trim().slice(0, 500);
1247
+ return report;
1248
+ }
1249
+ function normalizeGhPrStatus(value) {
1250
+ const status = stringValue(value).toLowerCase();
1251
+ if (status === "merged") return "merged";
1252
+ if (status === "open") return "open";
1253
+ if (status === "closed") return "closed";
1254
+ return status || "unknown";
1255
+ }
1256
+ function prRefFromState(state) {
1257
+ return stringValue(state?.pr_number) || stringValue(state?.pr_url);
1258
+ }
1259
+ function prNumberFromUrl(url) {
1260
+ const match = url.match(/\/pull\/(\d+)(?:$|[?#])/);
1261
+ return match?.[1] || "";
1262
+ }
1263
+ function normalizePrState(raw, state, checkedAt = (/* @__PURE__ */ new Date()).toISOString()) {
1264
+ const mergeCommit = typeof raw?.mergeCommit === "object" && raw.mergeCommit ? stringValue(raw.mergeCommit.oid) : stringValue(raw?.mergeCommit);
1265
+ const url = stringValue(raw?.url) || stringValue(state?.pr_url);
1266
+ return {
1267
+ status: normalizeGhPrStatus(raw?.state),
1268
+ pr_url: url || null,
1269
+ pr_number: String(raw?.number || state?.pr_number || prNumberFromUrl(url) || ""),
1270
+ repo: stringValue(state?.repo) || null,
1271
+ head_branch: stringValue(raw?.headRefName) || stringValue(state?.target_branch) || stringValue(state?.branch) || null,
1272
+ base_branch: stringValue(raw?.baseRefName) || stringValue(state?.base_branch) || "main",
1273
+ merge_commit: mergeCommit || null,
1274
+ merged_at: stringValue(raw?.mergedAt) || null,
1275
+ closed_at: stringValue(raw?.closedAt) || null,
1276
+ checked_at: checkedAt,
1277
+ source: "gh"
1278
+ };
1279
+ }
1280
+ function cleanupMergedProofRun(state, repoDir, params, prState) {
1281
+ const cleanup = {
1282
+ requested: params.cleanup_merged_pr !== false,
1283
+ fetch_base: params.fetch_base !== false,
1284
+ update_base_checkout: params.update_base_checkout !== false,
1285
+ repo_dir: repoDir,
1286
+ worktrees_removed: [],
1287
+ worktree_remove_errors: [],
1288
+ branches_deleted: [],
1289
+ branch_delete_errors: [],
1290
+ pruned: false
1291
+ };
1292
+ const baseBranch = stringValue(prState.base_branch) || stringValue(state?.base_branch) || "main";
1293
+ let fetchedBase = params.fetch_base === false;
1294
+ if (params.fetch_base !== false && baseBranch) {
1295
+ const fetch = commandResult("git", ["fetch", "origin", baseBranch], repoDir, 12e4);
1296
+ cleanup.fetch = fetch.ok ? { ok: true, base_branch: baseBranch } : { ok: false, base_branch: baseBranch, error: fetch.stderr.slice(0, 300) };
1297
+ if (fetch.ok) {
1298
+ fetchedBase = true;
1299
+ state.base_synced_at = (/* @__PURE__ */ new Date()).toISOString();
1300
+ state.base_branch = baseBranch;
1301
+ }
1302
+ }
1303
+ cleanup.base_checkout = baseCheckoutReport(repoDir, baseBranch, params.update_base_checkout !== false, fetchedBase);
1304
+ if (params.cleanup_merged_pr === false) {
1305
+ cleanup.skipped = "cleanup_disabled";
1306
+ return cleanup;
1307
+ }
1308
+ const removed = [];
1309
+ const removeErrors = [];
1310
+ for (const candidate of [state?.before_worktree, state?.after_worktree].map(stringValue).filter(Boolean)) {
1311
+ if (!(0, import_node_fs2.existsSync)(candidate) || import_node_path2.default.resolve(candidate) === import_node_path2.default.resolve(repoDir)) continue;
1312
+ const remove = commandResult("git", ["worktree", "remove", "--force", candidate], repoDir, 12e4);
1313
+ if (remove.ok) {
1314
+ removed.push(candidate);
1315
+ } else {
1316
+ removeErrors.push({ path: candidate, error: remove.stderr.slice(0, 300) });
1317
+ }
1318
+ }
1319
+ cleanup.worktrees_removed = removed;
1320
+ cleanup.worktree_remove_errors = removeErrors;
1321
+ const afterBranch = stringValue(state?.after_worktree_branch);
1322
+ if (afterBranch.startsWith("riddle-proof/")) {
1323
+ const deleted = commandResult("git", ["branch", "-D", afterBranch], repoDir, 6e4);
1324
+ if (deleted.ok) {
1325
+ cleanup.branches_deleted = [afterBranch];
1326
+ } else {
1327
+ cleanup.branch_delete_errors = [{ branch: afterBranch, error: deleted.stderr.slice(0, 300) }];
1328
+ }
1329
+ }
1330
+ const prune = commandResult("git", ["worktree", "prune"], repoDir, 6e4);
1331
+ cleanup.pruned = prune.ok;
1332
+ if (!prune.ok) cleanup.prune_error = prune.stderr.slice(0, 300);
1333
+ return cleanup;
1334
+ }
1335
+ function syncPrLifecycle(statePath, params) {
1336
+ const state = readState(statePath);
1337
+ if (!state) {
1338
+ return {
1339
+ ok: false,
1340
+ action: "sync",
1341
+ state_path: statePath,
1342
+ checkpoint: "pr_sync_not_found",
1343
+ summary: "No readable Riddle Proof state exists at state_path.",
1344
+ state: null,
1345
+ nextAction: "Check the wrapper state_path or run riddle_proof_status first."
1346
+ };
1347
+ }
1348
+ const repoDir = repoDirForSync(state);
1349
+ const prRef = prRefFromState(state);
1350
+ if (!repoDir || !prRef) {
1351
+ const missingPr = !prRef;
1352
+ const orphanSummary = "Riddle Proof state exists, but this run is not recoverable through PR sync because no PR URL or PR number was linked before it stopped.";
1353
+ const orphanNextAction = "Treat this as an orphaned proof run: update the base checkout directly if needed, then clean stale proof worktrees or riddle-proof/* branches outside normal PR sync.";
1354
+ const prState2 = {
1355
+ status: missingPr ? "orphaned" : "unavailable",
1356
+ pr_url: state.pr_url || null,
1357
+ pr_number: String(state.pr_number || prNumberFromUrl(stringValue(state.pr_url)) || ""),
1358
+ repo: state.repo || null,
1359
+ head_branch: state.target_branch || state.branch || null,
1360
+ base_branch: state.base_branch || "main",
1361
+ checked_at: (/* @__PURE__ */ new Date()).toISOString(),
1362
+ source: repoDir ? "state" : "local_state",
1363
+ sync_recoverable: !missingPr,
1364
+ sync_blocker: missingPr ? "missing_pr_linkage" : "missing_local_repo",
1365
+ next_action: missingPr ? orphanNextAction : "State has a PR but no readable local git repo/worktree; restore repo access and rerun sync."
1366
+ };
1367
+ state.pr_state = prState2;
1368
+ if (missingPr) state.pr_sync_summary = orphanSummary;
1369
+ writeState(statePath, state);
1370
+ return {
1371
+ ok: false,
1372
+ action: "sync",
1373
+ state_path: statePath,
1374
+ checkpoint: missingPr ? "pr_sync_no_pr" : "pr_sync_unavailable",
1375
+ summary: missingPr ? orphanSummary : prState2.next_action,
1376
+ state: summarizeState(state).state,
1377
+ pr_state: prState2,
1378
+ nextAction: prState2.next_action
1379
+ };
1380
+ }
1381
+ const viewed = commandResult("gh", ["pr", "view", prRef, "--json", "state,mergedAt,closedAt,mergeCommit,headRefName,baseRefName,url,number"], repoDir, 6e4);
1382
+ if (!viewed.ok) {
1383
+ const prState2 = {
1384
+ status: "unavailable",
1385
+ pr_url: state.pr_url || null,
1386
+ pr_number: String(state.pr_number || prNumberFromUrl(stringValue(state.pr_url)) || ""),
1387
+ repo: state.repo || null,
1388
+ head_branch: state.target_branch || state.branch || null,
1389
+ base_branch: state.base_branch || "main",
1390
+ checked_at: (/* @__PURE__ */ new Date()).toISOString(),
1391
+ source: "gh",
1392
+ next_action: "GitHub PR state is unavailable; fix gh auth/repo access and rerun riddle_proof_sync."
1393
+ };
1394
+ state.pr_state = prState2;
1395
+ state.cleanup_report = { requested: params.cleanup_merged_pr !== false, skipped: "pr_state_unavailable", error: viewed.stderr.slice(0, 300) };
1396
+ writeState(statePath, state);
1397
+ return {
1398
+ ok: false,
1399
+ action: "sync",
1400
+ state_path: statePath,
1401
+ checkpoint: "pr_sync_unavailable",
1402
+ summary: prState2.next_action,
1403
+ state: summarizeState(state).state,
1404
+ pr_state: prState2,
1405
+ cleanup: state.cleanup_report,
1406
+ nextAction: prState2.next_action
1407
+ };
1408
+ }
1409
+ let rawPr;
1410
+ try {
1411
+ rawPr = JSON.parse(viewed.stdout);
1412
+ } catch {
1413
+ rawPr = {};
1414
+ }
1415
+ const prState = normalizePrState(rawPr, state);
1416
+ let cleanup = null;
1417
+ let checkpoint = "pr_sync_open";
1418
+ let ok = true;
1419
+ let summary = "PR is still open; no merge cleanup was performed.";
1420
+ let nextAction = "Wait for the PR to merge, then rerun riddle_proof_sync.";
1421
+ if (prState.status === "merged") {
1422
+ cleanup = cleanupMergedProofRun(state, repoDir, params, prState);
1423
+ prState.cleanup = cleanup;
1424
+ prState.next_action = "The PR is merged; sync recorded proof cleanup and the local base checkout refresh status.";
1425
+ state.finalized = true;
1426
+ state.merge_commit = prState.merge_commit || state.merge_commit || "";
1427
+ state.merged_at = prState.merged_at || state.merged_at || "";
1428
+ state.cleanup_report = cleanup;
1429
+ checkpoint = "pr_sync_merged";
1430
+ summary = "PR is merged and Riddle Proof state has been reconciled.";
1431
+ nextAction = "Start the next proof run from the recorded base checkout; inspect cleanup.base_checkout only if it reports a skipped or failed fast-forward.";
1432
+ } else if (prState.status === "closed") {
1433
+ prState.next_action = "The PR is closed without a merge; inspect the PR before reusing or deleting the branch.";
1434
+ checkpoint = "pr_sync_closed";
1435
+ summary = "PR is closed without a merge; no merge cleanup was performed.";
1436
+ nextAction = prState.next_action;
1437
+ } else if (prState.status !== "open") {
1438
+ ok = false;
1439
+ prState.next_action = "PR state was not recognized; inspect gh pr view output and rerun sync.";
1440
+ checkpoint = "pr_sync_unavailable";
1441
+ summary = prState.next_action;
1442
+ nextAction = prState.next_action;
1443
+ }
1444
+ state.pr_state = prState;
1445
+ state.pr_url = prState.pr_url || state.pr_url;
1446
+ state.pr_number = prState.pr_number || state.pr_number;
1447
+ state.target_branch = prState.head_branch || state.target_branch || state.branch;
1448
+ state.branch = prState.head_branch || state.branch;
1449
+ state.base_branch = prState.base_branch || state.base_branch;
1450
+ writeState(statePath, state);
1451
+ const snapshot = summarizeState(state);
1452
+ return {
1453
+ ok,
1454
+ action: "sync",
1455
+ state_path: statePath,
1456
+ checkpoint,
1457
+ summary,
1458
+ state: snapshot.state,
1459
+ pr_state: prState,
1460
+ cleanup,
1461
+ nextAction
1462
+ };
1463
+ }
1464
+ async function executeWorkflow(params, pluginConfig, resolvedConfig) {
1465
+ const config = resolvedConfig || resolveConfig(pluginConfig, params);
1466
+ const action = ensureAction(params.action);
1467
+ if (!(0, import_node_fs2.existsSync)(config.riddleProofDir)) {
1468
+ throw new Error(`riddle-proof runtime directory not found: ${config.riddleProofDir}`);
1469
+ }
1470
+ if (action === "status") {
1471
+ return {
1472
+ state_path: config.statePath,
1473
+ ...summarizeState(readState(config.statePath))
1474
+ };
1475
+ }
1476
+ if (action === "sync") {
1477
+ return syncPrLifecycle(config.statePath, params);
1478
+ }
1479
+ const stateKey = import_node_path2.default.basename(config.statePath).replace(/[^A-Za-z0-9_.-]/g, "-");
1480
+ const lobsterStateDir = import_node_path2.default.join(import_node_path2.default.dirname(config.statePath), "riddle-proof-lobster-state", stateKey);
1481
+ (0, import_node_fs2.mkdirSync)(lobsterStateDir, { recursive: true });
1482
+ const env = {
1483
+ ...process.env,
1484
+ RIDDLE_PROOF_DIR: config.riddleProofDir,
1485
+ RIDDLE_PROOF_STATE_FILE: config.statePath,
1486
+ RIDDLE_PROOF_ARGS_FILE: config.argsPath,
1487
+ LOBSTER_STATE_DIR: lobsterStateDir
1488
+ };
1489
+ const lobsterCommand = process.env.RIDDLE_PROOF_LOBSTER_COMMAND || "lobster";
1490
+ const lobsterPrefix = process.env.RIDDLE_PROOF_LOBSTER_SCRIPT ? [process.env.RIDDLE_PROOF_LOBSTER_SCRIPT] : [];
1491
+ const runOne = (step) => {
1492
+ const args = step === "setup" ? buildSetupArgs(params, config) : {};
1493
+ const stepWorkflowFile = workflowFile(config.riddleProofDir, step);
1494
+ const timer = beginRuntimeStep(config.statePath, action, step, stepWorkflowFile);
1495
+ let output;
1496
+ try {
1497
+ output = JSON.parse(
1498
+ (0, import_node_child_process.execFileSync)(lobsterCommand, [...lobsterPrefix, "run", "--file", stepWorkflowFile, "--args-json", JSON.stringify(args)], {
1499
+ encoding: "utf-8",
1500
+ env
1501
+ })
1502
+ );
1503
+ } catch (error) {
1504
+ return finishRuntimeStep(config.statePath, action, {
1505
+ ok: false,
1506
+ step,
1507
+ error: error?.message || String(error),
1508
+ stdout: String(error?.stdout || ""),
1509
+ stderr: String(error?.stderr || "")
1510
+ }, timer);
1511
+ }
1512
+ if (output?.status === "needs_approval") {
1513
+ if (!params.auto_approve) {
1514
+ return finishRuntimeStep(config.statePath, action, {
1515
+ ok: false,
1516
+ haltedForApproval: true,
1517
+ step,
1518
+ approval: output.requiresApproval || null,
1519
+ raw: output
1520
+ }, timer);
1521
+ }
1522
+ const token = output?.requiresApproval?.resumeToken;
1523
+ if (!token) {
1524
+ return finishRuntimeStep(config.statePath, action, {
1525
+ ok: false,
1526
+ step,
1527
+ error: `${step} requested approval without a resume token.`,
1528
+ raw: output
1529
+ }, timer);
1530
+ }
1531
+ let resumed;
1532
+ try {
1533
+ resumed = JSON.parse(
1534
+ (0, import_node_child_process.execFileSync)(lobsterCommand, [...lobsterPrefix, "resume", "--token", token, "--approve", "yes"], {
1535
+ encoding: "utf-8",
1536
+ env
1537
+ })
1538
+ );
1539
+ } catch (error) {
1540
+ return finishRuntimeStep(config.statePath, action, {
1541
+ ok: false,
1542
+ step,
1543
+ autoApproved: true,
1544
+ error: error?.message || String(error),
1545
+ stdout: String(error?.stdout || ""),
1546
+ stderr: String(error?.stderr || "")
1547
+ }, timer);
1548
+ }
1549
+ return finishRuntimeStep(config.statePath, action, {
1550
+ ok: resumed?.ok !== false,
1551
+ step,
1552
+ autoApproved: true,
1553
+ raw: resumed
1554
+ }, timer);
1555
+ }
1556
+ return finishRuntimeStep(config.statePath, action, {
1557
+ ok: output?.ok !== false,
1558
+ step,
1559
+ raw: output
1560
+ }, timer);
1561
+ };
1562
+ let effectiveAdvanceStage = params.advance_stage || null;
1563
+ const recordAttempt = (stage, status, summary, extra = {}) => {
1564
+ updateState(config.statePath, (state) => {
1565
+ recordStageAttempt(state, stage, {
1566
+ status,
1567
+ summary,
1568
+ checkpoint: extra.checkpoint || null,
1569
+ requestedAdvanceStage: effectiveAdvanceStage || null,
1570
+ haltedForApproval: extra.haltedForApproval,
1571
+ autoApproved: extra.autoApproved,
1572
+ error: extra.error || null,
1573
+ details: extra.details || {}
1574
+ });
1575
+ });
1576
+ };
1577
+ const checkpoint = (stage, name, summary, extra = {}) => {
1578
+ const decision = updateState(config.statePath, (state) => {
1579
+ const checkpointContract = buildCheckpointContract(state, {
1580
+ statePath: config.statePath,
1581
+ stage,
1582
+ checkpoint: name,
1583
+ summary,
1584
+ nextActions: extra.nextActions,
1585
+ advanceOptions: extra.advanceOptions,
1586
+ recommendedAdvanceStage: extra.recommendedAdvanceStage,
1587
+ continueWithStage: extra.continueWithStage,
1588
+ blocking: extra.blocking
1589
+ });
1590
+ setStageDecisionRequest(state, {
1591
+ stage,
1592
+ checkpoint: name,
1593
+ summary,
1594
+ nextActions: extra.nextActions,
1595
+ advanceOptions: extra.advanceOptions,
1596
+ recommendedAdvanceStage: extra.recommendedAdvanceStage,
1597
+ continueWithStage: extra.continueWithStage,
1598
+ blocking: extra.blocking,
1599
+ details: extra.details,
1600
+ checkpointContract
1601
+ });
1602
+ }).stage_decision_request;
1603
+ const snapshot2 = snapshotFor(config.statePath);
1604
+ return {
1605
+ ok: extra.ok ?? true,
1606
+ action,
1607
+ state_path: config.statePath,
1608
+ stage: snapshot2.stage,
1609
+ checkpoint: name,
1610
+ summary,
1611
+ state: snapshot2.state,
1612
+ decisionRequest: decision,
1613
+ checkpointContract: decision?.checkpoint_contract || null,
1614
+ ...extra
1615
+ };
1616
+ };
1617
+ const primaryShipGateNextAction = (shipGate) => {
1618
+ const reasons = shipGate.reasons || [];
1619
+ if (reasons.some((reason) => reason.includes("proof_assessment"))) {
1620
+ return "resume with riddle_proof_review using decision=ready_to_ship only after the screenshots and semantic evidence visibly prove the request; otherwise choose needs_implementation or needs_richer_proof";
1621
+ }
1622
+ if (reasons.some((reason) => reason.includes("after_cdn") || reason.includes("verify_status"))) {
1623
+ return "rerun verify with stronger proof framing so after evidence is captured before shipping";
1624
+ }
1625
+ if (reasons.some((reason) => reason.includes("before_cdn") || reason.includes("prod_cdn") || reason.includes("prod_url"))) {
1626
+ return "return to recon and capture the missing required baseline before shipping";
1627
+ }
1628
+ return "inspect the ship gate details, repair the missing invariant, then resume the run";
1629
+ };
1630
+ const shipGateBlocked = (state, executed, details = {}) => {
1631
+ const shipGate = validateShipGate(state);
1632
+ const nextAction = primaryShipGateNextAction(shipGate);
1633
+ return checkpoint(
1634
+ "verify",
1635
+ "ship_gate_blocked",
1636
+ `Ship is blocked until the proof bundle satisfies the hard ship gate. Next action: ${nextAction}.`,
1637
+ {
1638
+ ok: false,
1639
+ nextActions: ["inspect_ship_gate", "advance_run_to_verify", "supply_proof_assessment_json", "return_to_recon_if_baseline_is_missing"],
1640
+ advanceOptions: ["verify", "author", "implement", "recon"],
1641
+ recommendedAdvanceStage: "verify",
1642
+ continueWithStage: "verify",
1643
+ blocking: true,
1644
+ details: { ...details, shipGate, next_action: nextAction, executed },
1645
+ nextAction,
1646
+ shipGate,
1647
+ verifyStatus: state?.verify_status || null,
1648
+ mergeRecommendation: state?.merge_recommendation || null,
1649
+ afterCdn: state?.after_cdn || null,
1650
+ proofAssessment: state?.proof_assessment || null,
1651
+ proofAssessmentRequest: state?.proof_assessment_request || null,
1652
+ executed
1653
+ }
1654
+ );
1655
+ };
1656
+ const failedRun = (stage, summary, res, extra = {}) => {
1657
+ recordAttempt(stage, res?.haltedForApproval ? "approval_required" : "failed", summary, {
1658
+ checkpoint: extra.checkpoint || null,
1659
+ haltedForApproval: res?.haltedForApproval || false,
1660
+ autoApproved: res?.autoApproved || false,
1661
+ error: res?.error || null,
1662
+ details: extra.details
1663
+ });
1664
+ const snapshot2 = snapshotFor(config.statePath);
1665
+ return {
1666
+ ok: false,
1667
+ action,
1668
+ state_path: config.statePath,
1669
+ stage: snapshot2.stage,
1670
+ summary,
1671
+ state: snapshot2.state,
1672
+ approval: res?.approval || null,
1673
+ error: res?.error || null,
1674
+ checkpoint: extra.checkpoint || null,
1675
+ ...extra
1676
+ };
1677
+ };
1678
+ if (action !== "setup") {
1679
+ mergeStateFromParams(config.statePath, params);
1680
+ }
1681
+ if (action === "run") {
1682
+ const executed = [];
1683
+ let state = readState(config.statePath);
1684
+ if (!state || !state.workspace_ready || params.advance_stage === "setup") {
1685
+ const setupRes = runOne("setup");
1686
+ executed.push(executedStep(setupRes));
1687
+ if (!setupRes.ok || setupRes.haltedForApproval) {
1688
+ return failedRun("setup", setupRes.haltedForApproval ? "setup halted for approval" : "setup failed", setupRes, {
1689
+ checkpoint: "setup_blocked"
1690
+ });
1691
+ }
1692
+ recordAttempt("setup", "completed", "Setup completed and state/worktrees are ready.", {
1693
+ checkpoint: params.advance_stage === "setup" ? "setup_review" : null,
1694
+ autoApproved: setupRes.autoApproved || false
1695
+ });
1696
+ state = readState(config.statePath);
1697
+ if (params.advance_stage === "setup") {
1698
+ return checkpoint(
1699
+ "setup",
1700
+ "setup_review",
1701
+ "Setup completed. Inspect the prepared workspace and explicitly advance to recon when ready.",
1702
+ {
1703
+ nextActions: ["inspect_setup_state", "advance_run_to_recon"],
1704
+ advanceOptions: ["recon", "setup"],
1705
+ recommendedAdvanceStage: "recon",
1706
+ details: { executed },
1707
+ executed
1708
+ }
1709
+ );
1710
+ }
1711
+ }
1712
+ state = readState(config.statePath);
1713
+ const continuedStage = params.continue_from_checkpoint ? checkpointContinueStage(state) : null;
1714
+ if (params.continue_from_checkpoint && !continuedStage) {
1715
+ const recommended = recommendedAdvanceStage(state);
1716
+ return checkpoint(
1717
+ state?.active_checkpoint_stage || recommended || "recon",
1718
+ "continue_unavailable",
1719
+ "This run call asked to continue from a checkpoint, but the current state has no resumable checkpoint. Inspect status or set advance_stage explicitly.",
1720
+ {
1721
+ ok: false,
1722
+ nextActions: ["inspect_state", "set_advance_stage", "resume_run"],
1723
+ advanceOptions: ["recon", "author", "implement", "verify", "ship"],
1724
+ recommendedAdvanceStage: null,
1725
+ blocking: true,
1726
+ details: {
1727
+ executed,
1728
+ activeCheckpoint: state?.active_checkpoint || null,
1729
+ suggestedAdvanceStage: recommended || null
1730
+ },
1731
+ suggestedAdvanceStage: recommended || null,
1732
+ executed
1733
+ }
1734
+ );
1735
+ }
1736
+ effectiveAdvanceStage = params.advance_stage || continuedStage || null;
1737
+ if (effectiveAdvanceStage) {
1738
+ updateState(config.statePath, (state2) => {
1739
+ clearStageDecisionRequest(state2);
1740
+ state2.last_requested_advance_stage = effectiveAdvanceStage;
1741
+ });
1742
+ state = readState(config.statePath);
1743
+ }
1744
+ let requestedStage = normalizeStageRequest(state, effectiveAdvanceStage);
1745
+ const reconCheckpointActive = ["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "") || state?.active_checkpoint === "recon_supervisor_judgment";
1746
+ if (requestedStage === "recon" && reconCheckpointActive) {
1747
+ const latestAttempt = latestReconAttempt(state);
1748
+ const latestCapturedBaselines = latestReconCapturedBaselines(state);
1749
+ const latestAssessment = reconAssessment(state);
1750
+ const reconAssessmentRequest = state?.recon_assessment_request || state?.recon_decision_request || null;
1751
+ const reconDetails = {
1752
+ executed,
1753
+ latestAttempt,
1754
+ latestCapturedBaselines,
1755
+ reconAssessmentRequest,
1756
+ reconAssessment: latestAssessment.raw
1757
+ };
1758
+ if (!hasSupervisorReconAssessment(state)) {
1759
+ return checkpoint(
1760
+ "recon",
1761
+ "recon_supervisor_judgment",
1762
+ "Recon gathered route hints, candidate paths, baseline captures, and observations. The supervising agent should now judge whether the latest baseline is trustworthy, whether recon should retry/reframe, and whether recon is done.",
1763
+ {
1764
+ nextActions: ["inspect_recon_packet", "supply_recon_assessment_json", "continue_internal_loop_with_checkpoint"],
1765
+ advanceOptions: ["recon", "author"],
1766
+ recommendedAdvanceStage: "recon",
1767
+ continueWithStage: "recon",
1768
+ blocking: false,
1769
+ details: reconDetails,
1770
+ reconAssessmentRequest,
1771
+ reconDecisionRequest: state?.recon_decision_request || null,
1772
+ executed
1773
+ }
1774
+ );
1775
+ }
1776
+ if (latestAssessment.decision === "recon_stuck" && latestAssessment.escalationTarget === "human") {
1777
+ const summary = latestAssessment.summary || "The supervising agent concluded recon is genuinely stuck and should escalate to the human.";
1778
+ recordAttempt("recon", "escalated", summary, {
1779
+ checkpoint: "recon_human_escalation",
1780
+ details: reconDetails
1781
+ });
1782
+ return checkpoint(
1783
+ "recon",
1784
+ "recon_human_escalation",
1785
+ summary,
1786
+ {
1787
+ ok: false,
1788
+ nextActions: ["inspect_recon_history", "summarize_failed_baselines", "ask_human_for_direction"],
1789
+ advanceOptions: ["recon", "author"],
1790
+ recommendedAdvanceStage: null,
1791
+ continueWithStage: null,
1792
+ blocking: true,
1793
+ details: reconDetails,
1794
+ reconAssessment: latestAssessment.raw,
1795
+ reconAssessmentRequest,
1796
+ executed
1797
+ }
1798
+ );
1799
+ }
1800
+ if ((latestAssessment.decision === "ready_for_author" || latestAssessment.continueWithStage === "author") && latestReconHasRequiredBaselines(state) && hasReconBaselineUnderstanding(state)) {
1801
+ updateState(config.statePath, (currentState) => {
1802
+ promoteLatestReconBaselines(currentState);
1803
+ currentState.recon_status = "ready_for_proof_plan";
1804
+ currentState.recon_results = currentState.recon_results || {};
1805
+ currentState.recon_results.status = "ready_for_proof_plan";
1806
+ currentState.recon_assessment_request = {};
1807
+ currentState.recon_decision_request = {};
1808
+ if ((currentState.proof_plan || "").trim() && (currentState.capture_script || "").trim()) {
1809
+ currentState.author_status = "ready";
1810
+ currentState.proof_plan_status = "ready";
1811
+ } else if (!authorReady(currentState)) {
1812
+ currentState.author_status = "needs_authoring";
1813
+ currentState.proof_plan_status = "needs_authoring";
1814
+ }
1815
+ });
1816
+ state = readState(config.statePath);
1817
+ const approvedSummary = latestAssessment.summary || "The supervising agent approved the latest recon baseline and selected the route for proof authoring.";
1818
+ if (params.advance_stage === "recon") {
1819
+ recordAttempt("recon", "completed", approvedSummary, {
1820
+ checkpoint: "recon_review",
1821
+ details: {
1822
+ ...reconDetails,
1823
+ promotedBaselines: latestReconCapturedBaselines(state)
1824
+ }
1825
+ });
1826
+ return checkpoint(
1827
+ "recon",
1828
+ "recon_review",
1829
+ approvedSummary,
1830
+ {
1831
+ nextActions: ["inspect_recon_baseline", "continue_internal_loop_with_checkpoint", "advance_run_to_author"],
1832
+ advanceOptions: ["author", "recon", "implement"],
1833
+ recommendedAdvanceStage: "author",
1834
+ continueWithStage: "author",
1835
+ blocking: false,
1836
+ details: {
1837
+ ...reconDetails,
1838
+ promotedBaselines: latestReconCapturedBaselines(state)
1839
+ },
1840
+ reconAssessment: latestAssessment.raw,
1841
+ executed
1842
+ }
1843
+ );
1844
+ }
1845
+ recordAttempt("recon", "completed", approvedSummary, {
1846
+ checkpoint: "recon_auto_continue",
1847
+ details: {
1848
+ ...reconDetails,
1849
+ promotedBaselines: latestReconCapturedBaselines(state)
1850
+ }
1851
+ });
1852
+ effectiveAdvanceStage = "author";
1853
+ updateState(config.statePath, (currentState) => {
1854
+ currentState.last_requested_advance_stage = "author";
1855
+ });
1856
+ state = readState(config.statePath);
1857
+ requestedStage = normalizeStageRequest(state, effectiveAdvanceStage);
1858
+ } else if (latestAssessment.decision === "ready_for_author") {
1859
+ const missingUnderstanding = latestReconHasRequiredBaselines(state) && !hasReconBaselineUnderstanding(state);
1860
+ return checkpoint(
1861
+ "recon",
1862
+ "recon_supervisor_judgment",
1863
+ missingUnderstanding ? "The supervising agent tried to approve recon, but did not provide a concrete baseline_understanding. The before evidence must be understood before proof authoring or code edits begin." : "The supervising agent tried to approve recon, but the latest attempt is still missing one or more required baseline screenshots. Retry recon with a better plan or declare the loop genuinely stuck.",
1864
+ {
1865
+ ok: false,
1866
+ nextActions: ["inspect_recon_packet", "refine_recon_plan", "continue_internal_loop_with_checkpoint"],
1867
+ advanceOptions: ["recon", "author"],
1868
+ recommendedAdvanceStage: "recon",
1869
+ continueWithStage: "recon",
1870
+ blocking: false,
1871
+ details: reconDetails,
1872
+ reconAssessment: latestAssessment.raw,
1873
+ reconAssessmentRequest,
1874
+ executed
1875
+ }
1876
+ );
1877
+ } else {
1878
+ updateState(config.statePath, (currentState) => {
1879
+ currentState.recon_status = "";
1880
+ currentState.recon_assessment = {};
1881
+ currentState.recon_assessment_source = null;
1882
+ currentState.recon_assessment_request = {};
1883
+ currentState.recon_decision_request = {};
1884
+ currentState.before_cdn = "";
1885
+ currentState.prod_cdn = "";
1886
+ currentState.recon_results = currentState.recon_results || {};
1887
+ currentState.recon_results.baselines = {};
1888
+ currentState.recon_results.selected_attempt = {};
1889
+ currentState.recon_results.status = "retry_requested";
1890
+ });
1891
+ state = readState(config.statePath);
1892
+ }
1893
+ }
1894
+ if (!state?.recon_results || state?.stage === "setup" || state?.stage === "preflight" || ["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "") || requestedStage === "recon") {
1895
+ const reconRes = runOne("recon");
1896
+ executed.push(executedStep(reconRes));
1897
+ if (!reconRes.ok || reconRes.haltedForApproval) {
1898
+ return failedRun("recon", reconRes.haltedForApproval ? "recon halted for approval" : "recon failed", reconRes, {
1899
+ checkpoint: "recon_failed",
1900
+ details: { executed },
1901
+ executed
1902
+ });
1903
+ }
1904
+ state = readState(config.statePath);
1905
+ if (["needs_agent_decision", "needs_supervisor_judgment"].includes(state?.recon_status || "")) {
1906
+ const reconAssessmentRequest = state?.recon_assessment_request || state?.recon_decision_request || null;
1907
+ const summary = "Recon gathered route hints, candidate paths, baseline captures, and observations. The supervising agent should now judge whether the latest baseline is trustworthy, whether recon should retry/reframe, and whether recon is done.";
1908
+ const reconDetails = {
1909
+ executed,
1910
+ latestAttempt: latestReconAttempt(state),
1911
+ latestCapturedBaselines: latestReconCapturedBaselines(state),
1912
+ reconAssessmentRequest
1913
+ };
1914
+ recordAttempt("recon", "checkpoint", summary, {
1915
+ autoApproved: reconRes.autoApproved || false,
1916
+ checkpoint: "recon_supervisor_judgment",
1917
+ details: reconDetails
1918
+ });
1919
+ return checkpoint(
1920
+ "recon",
1921
+ "recon_supervisor_judgment",
1922
+ summary,
1923
+ {
1924
+ nextActions: ["inspect_recon_packet", "supply_recon_assessment_json", "continue_internal_loop_with_checkpoint"],
1925
+ advanceOptions: ["recon", "author"],
1926
+ recommendedAdvanceStage: "recon",
1927
+ continueWithStage: "recon",
1928
+ blocking: false,
1929
+ details: reconDetails,
1930
+ reconAssessmentRequest,
1931
+ reconDecisionRequest: state?.recon_decision_request || null,
1932
+ executed
1933
+ }
1934
+ );
1935
+ }
1936
+ recordAttempt("recon", "completed", "Recon completed and promoted an approved baseline context.", {
1937
+ autoApproved: reconRes.autoApproved || false,
1938
+ details: { executed }
1939
+ });
1940
+ }
1941
+ state = readState(config.statePath);
1942
+ if (!authorReady(state) || effectiveAdvanceStage === "author") {
1943
+ const authorRes = runOne("author");
1944
+ executed.push(executedStep(authorRes));
1945
+ if (!authorRes.ok || authorRes.haltedForApproval) {
1946
+ return failedRun("author", authorRes.haltedForApproval ? "author halted for approval" : "author failed", authorRes, {
1947
+ checkpoint: "author_failed",
1948
+ details: { executed },
1949
+ executed
1950
+ });
1951
+ }
1952
+ state = readState(config.statePath);
1953
+ if (!authorReady(state)) {
1954
+ recordAttempt("author", "checkpoint", "Author prepared a supervisor judgment request instead of delegating proof authoring to an internal model.", {
1955
+ autoApproved: authorRes.autoApproved || false,
1956
+ checkpoint: "author_supervisor_judgment",
1957
+ details: {
1958
+ executed,
1959
+ authorSummary: state?.author_summary || null,
1960
+ authorRequest: state?.author_request || null,
1961
+ serverPath: state?.server_path || null,
1962
+ waitForSelector: state?.wait_for_selector || null
1963
+ }
1964
+ });
1965
+ return checkpoint(
1966
+ "author",
1967
+ "author_supervisor_judgment",
1968
+ "Author distilled recon into a proof-authoring request. The supervising agent should supply the proof packet, then resume the workflow.",
1969
+ {
1970
+ nextActions: ["inspect_author_request", "supply_author_packet_json_or_proof_plan", "continue_internal_loop_with_checkpoint"],
1971
+ advanceOptions: ["author", "recon", "implement", "verify"],
1972
+ recommendedAdvanceStage: "author",
1973
+ continueWithStage: "author",
1974
+ details: {
1975
+ executed,
1976
+ authorSummary: state?.author_summary || null,
1977
+ authorRequest: state?.author_request || null,
1978
+ proofPlanDraft: state?.author_request?.fallback_defaults?.proof_plan || null,
1979
+ captureScriptDraft: state?.author_request?.fallback_defaults?.capture_script || null,
1980
+ serverPathDraft: state?.author_request?.fallback_defaults?.server_path || null,
1981
+ waitForSelectorDraft: state?.author_request?.fallback_defaults?.wait_for_selector || null
1982
+ },
1983
+ authorSummary: state?.author_summary || null,
1984
+ authorRequest: state?.author_request || null,
1985
+ proofPlanDraft: state?.author_request?.fallback_defaults?.proof_plan || null,
1986
+ captureScriptDraft: state?.author_request?.fallback_defaults?.capture_script || null,
1987
+ serverPathDraft: state?.author_request?.fallback_defaults?.server_path || null,
1988
+ waitForSelectorDraft: state?.author_request?.fallback_defaults?.wait_for_selector || null,
1989
+ executed
1990
+ }
1991
+ );
1992
+ }
1993
+ const authorNextStage = stageAfterAuthor(state);
1994
+ const explicitAuthorDebug = params.advance_stage === "author";
1995
+ recordAttempt("author", "completed", "Author applied the supervising agent's proof packet to recon observations.", {
1996
+ autoApproved: authorRes.autoApproved || false,
1997
+ checkpoint: explicitAuthorDebug ? "author_review" : "author_auto_continue",
1998
+ details: {
1999
+ executed,
2000
+ authorSummary: state?.author_summary || null,
2001
+ authorModel: state?.author_model || null,
2002
+ authorRuntimeModelHint: state?.author_runtime_model_hint || null,
2003
+ serverPath: state?.server_path || null,
2004
+ waitForSelector: state?.wait_for_selector || null
2005
+ }
2006
+ });
2007
+ if (explicitAuthorDebug) {
2008
+ return checkpoint(
2009
+ "author",
2010
+ "author_review",
2011
+ authorNextStage === "verify" ? "Author applied the supervising agent's proof packet. Because implementation is already recorded, you can continue straight into verify." : "Author applied the supervising agent's proof packet. Inspect it if needed, then continue into implement.",
2012
+ {
2013
+ nextActions: authorNextStage === "verify" ? ["inspect_proof_packet", "advance_run_to_verify", "rerun_author"] : ["inspect_proof_packet", "advance_run_to_implement", "rerun_author"],
2014
+ advanceOptions: authorNextStage === "verify" ? ["author", "verify", "recon"] : ["author", "implement", "recon"],
2015
+ recommendedAdvanceStage: authorNextStage,
2016
+ continueWithStage: authorNextStage,
2017
+ details: {
2018
+ executed,
2019
+ authorSummary: state?.author_summary || null,
2020
+ authorModel: state?.author_model || null,
2021
+ authorRuntimeModelHint: state?.author_runtime_model_hint || null,
2022
+ proofPlan: state?.proof_plan || null,
2023
+ serverPath: state?.server_path || null,
2024
+ waitForSelector: state?.wait_for_selector || null
2025
+ },
2026
+ authorSummary: state?.author_summary || null,
2027
+ authorModel: state?.author_model || null,
2028
+ authorRuntimeModelHint: state?.author_runtime_model_hint || null,
2029
+ proofPlan: state?.proof_plan || null,
2030
+ serverPath: state?.server_path || null,
2031
+ waitForSelector: state?.wait_for_selector || null,
2032
+ executed
2033
+ }
2034
+ );
2035
+ }
2036
+ effectiveAdvanceStage = authorNextStage;
2037
+ updateState(config.statePath, (currentState) => {
2038
+ currentState.last_requested_advance_stage = authorNextStage;
2039
+ });
2040
+ state = readState(config.statePath);
2041
+ }
2042
+ if (!effectiveAdvanceStage) {
2043
+ const recommended = recommendedAdvanceStage(state);
2044
+ return checkpoint(
2045
+ recommended || "implement",
2046
+ "awaiting_stage_advance",
2047
+ "Proof authoring is ready. The wrapper will not guess the next stage from here, explicitly choose whether to revisit recon/author, validate implementation, capture verify evidence, or ship.",
2048
+ {
2049
+ nextActions: ["inspect_state", "set_advance_stage", "resume_run"],
2050
+ advanceOptions: ["recon", "author", "implement", "verify", "ship"],
2051
+ recommendedAdvanceStage: recommended,
2052
+ details: { executed },
2053
+ executed
2054
+ }
2055
+ );
2056
+ }
2057
+ if (effectiveAdvanceStage === "implement") {
2058
+ const implementRes = runOne("implement");
2059
+ executed.push(executedStep(implementRes));
2060
+ if (implementRes.haltedForApproval) {
2061
+ return failedRun("implement", "implement halted for approval", implementRes, {
2062
+ checkpoint: "implement_blocked",
2063
+ details: { executed },
2064
+ executed
2065
+ });
2066
+ }
2067
+ if (!implementRes.ok) {
2068
+ const implementError = `${implementRes.error || ""}
2069
+ ${implementRes.stdout || ""}
2070
+ ${implementRes.stderr || ""}`;
2071
+ if (implementError.includes("No implementation detected")) {
2072
+ recordAttempt("implement", "checkpoint", "Implementation checkpoint found no material code changes yet.", {
2073
+ checkpoint: "implement_changes_missing",
2074
+ error: implementRes.error || null,
2075
+ details: { executed }
2076
+ });
2077
+ return checkpoint(
2078
+ "implement",
2079
+ "implement_changes_missing",
2080
+ "Proof plan is ready, but code changes are not recorded yet. Make the implementation changes on the after worktree, then resume run.",
2081
+ {
2082
+ nextActions: ["make_code_changes", "rerun_implement"],
2083
+ advanceOptions: ["implement", "author", "recon"],
2084
+ recommendedAdvanceStage: "implement",
2085
+ blocking: true,
2086
+ details: { executed },
2087
+ executed
2088
+ }
2089
+ );
2090
+ }
2091
+ return failedRun("implement", "implement failed", implementRes, {
2092
+ checkpoint: "implement_failed",
2093
+ details: { executed },
2094
+ executed
2095
+ });
2096
+ }
2097
+ let invalidatedVerifyEvidence2 = false;
2098
+ updateState(config.statePath, (state2) => {
2099
+ invalidatedVerifyEvidence2 = invalidateVerifyEvidence(state2).invalidated;
2100
+ });
2101
+ recordAttempt("implement", "completed", "Implementation checkpoint recorded code changes on the after worktree.", {
2102
+ autoApproved: implementRes.autoApproved || false,
2103
+ checkpoint: "implement_review",
2104
+ details: { executed, invalidatedVerifyEvidence: invalidatedVerifyEvidence2 }
2105
+ });
2106
+ return checkpoint(
2107
+ "implement",
2108
+ "implement_review",
2109
+ invalidatedVerifyEvidence2 ? "Implementation changes were detected and prior verify evidence was invalidated. Inspect the branch diff or notes, then explicitly choose whether to iterate implementation again or advance to verify." : "Implementation changes were detected. Inspect the branch diff or notes, then explicitly choose whether to iterate implementation again or advance to verify.",
2110
+ {
2111
+ nextActions: ["inspect_branch_diff", "rerun_implement", "advance_run_to_verify"],
2112
+ advanceOptions: ["implement", "author", "verify", "recon"],
2113
+ recommendedAdvanceStage: "verify",
2114
+ details: {
2115
+ executed,
2116
+ implementationSummary: readState(config.statePath)?.implementation_summary || null,
2117
+ invalidatedVerifyEvidence: invalidatedVerifyEvidence2
2118
+ },
2119
+ implementationSummary: readState(config.statePath)?.implementation_summary || null,
2120
+ invalidatedVerifyEvidence: invalidatedVerifyEvidence2,
2121
+ executed
2122
+ }
2123
+ );
2124
+ }
2125
+ if (effectiveAdvanceStage === "verify") {
2126
+ state = readState(config.statePath);
2127
+ if (!["changes_detected", "completed"].includes(state?.implementation_status || "")) {
2128
+ return checkpoint(
2129
+ "implement",
2130
+ "implement_required",
2131
+ "Verify is blocked until implementation has been recorded. Run the implement stage after making code changes, then resume verify.",
2132
+ {
2133
+ ok: false,
2134
+ nextActions: ["make_code_changes", "advance_run_to_implement"],
2135
+ advanceOptions: ["implement", "author", "recon"],
2136
+ recommendedAdvanceStage: "implement",
2137
+ continueWithStage: "implement",
2138
+ blocking: true,
2139
+ details: { executed },
2140
+ executed
2141
+ }
2142
+ );
2143
+ }
2144
+ const hasIncomingProofAssessment = typeof params.proof_assessment_json === "string" && params.proof_assessment_json.trim().length > 0;
2145
+ const canReuseVerifyEvidence = (params.advance_stage !== "verify" || hasIncomingProofAssessment) && state?.verify_status === "evidence_captured" && Boolean((state?.after_cdn || "").trim()) && (state?.active_checkpoint === "verify_supervisor_judgment" || hasSupervisorProofAssessment(state));
2146
+ let verifyRes = { ok: true, step: "verify", reusedEvidence: canReuseVerifyEvidence };
2147
+ if (!canReuseVerifyEvidence) {
2148
+ verifyRes = runOne("verify");
2149
+ executed.push(executedStep(verifyRes));
2150
+ if (!verifyRes.ok || verifyRes.haltedForApproval) {
2151
+ return failedRun("verify", verifyRes.haltedForApproval ? "verify halted for approval" : "verify failed", verifyRes, {
2152
+ checkpoint: "verify_failed",
2153
+ details: { executed },
2154
+ executed
2155
+ });
2156
+ }
2157
+ } else {
2158
+ executed.push(executedStep(verifyRes, { reusedEvidence: true }));
2159
+ }
2160
+ state = readState(config.statePath);
2161
+ const verifyStatus = state?.verify_status || ((state?.after_cdn || "").trim() ? "evidence_captured" : "capture_incomplete");
2162
+ const verifyDecisionRequest = state?.verify_decision_request || null;
2163
+ const verifySummary = state?.verify_summary || state?.proof_summary || null;
2164
+ const proofAssessment = verifyAssessment(state);
2165
+ const convergenceSignals = nonConvergenceSignals(state, proofAssessment);
2166
+ const verifyRecommendedStage = proofAssessment.recommendedStage || null;
2167
+ const verifyContinueWithStage = shouldEscalateVerifyToHuman(state, proofAssessment) ? null : proofAssessment.continueWithStage || verifyRecommendedStage || null;
2168
+ const verifyDetails = {
2169
+ executed,
2170
+ verifyStatus,
2171
+ verifySummary,
2172
+ afterCdn: state?.after_cdn || null,
2173
+ mergeRecommendation: state?.merge_recommendation || null,
2174
+ verifyDecisionRequest,
2175
+ proofAssessment: proofAssessment.raw,
2176
+ proofAssessmentSource: proofAssessment.source || null,
2177
+ proofAssessmentRequest: state?.proof_assessment_request || null,
2178
+ verifyRecommendedStage,
2179
+ verifyContinueWithStage,
2180
+ convergenceSignals
2181
+ };
2182
+ if (verifyStatus !== "evidence_captured") {
2183
+ if ((verifyContinueWithStage || verifyRecommendedStage || "author") === "author") {
2184
+ updateState(config.statePath, (currentState) => {
2185
+ currentState.author_status = "needs_authoring";
2186
+ currentState.proof_plan_status = "needs_authoring";
2187
+ currentState.supervisor_author_packet = null;
2188
+ });
2189
+ state = readState(config.statePath);
2190
+ }
2191
+ const checkpointName = "verify_capture_retry";
2192
+ const summary = "Verify ran, but the proof packet still needs internal capture-plan work before it should ship.";
2193
+ recordAttempt("verify", "checkpoint", summary, {
2194
+ autoApproved: verifyRes.autoApproved || false,
2195
+ checkpoint: checkpointName,
2196
+ details: verifyDetails
2197
+ });
2198
+ return checkpoint(
2199
+ "verify",
2200
+ checkpointName,
2201
+ summary,
2202
+ {
2203
+ ok: true,
2204
+ nextActions: ["inspect_after_capture", "continue_internal_loop_with_checkpoint", "return_to_recon_if_baseline_is_wrong"],
2205
+ advanceOptions: ["author", "verify", "implement", "recon"],
2206
+ recommendedAdvanceStage: verifyRecommendedStage || "author",
2207
+ continueWithStage: verifyContinueWithStage || "author",
2208
+ blocking: false,
2209
+ details: verifyDetails,
2210
+ verifyStatus,
2211
+ verifySummary,
2212
+ afterCdn: state?.after_cdn || null,
2213
+ mergeRecommendation: state?.merge_recommendation || null,
2214
+ verifyDecisionRequest,
2215
+ proofAssessment: proofAssessment.raw,
2216
+ executed
2217
+ }
2218
+ );
2219
+ }
2220
+ if (!hasSupervisorProofAssessment(state)) {
2221
+ const summary = "Verify captured usable evidence. The supervising agent should now assess whether the proof supports ship or more internal iteration, then resume the workflow with proof_assessment_json.";
2222
+ recordAttempt("verify", "checkpoint", summary, {
2223
+ autoApproved: verifyRes.autoApproved || false,
2224
+ checkpoint: "verify_supervisor_judgment",
2225
+ details: verifyDetails
2226
+ });
2227
+ return checkpoint(
2228
+ "verify",
2229
+ "verify_supervisor_judgment",
2230
+ summary,
2231
+ {
2232
+ nextActions: ["inspect_evidence", "author_proof_assessment_json", "continue_internal_loop_with_checkpoint"],
2233
+ advanceOptions: ["verify", "author", "implement", "recon", "ship"],
2234
+ recommendedAdvanceStage: "verify",
2235
+ continueWithStage: "verify",
2236
+ blocking: false,
2237
+ details: verifyDetails,
2238
+ verifyStatus,
2239
+ verifySummary,
2240
+ afterCdn: state?.after_cdn || null,
2241
+ mergeRecommendation: state?.merge_recommendation || null,
2242
+ verifyDecisionRequest,
2243
+ proofAssessmentRequest: state?.proof_assessment_request || null,
2244
+ executed
2245
+ }
2246
+ );
2247
+ }
2248
+ const shouldEscalate = shouldEscalateVerifyToHuman(state, proofAssessment);
2249
+ if (shouldEscalate) {
2250
+ const summary = "The supervising agent concluded the workflow hit a real wall and explicitly escalated the proof loop to the human.";
2251
+ recordAttempt("verify", "escalated", summary, {
2252
+ autoApproved: verifyRes.autoApproved || false,
2253
+ checkpoint: "verify_human_escalation",
2254
+ details: verifyDetails
2255
+ });
2256
+ return checkpoint(
2257
+ "verify",
2258
+ "verify_human_escalation",
2259
+ summary,
2260
+ {
2261
+ ok: false,
2262
+ nextActions: ["inspect_retry_history", "summarize_internal_loop", "ask_human_for_direction"],
2263
+ advanceOptions: ["author", "implement", "ship", "verify", "recon"],
2264
+ recommendedAdvanceStage: null,
2265
+ continueWithStage: null,
2266
+ blocking: true,
2267
+ details: verifyDetails,
2268
+ verifyStatus,
2269
+ verifySummary,
2270
+ afterCdn: state?.after_cdn || null,
2271
+ mergeRecommendation: state?.merge_recommendation || null,
2272
+ verifyDecisionRequest,
2273
+ proofAssessment: proofAssessment.raw,
2274
+ executed
2275
+ }
2276
+ );
2277
+ }
2278
+ const shouldAutoShip = verifyContinueWithStage === "ship" && (params.ship_after_verify || params.continue_from_checkpoint || params.advance_stage !== "verify");
2279
+ if (shouldAutoShip) {
2280
+ const shipGate = validateShipGate(state);
2281
+ if (!shipGate.ok) {
2282
+ recordAttempt("verify", "checkpoint", "Verify cannot continue into ship because the hard ship gate is missing required evidence or approval.", {
2283
+ autoApproved: verifyRes.autoApproved || false,
2284
+ checkpoint: "ship_gate_blocked",
2285
+ details: { ...verifyDetails, shipGate }
2286
+ });
2287
+ return shipGateBlocked(state, executed, verifyDetails);
2288
+ }
2289
+ recordAttempt("verify", "checkpoint", "Verify captured a strong proof packet and is continuing directly into ship.", {
2290
+ autoApproved: verifyRes.autoApproved || false,
2291
+ checkpoint: "verify_then_ship",
2292
+ details: { ...verifyDetails, shipGate }
2293
+ });
2294
+ const shipRes = runOne("ship");
2295
+ executed.push(executedStep(shipRes));
2296
+ if (!shipRes.ok || shipRes.haltedForApproval) {
2297
+ const shipNextAction = shipRes?.error && String(shipRes.error).includes("temporary proof branch") ? "product bug: ship resolved a temporary proof branch; resolve the PR head branch before retrying ship" : "inspect the ship error, confirm the PR head branch and verified commit, then retry ship";
2298
+ return failedRun("ship", shipRes.haltedForApproval ? "ship halted for approval" : "ship failed", shipRes, {
2299
+ checkpoint: "ship_failed",
2300
+ details: { executed, next_action: shipNextAction },
2301
+ nextAction: shipNextAction,
2302
+ executed
2303
+ });
2304
+ }
2305
+ recordAttempt("ship", "completed", "Ship updated the PR and posted proof artifacts after the supervising agent judged the proof strong enough.", {
2306
+ autoApproved: shipRes.autoApproved || false,
2307
+ checkpoint: "ship_review",
2308
+ details: { executed }
2309
+ });
2310
+ const snapshot2 = snapshotFor(config.statePath);
2311
+ const summary = "The supervising agent judged the proof strong enough, so the workflow shipped automatically and left the PR as the main human review surface.";
2312
+ const finalState = readState(config.statePath);
2313
+ const shipReport = finalState?.ship_report || snapshot2.state?.ship_report || null;
2314
+ return {
2315
+ ok: true,
2316
+ action,
2317
+ state_path: config.statePath,
2318
+ stage: snapshot2.stage,
2319
+ checkpoint: "ship_review",
2320
+ summary,
2321
+ state: snapshot2.state,
2322
+ shipReport,
2323
+ checkpointContract: buildCheckpointContract(readState(config.statePath), {
2324
+ statePath: config.statePath,
2325
+ stage: "ship",
2326
+ checkpoint: "ship_review",
2327
+ summary,
2328
+ nextActions: ["inspect_pr", "rerun_ship_if_needed"],
2329
+ advanceOptions: ["ship", "verify", "author", "implement"],
2330
+ recommendedAdvanceStage: "ship"
2331
+ }),
2332
+ executed
2333
+ };
2334
+ }
2335
+ if (proofAssessment.decision === "ready_to_ship") {
2336
+ const shipGate = validateShipGate(state);
2337
+ if (!shipGate.ok) {
2338
+ recordAttempt("verify", "checkpoint", "Verify cannot mark ship ready because the hard ship gate is missing required evidence or approval.", {
2339
+ autoApproved: verifyRes.autoApproved || false,
2340
+ checkpoint: "ship_gate_blocked",
2341
+ details: { ...verifyDetails, shipGate }
2342
+ });
2343
+ return shipGateBlocked(state, executed, verifyDetails);
2344
+ }
2345
+ recordAttempt("verify", "checkpoint", "Verify captured a strong proof packet and is ready to continue into ship.", {
2346
+ autoApproved: verifyRes.autoApproved || false,
2347
+ checkpoint: "verify_ship_ready",
2348
+ details: { ...verifyDetails, shipGate }
2349
+ });
2350
+ return checkpoint(
2351
+ "verify",
2352
+ "verify_ship_ready",
2353
+ "The supervising agent judged the proof strong enough to continue into ship.",
2354
+ {
2355
+ nextActions: ["inspect_evidence", "continue_internal_loop_with_checkpoint", "advance_run_to_ship_if_you_need_manual_control"],
2356
+ advanceOptions: ["ship", "verify", "author", "implement", "recon"],
2357
+ recommendedAdvanceStage: "ship",
2358
+ continueWithStage: "ship",
2359
+ blocking: false,
2360
+ details: { ...verifyDetails, shipGate },
2361
+ shipGate,
2362
+ verifyStatus,
2363
+ verifySummary,
2364
+ afterCdn: state?.after_cdn || null,
2365
+ mergeRecommendation: state?.merge_recommendation || null,
2366
+ verifyDecisionRequest,
2367
+ proofAssessment: proofAssessment.raw,
2368
+ executed
2369
+ }
2370
+ );
2371
+ }
2372
+ if (verifyContinueWithStage === "author") {
2373
+ updateState(config.statePath, (currentState) => {
2374
+ currentState.author_status = "needs_authoring";
2375
+ currentState.proof_plan_status = "needs_authoring";
2376
+ currentState.supervisor_author_packet = null;
2377
+ });
2378
+ state = readState(config.statePath);
2379
+ }
2380
+ const unresolvedSummary = convergenceSignals.warning ? "The supervising agent kept the workflow in the internal loop, but retry history suggests it may not be converging yet. Keep iterating internally or explicitly escalate with escalation_target=human when you conclude it is genuinely stuck." : "The supervising agent judged that the workflow should keep iterating internally before it ships.";
2381
+ recordAttempt("verify", "checkpoint", unresolvedSummary, {
2382
+ autoApproved: verifyRes.autoApproved || false,
2383
+ checkpoint: "verify_agent_retry",
2384
+ details: verifyDetails
2385
+ });
2386
+ return checkpoint(
2387
+ "verify",
2388
+ "verify_agent_retry",
2389
+ unresolvedSummary,
2390
+ {
2391
+ ok: true,
2392
+ nextActions: convergenceSignals.warning ? ["inspect_retry_history", "decide_whether_to_keep_iterating_or_escalate", "continue_internal_loop_with_checkpoint"] : ["inspect_proof_assessment", "continue_internal_loop_with_checkpoint", "return_to_implement_if_fix_failed"],
2393
+ advanceOptions: ["author", "implement", "ship", "verify", "recon"],
2394
+ recommendedAdvanceStage: verifyRecommendedStage,
2395
+ continueWithStage: verifyContinueWithStage,
2396
+ blocking: false,
2397
+ details: verifyDetails,
2398
+ verifyStatus,
2399
+ verifySummary,
2400
+ afterCdn: state?.after_cdn || null,
2401
+ mergeRecommendation: state?.merge_recommendation || null,
2402
+ verifyDecisionRequest,
2403
+ proofAssessment: proofAssessment.raw,
2404
+ executed
2405
+ }
2406
+ );
2407
+ }
2408
+ if (effectiveAdvanceStage === "ship") {
2409
+ state = readState(config.statePath);
2410
+ const shipAssessment = verifyAssessment(state);
2411
+ const shipGate = validateShipGate(state);
2412
+ if (state?.verify_status !== "evidence_captured") {
2413
+ return checkpoint(
2414
+ "verify",
2415
+ "verify_required",
2416
+ "Ship is blocked until verify has captured a usable proof packet. Run verify, inspect the evidence, then explicitly advance to ship only if the proof supports success.",
2417
+ {
2418
+ ok: false,
2419
+ nextActions: ["advance_run_to_verify", "inspect_verify_state"],
2420
+ advanceOptions: ["verify", "author", "implement", "recon"],
2421
+ recommendedAdvanceStage: "verify",
2422
+ continueWithStage: "verify",
2423
+ blocking: true,
2424
+ details: {
2425
+ executed,
2426
+ shipGate,
2427
+ verifyStatus: state?.verify_status || null,
2428
+ mergeRecommendation: state?.merge_recommendation || null,
2429
+ afterCdn: state?.after_cdn || null
2430
+ },
2431
+ shipGate,
2432
+ verifyStatus: state?.verify_status || null,
2433
+ mergeRecommendation: state?.merge_recommendation || null,
2434
+ afterCdn: state?.after_cdn || null,
2435
+ executed
2436
+ }
2437
+ );
2438
+ }
2439
+ if (!hasSupervisorProofAssessment(state) || shipAssessment.decision !== "ready_to_ship") {
2440
+ return checkpoint(
2441
+ "verify",
2442
+ "verify_supervisor_judgment_required",
2443
+ "Ship is blocked until the supervising agent judges the current proof packet as ready_to_ship.",
2444
+ {
2445
+ ok: false,
2446
+ nextActions: ["inspect_evidence", "supply_proof_assessment_json", "continue_internal_loop_with_checkpoint"],
2447
+ advanceOptions: ["verify", "author", "implement", "recon", "ship"],
2448
+ recommendedAdvanceStage: "verify",
2449
+ continueWithStage: "verify",
2450
+ blocking: true,
2451
+ details: {
2452
+ executed,
2453
+ shipGate,
2454
+ verifyStatus: state?.verify_status || null,
2455
+ mergeRecommendation: state?.merge_recommendation || null,
2456
+ afterCdn: state?.after_cdn || null,
2457
+ proofAssessment: state?.proof_assessment || null,
2458
+ proofAssessmentRequest: state?.proof_assessment_request || null
2459
+ },
2460
+ shipGate,
2461
+ verifyStatus: state?.verify_status || null,
2462
+ mergeRecommendation: state?.merge_recommendation || null,
2463
+ afterCdn: state?.after_cdn || null,
2464
+ proofAssessment: state?.proof_assessment || null,
2465
+ proofAssessmentRequest: state?.proof_assessment_request || null,
2466
+ executed
2467
+ }
2468
+ );
2469
+ }
2470
+ if (!shipGate.ok) {
2471
+ return shipGateBlocked(state, executed, { shipAssessment: shipAssessment.raw });
2472
+ }
2473
+ const shipRes = runOne("ship");
2474
+ executed.push(executedStep(shipRes));
2475
+ if (!shipRes.ok || shipRes.haltedForApproval) {
2476
+ return failedRun("ship", shipRes.haltedForApproval ? "ship halted for approval" : "ship failed", shipRes, {
2477
+ checkpoint: "ship_failed",
2478
+ details: { executed },
2479
+ executed
2480
+ });
2481
+ }
2482
+ recordAttempt("ship", "completed", "Ship updated the PR and posted proof artifacts.", {
2483
+ autoApproved: shipRes.autoApproved || false,
2484
+ checkpoint: "ship_review",
2485
+ details: { executed }
2486
+ });
2487
+ return checkpoint(
2488
+ "ship",
2489
+ "ship_review",
2490
+ "Ship completed. Review the PR, proof comment, and cleanup results. Re-run ship if you need to refresh the PR after more changes.",
2491
+ {
2492
+ nextActions: ["inspect_pr", "rerun_ship_if_needed"],
2493
+ advanceOptions: ["ship", "verify", "author", "implement"],
2494
+ recommendedAdvanceStage: "ship",
2495
+ details: {
2496
+ executed,
2497
+ prUrl: readState(config.statePath)?.pr_url || null
2498
+ },
2499
+ prUrl: readState(config.statePath)?.pr_url || null,
2500
+ executed
2501
+ }
2502
+ );
2503
+ }
2504
+ }
2505
+ if (action === "ship") {
2506
+ const state = readState(config.statePath);
2507
+ const shipGate = validateShipGate(state);
2508
+ if (state?.verify_status !== "evidence_captured") {
2509
+ return checkpoint(
2510
+ "verify",
2511
+ "verify_required",
2512
+ "Ship is blocked until verify has captured a usable proof packet. Run verify, inspect the evidence, then ship only if the proof supports success.",
2513
+ {
2514
+ ok: false,
2515
+ nextActions: ["run_verify", "inspect_verify_state"],
2516
+ advanceOptions: ["verify", "author", "implement", "recon"],
2517
+ recommendedAdvanceStage: "verify",
2518
+ continueWithStage: "verify",
2519
+ blocking: true,
2520
+ details: { shipGate },
2521
+ shipGate,
2522
+ verifyStatus: state?.verify_status || null,
2523
+ mergeRecommendation: state?.merge_recommendation || null,
2524
+ afterCdn: state?.after_cdn || null
2525
+ }
2526
+ );
2527
+ }
2528
+ if (!hasSupervisorProofAssessment(state) || verifyAssessment(state).decision !== "ready_to_ship") {
2529
+ return checkpoint(
2530
+ "verify",
2531
+ "verify_supervisor_judgment_required",
2532
+ "Ship is blocked until the supervising agent judges the current proof packet as ready_to_ship.",
2533
+ {
2534
+ ok: false,
2535
+ nextActions: ["inspect_evidence", "supply_proof_assessment_json", "rerun_ship"],
2536
+ advanceOptions: ["verify", "author", "implement", "recon", "ship"],
2537
+ recommendedAdvanceStage: "verify",
2538
+ continueWithStage: "verify",
2539
+ blocking: true,
2540
+ details: { shipGate },
2541
+ shipGate,
2542
+ verifyStatus: state?.verify_status || null,
2543
+ mergeRecommendation: state?.merge_recommendation || null,
2544
+ afterCdn: state?.after_cdn || null,
2545
+ proofAssessment: state?.proof_assessment || null,
2546
+ proofAssessmentRequest: state?.proof_assessment_request || null
2547
+ }
2548
+ );
2549
+ }
2550
+ if (!shipGate.ok) {
2551
+ return shipGateBlocked(state, [], {});
2552
+ }
2553
+ }
2554
+ const single = runOne(action);
2555
+ if (!single.ok || single.haltedForApproval) {
2556
+ return failedRun(action, single.haltedForApproval ? `${action} halted for approval` : `${action} failed`, single, {
2557
+ checkpoint: `${action}_failed`
2558
+ });
2559
+ }
2560
+ let invalidatedVerifyEvidence = false;
2561
+ updateState(config.statePath, (state) => {
2562
+ if (action === "implement") {
2563
+ invalidatedVerifyEvidence = invalidateVerifyEvidence(state).invalidated;
2564
+ }
2565
+ clearStageDecisionRequest(state);
2566
+ });
2567
+ const singleSummary = action === "implement" && invalidatedVerifyEvidence ? "implement completed and invalidated prior verify evidence" : `${action} completed`;
2568
+ recordAttempt(action, "completed", singleSummary, {
2569
+ autoApproved: single.autoApproved || false,
2570
+ details: action === "implement" ? { invalidatedVerifyEvidence } : {}
2571
+ });
2572
+ const snapshot = snapshotFor(config.statePath);
2573
+ return {
2574
+ ok: true,
2575
+ action,
2576
+ state_path: config.statePath,
2577
+ stage: snapshot.stage,
2578
+ summary: singleSummary,
2579
+ state: snapshot.state,
2580
+ approval: null,
2581
+ autoApproved: single.autoApproved || false,
2582
+ error: null
2583
+ };
2584
+ }
2585
+ function createRiddleProofEngine(pluginConfig = {}) {
2586
+ return {
2587
+ execute(params) {
2588
+ const config = resolveConfig(pluginConfig, params);
2589
+ return executeWorkflow(params, pluginConfig, config);
2590
+ },
2591
+ status(statePath) {
2592
+ const config = resolveConfig(pluginConfig, { action: "status", state_path: statePath });
2593
+ return executeWorkflow({ action: "status", state_path: statePath }, pluginConfig, config);
2594
+ },
2595
+ resolveConfig(params = {}) {
2596
+ return resolveConfig(pluginConfig, params);
2597
+ }
2598
+ };
2599
+ }
2600
+ var import_node_child_process, import_node_fs2, import_node_path2, RUNTIME_EVENT_LIMIT;
2601
+ var init_proof_run_engine = __esm({
2602
+ "src/proof-run-engine.ts"() {
2603
+ "use strict";
2604
+ import_node_child_process = require("child_process");
2605
+ import_node_fs2 = require("fs");
2606
+ import_node_path2 = __toESM(require("path"), 1);
2607
+ init_proof_run_core();
2608
+ RUNTIME_EVENT_LIMIT = 100;
2609
+ }
2610
+ });
2611
+
30
2612
  // src/index.ts
31
2613
  var index_exports = {};
32
2614
  __export(index_exports, {
@@ -970,31 +3552,47 @@ async function runRiddleProof(input) {
970
3552
  }
971
3553
 
972
3554
  // src/engine-harness.ts
973
- var import_node_child_process = require("child_process");
974
- var import_node_fs = require("fs");
975
- var import_node_path = __toESM(require("path"), 1);
976
- var import_node_crypto = __toESM(require("crypto"), 1);
3555
+ var import_node_child_process2 = require("child_process");
3556
+ var import_node_fs3 = require("fs");
3557
+ var import_node_path3 = __toESM(require("path"), 1);
3558
+ var import_node_crypto2 = __toESM(require("crypto"), 1);
977
3559
  function timestamp2() {
978
3560
  return (/* @__PURE__ */ new Date()).toISOString();
979
3561
  }
980
3562
  function createHarnessStatePath(stateDir) {
981
3563
  const stamp = timestamp2().replace(/\D/g, "").slice(0, 14) || "unknown";
982
- return import_node_path.default.join(stateDir, `riddle-proof-run-${stamp}-${import_node_crypto.default.randomUUID().slice(0, 8)}.json`);
3564
+ return import_node_path3.default.join(stateDir, `riddle-proof-run-${stamp}-${import_node_crypto2.default.randomUUID().slice(0, 8)}.json`);
3565
+ }
3566
+ function createEngineStatePath(state, config) {
3567
+ const existing = nonEmptyString(state.request.engine_state_path);
3568
+ if (existing) return existing;
3569
+ const harnessStatePath = nonEmptyString(state.state_path);
3570
+ if (harnessStatePath) {
3571
+ const dir = import_node_path3.default.dirname(harnessStatePath);
3572
+ const base = import_node_path3.default.basename(harnessStatePath);
3573
+ if (base.startsWith("riddle-proof-run-")) {
3574
+ return import_node_path3.default.join(dir, base.replace("riddle-proof-run-", "riddle-proof-state-"));
3575
+ }
3576
+ return import_node_path3.default.join(dir, `${base}.engine-state.json`);
3577
+ }
3578
+ const stateDir = config?.stateDir || "/tmp";
3579
+ const stamp = timestamp2().replace(/\D/g, "").slice(0, 14) || "unknown";
3580
+ return import_node_path3.default.join(stateDir, `riddle-proof-state-${stamp}-${import_node_crypto2.default.randomUUID().slice(0, 8)}.json`);
983
3581
  }
984
3582
  function ensureParent(filePath) {
985
- (0, import_node_fs.mkdirSync)(import_node_path.default.dirname(filePath), { recursive: true });
3583
+ (0, import_node_fs3.mkdirSync)(import_node_path3.default.dirname(filePath), { recursive: true });
986
3584
  }
987
3585
  function readJson(filePath) {
988
- if (!filePath || !(0, import_node_fs.existsSync)(filePath)) return null;
3586
+ if (!filePath || !(0, import_node_fs3.existsSync)(filePath)) return null;
989
3587
  try {
990
- return JSON.parse((0, import_node_fs.readFileSync)(filePath, "utf-8"));
3588
+ return JSON.parse((0, import_node_fs3.readFileSync)(filePath, "utf-8"));
991
3589
  } catch {
992
3590
  return null;
993
3591
  }
994
3592
  }
995
3593
  function writeJson(filePath, payload) {
996
3594
  ensureParent(filePath);
997
- (0, import_node_fs.writeFileSync)(filePath, JSON.stringify(payload, null, 2) + "\n");
3595
+ (0, import_node_fs3.writeFileSync)(filePath, JSON.stringify(payload, null, 2) + "\n");
998
3596
  }
999
3597
  function loadRunState(input) {
1000
3598
  if (input.state) return input.state;
@@ -1023,6 +3621,18 @@ function heartbeat(state, input) {
1023
3621
  function jsonParam(payload) {
1024
3622
  return JSON.stringify(payload);
1025
3623
  }
3624
+ function redactedWorkflowParams(params) {
3625
+ const secretKeys = /* @__PURE__ */ new Set([
3626
+ "auth_localStorage_json",
3627
+ "auth_cookies_json",
3628
+ "auth_headers_json"
3629
+ ]);
3630
+ const output = {};
3631
+ for (const [key, value] of Object.entries(params)) {
3632
+ output[key] = secretKeys.has(key) && value ? "[redacted]" : value;
3633
+ }
3634
+ return output;
3635
+ }
1026
3636
  function engineStatePath(result, state) {
1027
3637
  return nonEmptyString(result.state_path) || nonEmptyString(state.request.engine_state_path);
1028
3638
  }
@@ -1033,9 +3643,9 @@ function workdirFromState(state) {
1033
3643
  return nonEmptyString(state?.after_worktree) || nonEmptyString(state?.worktree_path) || null;
1034
3644
  }
1035
3645
  function hasGitDiff(workdir) {
1036
- if (!workdir || !(0, import_node_fs.existsSync)(workdir)) return false;
3646
+ if (!workdir || !(0, import_node_fs3.existsSync)(workdir)) return false;
1037
3647
  try {
1038
- const status = (0, import_node_child_process.execFileSync)("git", ["status", "--porcelain"], {
3648
+ const status = (0, import_node_child_process2.execFileSync)("git", ["status", "--porcelain"], {
1039
3649
  cwd: workdir,
1040
3650
  encoding: "utf-8",
1041
3651
  timeout: 1e4
@@ -1046,18 +3656,18 @@ function hasGitDiff(workdir) {
1046
3656
  }
1047
3657
  }
1048
3658
  function removeEmptyToolArtifacts(workdir) {
1049
- if (!workdir || !(0, import_node_fs.existsSync)(workdir)) return [];
1050
- const artifactPath = import_node_path.default.join(workdir, ".codex");
1051
- if (!(0, import_node_fs.existsSync)(artifactPath)) return [];
3659
+ if (!workdir || !(0, import_node_fs3.existsSync)(workdir)) return [];
3660
+ const artifactPath = import_node_path3.default.join(workdir, ".codex");
3661
+ if (!(0, import_node_fs3.existsSync)(artifactPath)) return [];
1052
3662
  try {
1053
- const status = (0, import_node_child_process.execFileSync)("git", ["status", "--porcelain", "--", ".codex"], {
3663
+ const status = (0, import_node_child_process2.execFileSync)("git", ["status", "--porcelain", "--", ".codex"], {
1054
3664
  cwd: workdir,
1055
3665
  encoding: "utf-8",
1056
3666
  timeout: 1e4
1057
3667
  }).trim();
1058
- const stat = (0, import_node_fs.statSync)(artifactPath);
3668
+ const stat = (0, import_node_fs3.statSync)(artifactPath);
1059
3669
  if (status.startsWith("?? ") && stat.isFile() && stat.size === 0) {
1060
- (0, import_node_fs.unlinkSync)(artifactPath);
3670
+ (0, import_node_fs3.unlinkSync)(artifactPath);
1061
3671
  return [".codex"];
1062
3672
  }
1063
3673
  } catch {
@@ -1139,12 +3749,12 @@ function initialRunParams(request, input, state) {
1139
3749
  function effectiveShipMode(request, config) {
1140
3750
  return request.ship_mode || config?.defaultShipMode || "ship";
1141
3751
  }
1142
- function checkpointContinueStage(result) {
3752
+ function checkpointContinueStage2(result) {
1143
3753
  const resume = recordValue(result.checkpointContract?.resume);
1144
3754
  return nonEmptyString(resume?.continue_with_stage);
1145
3755
  }
1146
3756
  function recommendedContinuation(result) {
1147
- const continueStage = checkpointContinueStage(result);
3757
+ const continueStage = checkpointContinueStage2(result);
1148
3758
  if (!continueStage) return null;
1149
3759
  return {
1150
3760
  action: "run",
@@ -1288,7 +3898,11 @@ async function resolveEngine(input) {
1288
3898
  if (input.engine) return input.engine;
1289
3899
  const moduleUrl = input.config?.riddleEngineModuleUrl;
1290
3900
  if (!moduleUrl) {
1291
- throw new Error("No riddle engine adapter or riddleEngineModuleUrl is configured.");
3901
+ const mod2 = await Promise.resolve().then(() => (init_proof_run_engine(), proof_run_engine_exports));
3902
+ return mod2.createRiddleProofEngine({
3903
+ riddleProofDir: input.config?.riddleProofDir,
3904
+ defaultReviewer: input.config?.defaultReviewer
3905
+ });
1292
3906
  }
1293
3907
  const mod = await import(moduleUrl);
1294
3908
  if (typeof mod.createRiddleProofEngine !== "function") {
@@ -1305,7 +3919,7 @@ async function handleImplementation(request, state, result, agent) {
1305
3919
  state.worktree_path = workdir || state.worktree_path;
1306
3920
  state.branch = nonEmptyString(context.fullRiddleState?.branch) || state.branch;
1307
3921
  persist(state);
1308
- if (!workdir || !(0, import_node_fs.existsSync)(workdir)) {
3922
+ if (!workdir || !(0, import_node_fs3.existsSync)(workdir)) {
1309
3923
  return {
1310
3924
  blocker: {
1311
3925
  code: "implementation_worktree_missing",
@@ -1450,7 +4064,7 @@ async function routeCheckpoint(request, state, result, agent, input) {
1450
4064
  next: { ...baseContinuation(result), recon_assessment_json: jsonParam(assessment.payload) }
1451
4065
  };
1452
4066
  }
1453
- const continueStage = checkpointContinueStage(result);
4067
+ const continueStage = checkpointContinueStage2(result);
1454
4068
  const checkpointContinuesToAuthor = continueStage === "author";
1455
4069
  if (checkpoint === "author_supervisor_judgment" || checkpoint === "verify_capture_retry" || checkpoint === "verify_agent_retry" && checkpointContinuesToAuthor) {
1456
4070
  const packet = await agent.authorProofPacket(context);
@@ -1525,6 +4139,7 @@ function readRiddleProofRunStatus(state_path) {
1525
4139
  async function runRiddleProofEngineHarness(input) {
1526
4140
  const state = loadRunState(input);
1527
4141
  state.request = normalizeRunParams({ ...state.request, ...input.request });
4142
+ state.request.engine_state_path = nonEmptyString(input.resume_params?.state_path) || nonEmptyString(state.request.engine_state_path) || createEngineStatePath(state, input.config);
1528
4143
  const request = state.request;
1529
4144
  const agent = input.agent || createDisabledRiddleProofAgentAdapter();
1530
4145
  const maxIterations = Math.max(
@@ -1580,24 +4195,41 @@ async function runRiddleProofEngineHarness(input) {
1580
4195
  branch: state.branch || null
1581
4196
  }
1582
4197
  });
4198
+ const engineCallStartedAt = timestamp2();
4199
+ const engineCallStartedMs = Date.now();
1583
4200
  recordEvent(state, {
1584
4201
  kind: "engine.call",
1585
4202
  checkpoint: "engine_call",
1586
4203
  stage,
1587
4204
  summary: "Calling Riddle Proof engine.",
1588
- details: { params: nextParams }
4205
+ details: {
4206
+ params: redactedWorkflowParams(nextParams),
4207
+ started_at: engineCallStartedAt
4208
+ }
1589
4209
  });
1590
4210
  let result;
1591
4211
  try {
1592
4212
  result = await engine.execute(nextParams);
1593
4213
  } catch (error) {
1594
4214
  const message = error instanceof Error ? error.message : String(error);
4215
+ recordEvent(state, {
4216
+ kind: "engine.exception",
4217
+ checkpoint: "engine_call_failed",
4218
+ stage,
4219
+ summary: message,
4220
+ details: {
4221
+ duration_ms: Date.now() - engineCallStartedMs,
4222
+ started_at: engineCallStartedAt,
4223
+ finished_at: timestamp2()
4224
+ }
4225
+ });
1595
4226
  return blockerResult(state, lastResult, {
1596
4227
  code: "riddle_engine_exception",
1597
4228
  checkpoint: "engine_call_failed",
1598
4229
  message
1599
4230
  });
1600
4231
  }
4232
+ const engineCallDurationMs = Date.now() - engineCallStartedMs;
1601
4233
  lastResult = result;
1602
4234
  const engineState = engineStatePath(result, state);
1603
4235
  if (engineState) state.request.engine_state_path = engineState;
@@ -1622,7 +4254,10 @@ async function runRiddleProofEngineHarness(input) {
1622
4254
  details: {
1623
4255
  ok: result.ok ?? null,
1624
4256
  engine_state_path: engineState || null,
1625
- checkpoint: result.checkpoint || null
4257
+ checkpoint: result.checkpoint || null,
4258
+ duration_ms: engineCallDurationMs,
4259
+ started_at: engineCallStartedAt,
4260
+ finished_at: timestamp2()
1626
4261
  }
1627
4262
  });
1628
4263
  const routed = await routeCheckpoint(request, state, result, agent, input);
@@ -1675,7 +4310,7 @@ function truncateString(value, limit) {
1675
4310
  function sortedKeys(value) {
1676
4311
  return isRecord(value) ? Object.keys(value).sort() : [];
1677
4312
  }
1678
- function stringValue(value) {
4313
+ function stringValue2(value) {
1679
4314
  if (typeof value !== "string") return void 0;
1680
4315
  const trimmed = value.trim();
1681
4316
  return trimmed ? trimmed : void 0;
@@ -1691,12 +4326,12 @@ function artifactSummary(item, source) {
1691
4326
  const artifact = item;
1692
4327
  const metadata = isRecord(artifact.metadata) ? artifact.metadata : void 0;
1693
4328
  return {
1694
- name: stringValue(artifact.name) || "",
1695
- kind: stringValue(artifact.kind),
1696
- role: stringValue(artifact.role),
1697
- url: stringValue(artifact.url),
1698
- path: stringValue(artifact.path),
1699
- content_type: stringValue(artifact.content_type),
4329
+ name: stringValue2(artifact.name) || "",
4330
+ kind: stringValue2(artifact.kind),
4331
+ role: stringValue2(artifact.role),
4332
+ url: stringValue2(artifact.url),
4333
+ path: stringValue2(artifact.path),
4334
+ content_type: stringValue2(artifact.content_type),
1700
4335
  size_bytes: numberValue(artifact.size_bytes),
1701
4336
  metadata_keys: metadata ? Object.keys(metadata).sort() : void 0,
1702
4337
  source