@riddledc/riddle-proof 0.5.45 → 0.5.46

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.
Files changed (44) hide show
  1. package/README.md +17 -0
  2. package/dist/checkpoint.cjs +204 -1
  3. package/dist/checkpoint.d.cts +16 -1
  4. package/dist/checkpoint.d.ts +16 -1
  5. package/dist/checkpoint.js +4 -2
  6. package/dist/{chunk-W7VTDN4T.js → chunk-DUFDZJOF.js} +1 -0
  7. package/dist/{chunk-7S7O3NKF.js → chunk-JTNMEH57.js} +6 -1
  8. package/dist/{chunk-MRSYJMF4.js → chunk-L26NTZOU.js} +2 -2
  9. package/dist/chunk-NOBFZDZG.js +754 -0
  10. package/dist/chunk-PLSGW2GI.js +161 -0
  11. package/dist/{chunk-LXE5YUYY.js → chunk-R6SCWJCI.js} +204 -2
  12. package/dist/{chunk-CHRYLX6N.js → chunk-X3AQ2WUM.js} +128 -15
  13. package/dist/cli.cjs +6129 -0
  14. package/dist/cli.d.cts +1 -0
  15. package/dist/cli.d.ts +1 -0
  16. package/dist/cli.js +160 -0
  17. package/dist/codex-exec-agent.cjs +790 -0
  18. package/dist/codex-exec-agent.d.cts +91 -0
  19. package/dist/codex-exec-agent.d.ts +91 -0
  20. package/dist/codex-exec-agent.js +10 -0
  21. package/dist/engine-harness.cjs +740 -279
  22. package/dist/engine-harness.js +5 -4
  23. package/dist/index.cjs +1469 -247
  24. package/dist/index.d.cts +4 -2
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.js +33 -17
  27. package/dist/openclaw.js +4 -2
  28. package/dist/proof-run-engine.d.cts +3 -3
  29. package/dist/proof-run-engine.d.ts +3 -3
  30. package/dist/result.cjs +1 -0
  31. package/dist/result.js +1 -1
  32. package/dist/run-card.cjs +212 -0
  33. package/dist/run-card.d.cts +10 -0
  34. package/dist/run-card.d.ts +10 -0
  35. package/dist/run-card.js +10 -0
  36. package/dist/runner.cjs +2 -0
  37. package/dist/runner.js +5 -3
  38. package/dist/state.cjs +174 -5
  39. package/dist/state.d.cts +2 -1
  40. package/dist/state.d.ts +2 -1
  41. package/dist/state.js +4 -2
  42. package/dist/types.d.cts +63 -2
  43. package/dist/types.d.ts +63 -2
  44. package/package.json +15 -2
@@ -2971,201 +2971,18 @@ function createRunResult(input) {
2971
2971
  checkpoint_summary: state.checkpoint_summary,
2972
2972
  state_paths: state.state_paths,
2973
2973
  proof_contract: state.proof_contract,
2974
+ run_card: state.run_card,
2974
2975
  proof_session: state.proof_session,
2975
2976
  evidence_bundle: input.evidence_bundle,
2976
2977
  raw: input.raw
2977
2978
  });
2978
2979
  }
2979
2980
 
2980
- // src/state.ts
2981
- var RIDDLE_PROOF_RUN_STATE_VERSION = "riddle-proof.run-state.v1";
2982
- function timestamp() {
2983
- return (/* @__PURE__ */ new Date()).toISOString();
2984
- }
2985
- function createRunId(createdAt) {
2986
- const stamp = createdAt.replace(/\D/g, "").slice(0, 14) || "unknown";
2987
- const entropy = Math.random().toString(36).slice(2, 8) || "run";
2988
- return `rp_${stamp}_${entropy}`;
2989
- }
2990
- function elapsedMs(start, end) {
2991
- const startMs = start ? Date.parse(start) : NaN;
2992
- const endMs = end ? Date.parse(end) : NaN;
2993
- if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return void 0;
2994
- return Math.max(0, endMs - startMs);
2995
- }
2996
- function normalizeIntegrationContext(input, fallbackSource) {
2997
- const value = recordValue(input);
2998
- if (!value) {
2999
- return fallbackSource ? { source: fallbackSource } : void 0;
3000
- }
3001
- const metadata = recordValue(value.metadata);
3002
- return compactRecord({
3003
- source: nonEmptyString(value.source) || fallbackSource,
3004
- channel_id: nonEmptyString(value.channel_id),
3005
- thread_id: nonEmptyString(value.thread_id),
3006
- message_id: nonEmptyString(value.message_id),
3007
- source_url: nonEmptyString(value.source_url),
3008
- metadata: metadata && Object.keys(metadata).length ? metadata : void 0
3009
- });
3010
- }
3011
- function normalizeRunParams(input) {
3012
- return compactRecord({
3013
- repo: input.repo,
3014
- branch: input.branch,
3015
- change_request: input.change_request,
3016
- commit_message: input.commit_message,
3017
- prod_url: input.prod_url,
3018
- capture_script: input.capture_script,
3019
- success_criteria: input.success_criteria,
3020
- assertions: input.assertions,
3021
- verification_mode: input.verification_mode,
3022
- resume_session: input.resume_session,
3023
- target_image_url: input.target_image_url,
3024
- target_image_hash: input.target_image_hash,
3025
- viewport_matrix: input.viewport_matrix,
3026
- deterministic_setup: input.deterministic_setup,
3027
- reference: input.reference,
3028
- base_branch: input.base_branch,
3029
- before_ref: input.before_ref,
3030
- allow_static_preview_fallback: input.allow_static_preview_fallback,
3031
- context: input.context,
3032
- reviewer: input.reviewer,
3033
- mode: input.mode,
3034
- build_command: input.build_command,
3035
- build_output: input.build_output,
3036
- server_image: input.server_image,
3037
- server_command: input.server_command,
3038
- server_port: input.server_port,
3039
- server_path: input.server_path,
3040
- use_auth: input.use_auth,
3041
- auth_localStorage_json: input.auth_localStorage_json,
3042
- auth_cookies_json: input.auth_cookies_json,
3043
- auth_headers_json: input.auth_headers_json,
3044
- color_scheme: input.color_scheme,
3045
- wait_for_selector: input.wait_for_selector,
3046
- ship_mode: input.ship_mode,
3047
- leave_draft: input.leave_draft,
3048
- engine_state_path: input.engine_state_path,
3049
- harness_state_path: input.harness_state_path,
3050
- max_iterations: input.max_iterations,
3051
- auto_approve: input.auto_approve,
3052
- dry_run: input.dry_run,
3053
- integration_context: normalizeIntegrationContext(input.integration_context)
3054
- });
3055
- }
3056
- function createRunState(input) {
3057
- const createdAt = input.created_at || timestamp();
3058
- return compactRecord({
3059
- version: RIDDLE_PROOF_RUN_STATE_VERSION,
3060
- run_id: input.run_id || createRunId(createdAt),
3061
- state_path: input.state_path,
3062
- worktree_path: input.worktree_path,
3063
- branch: input.branch || input.request.branch,
3064
- current_stage: input.current_stage ?? null,
3065
- stage_started_at: input.stage_started_at ?? null,
3066
- status: input.status || "running",
3067
- created_at: createdAt,
3068
- updated_at: input.updated_at || createdAt,
3069
- request: normalizeRunParams(input.request),
3070
- iterations: input.iterations ?? 0,
3071
- last_checkpoint: input.last_checkpoint ?? null,
3072
- checkpoint_packet: input.checkpoint_packet,
3073
- checkpoint_summary: input.checkpoint_summary,
3074
- state_paths: input.state_paths,
3075
- proof_contract: input.proof_contract,
3076
- checkpoint_history: input.checkpoint_history,
3077
- events: input.events ? [...input.events] : []
3078
- });
3079
- }
3080
- function appendRunEvent(state, input) {
3081
- const event = {
3082
- ts: input.ts || timestamp(),
3083
- kind: input.kind,
3084
- checkpoint: input.checkpoint,
3085
- stage: input.stage,
3086
- summary: input.summary,
3087
- details: input.details
3088
- };
3089
- state.events.push(compactRecord({
3090
- ts: event.ts,
3091
- kind: event.kind,
3092
- checkpoint: event.checkpoint,
3093
- stage: event.stage,
3094
- summary: event.summary,
3095
- details: event.details
3096
- }));
3097
- if (input.checkpoint !== void 0) state.last_checkpoint = input.checkpoint;
3098
- if (input.stage !== void 0) {
3099
- if (state.current_stage !== input.stage) state.stage_started_at = event.ts;
3100
- state.current_stage = input.stage;
3101
- }
3102
- state.updated_at = event.ts;
3103
- return state;
3104
- }
3105
- function appendStageHeartbeat(state, input) {
3106
- const at = input.ts || timestamp();
3107
- return appendRunEvent(state, {
3108
- ts: at,
3109
- kind: "stage.heartbeat",
3110
- checkpoint: input.checkpoint || `${input.stage}_heartbeat`,
3111
- stage: input.stage,
3112
- summary: input.summary || `${input.stage} stage is active.`,
3113
- details: compactRecord({
3114
- elapsed_ms: elapsedMs(state.created_at, at),
3115
- stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
3116
- wait_reason: input.wait_reason,
3117
- blocker: input.blocker,
3118
- ...input.details
3119
- })
3120
- });
3121
- }
3122
- function createRunStatusSnapshot(state, at = timestamp()) {
3123
- const latestEvent = state.events[state.events.length - 1];
3124
- const runId = state.run_id || "unknown";
3125
- return compactRecord({
3126
- run_id: runId,
3127
- status: state.status,
3128
- is_terminal: isTerminalStatus(state.status),
3129
- monitor_should_continue: !isTerminalStatus(state.status),
3130
- current_stage: state.current_stage ?? null,
3131
- state_path: state.state_path ?? null,
3132
- worktree_path: state.worktree_path ?? null,
3133
- branch: state.branch ?? null,
3134
- pr_url: state.pr_url ?? null,
3135
- pr_branch: state.pr_branch ?? null,
3136
- pr_state: state.pr_state,
3137
- ci_status: state.ci_status,
3138
- ship_commit: state.ship_commit,
3139
- ship_remote_head: state.ship_remote_head,
3140
- merge_commit: state.merge_commit,
3141
- merged_at: state.merged_at,
3142
- proof_comment_url: state.proof_comment_url,
3143
- cleanup_report: state.cleanup_report,
3144
- iterations: state.iterations,
3145
- last_checkpoint: state.last_checkpoint ?? null,
3146
- updated_at: state.updated_at,
3147
- elapsed_ms: elapsedMs(state.created_at, at),
3148
- stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
3149
- blocker: state.blocker,
3150
- checkpoint_packet: state.checkpoint_packet,
3151
- checkpoint_summary: state.checkpoint_summary,
3152
- state_paths: state.state_paths,
3153
- proof_contract: state.proof_contract,
3154
- latest_event: latestEvent
3155
- });
3156
- }
3157
- function setRunStatus(state, status, at = timestamp()) {
3158
- state.status = status;
3159
- state.ok = status !== "blocked" && status !== "failed";
3160
- state.updated_at = at;
3161
- return state;
3162
- }
3163
-
3164
2981
  // src/checkpoint.ts
3165
2982
  var import_node_crypto = __toESM(require("crypto"), 1);
3166
2983
  var RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION = "riddle-proof.checkpoint.v1";
3167
2984
  var RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION = "riddle-proof.checkpoint_response.v1";
3168
- function timestamp2() {
2985
+ function timestamp() {
3169
2986
  return (/* @__PURE__ */ new Date()).toISOString();
3170
2987
  }
3171
2988
  function jsonCloneRecord(value) {
@@ -3279,6 +3096,102 @@ function responseSchemaForProofAssessmentPacket() {
3279
3096
  }
3280
3097
  };
3281
3098
  }
3099
+ function responseSchemaForReconPacket() {
3100
+ return {
3101
+ type: "object",
3102
+ required: ["version", "run_id", "checkpoint", "decision", "summary", "created_at"],
3103
+ additionalProperties: false,
3104
+ properties: {
3105
+ version: { const: RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION },
3106
+ run_id: { type: "string" },
3107
+ checkpoint: { type: "string" },
3108
+ resume_token: { type: "string" },
3109
+ decision: {
3110
+ type: "string",
3111
+ enum: ["ready_for_author", "retry_recon", "recon_stuck", "needs_recon", "blocked", "human_review"]
3112
+ },
3113
+ summary: { type: "string" },
3114
+ payload: {
3115
+ type: "object",
3116
+ description: "Optional recon assessment details such as baseline_understanding, refined_inputs, reasons, or diagnostic blocker context."
3117
+ },
3118
+ reasons: { type: "array", items: { type: "string" } },
3119
+ continue_with_stage: { type: "string", enum: ["recon", "author"] },
3120
+ source: {
3121
+ type: "object",
3122
+ properties: {
3123
+ kind: { type: "string" },
3124
+ session_id: { type: "string" },
3125
+ user_id: { type: "string" }
3126
+ }
3127
+ },
3128
+ created_at: { type: "string" }
3129
+ }
3130
+ };
3131
+ }
3132
+ function responseSchemaForImplementationPacket() {
3133
+ return {
3134
+ type: "object",
3135
+ required: ["version", "run_id", "checkpoint", "decision", "summary", "created_at"],
3136
+ additionalProperties: false,
3137
+ properties: {
3138
+ version: { const: RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION },
3139
+ run_id: { type: "string" },
3140
+ checkpoint: { type: "string" },
3141
+ resume_token: { type: "string" },
3142
+ decision: {
3143
+ type: "string",
3144
+ enum: ["implementation_complete", "needs_author", "needs_recon", "blocked", "human_review"]
3145
+ },
3146
+ summary: { type: "string" },
3147
+ payload: {
3148
+ type: "object",
3149
+ description: "Implementation details such as changed_files, tests_run, and implementation_notes. The changed worktree must contain a real git diff before verify can advance."
3150
+ },
3151
+ reasons: { type: "array", items: { type: "string" } },
3152
+ continue_with_stage: { type: "string", enum: ["implement", "verify", "author", "recon"] },
3153
+ source: {
3154
+ type: "object",
3155
+ properties: {
3156
+ kind: { type: "string" },
3157
+ session_id: { type: "string" },
3158
+ user_id: { type: "string" }
3159
+ }
3160
+ },
3161
+ created_at: { type: "string" }
3162
+ }
3163
+ };
3164
+ }
3165
+ function responseSchemaForAdvancePacket(stage) {
3166
+ return {
3167
+ type: "object",
3168
+ required: ["version", "run_id", "checkpoint", "decision", "summary", "created_at"],
3169
+ additionalProperties: false,
3170
+ properties: {
3171
+ version: { const: RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION },
3172
+ run_id: { type: "string" },
3173
+ checkpoint: { type: "string" },
3174
+ resume_token: { type: "string" },
3175
+ decision: {
3176
+ type: "string",
3177
+ enum: ["continue_stage", "retry_stage", "needs_recon", "needs_implementation", "blocked", "human_review"]
3178
+ },
3179
+ summary: { type: "string" },
3180
+ payload: { type: "object" },
3181
+ reasons: { type: "array", items: { type: "string" } },
3182
+ continue_with_stage: { type: "string", enum: ["recon", "author", "implement", "verify", "ship", stage] },
3183
+ source: {
3184
+ type: "object",
3185
+ properties: {
3186
+ kind: { type: "string" },
3187
+ session_id: { type: "string" },
3188
+ user_id: { type: "string" }
3189
+ }
3190
+ },
3191
+ created_at: { type: "string" }
3192
+ }
3193
+ };
3194
+ }
3282
3195
  function resumeTokenFor(input) {
3283
3196
  const hash = import_node_crypto.default.createHash("sha256").update(JSON.stringify(input)).digest("hex").slice(0, 24);
3284
3197
  return `rpchk_${hash}`;
@@ -3306,6 +3219,106 @@ function artifactsFromState(state) {
3306
3219
  }
3307
3220
  return artifacts.slice(0, 16);
3308
3221
  }
3222
+ function stageFromCheckpoint(checkpoint) {
3223
+ if (checkpoint.startsWith("recon_")) return "recon";
3224
+ if (checkpoint.startsWith("author_")) return "author";
3225
+ if (checkpoint.startsWith("implement_")) return "implement";
3226
+ if (checkpoint.startsWith("verify_")) return "verify";
3227
+ if (checkpoint.startsWith("ship_")) return "ship";
3228
+ if (checkpoint.startsWith("pr_sync_")) return "notify";
3229
+ if (checkpoint.includes("capture")) return "prove";
3230
+ return "setup";
3231
+ }
3232
+ function allowedDecisionsForStage(stage, checkpoint) {
3233
+ if (stage === "recon") return ["ready_for_author", "retry_recon", "recon_stuck", "blocked", "human_review"];
3234
+ if (stage === "implement") return ["implementation_complete", "needs_author", "needs_recon", "blocked", "human_review"];
3235
+ if (stage === "ship") return ["continue_stage", "needs_implementation", "needs_recon", "blocked", "human_review"];
3236
+ if (checkpoint === "awaiting_stage_advance") return ["continue_stage", "retry_stage", "blocked", "human_review"];
3237
+ return ["continue_stage", "needs_recon", "needs_implementation", "blocked", "human_review"];
3238
+ }
3239
+ function packetKindForStage(stage, checkpoint) {
3240
+ if (stage === "recon") return "assess_recon";
3241
+ if (stage === "implement") return "implement_change";
3242
+ if (checkpoint.includes("human")) return "human_review";
3243
+ return "advance_decision";
3244
+ }
3245
+ function responseSchemaForStage(stage, checkpoint) {
3246
+ if (stage === "recon") return responseSchemaForReconPacket();
3247
+ if (stage === "implement") return responseSchemaForImplementationPacket();
3248
+ return responseSchemaForAdvancePacket(stage);
3249
+ }
3250
+ function questionForStage(stage, checkpoint) {
3251
+ if (stage === "recon") {
3252
+ return "Assess the baseline/recon evidence. Return ready_for_author only when the baseline is trustworthy; otherwise choose retry_recon, recon_stuck, blocked, or human_review.";
3253
+ }
3254
+ if (stage === "implement") {
3255
+ return "Implement the requested change in the after worktree, leave a real git diff, then return implementation_complete with changed_files/tests_run/implementation_notes. Choose blocked or human_review if implementation cannot honestly advance.";
3256
+ }
3257
+ if (stage === "ship") {
3258
+ return "Assess whether the ship gate can continue. Return continue_stage only if proof, PR, and policy gates are satisfied; otherwise route to the appropriate earlier stage or block with a concrete reason.";
3259
+ }
3260
+ return "Choose the next Riddle Proof stage for this durable run, or block with a concrete reason if the run cannot honestly advance.";
3261
+ }
3262
+ function buildStageCheckpointPacket(input) {
3263
+ const checkpoint = nonEmptyString(input.engineResult.checkpoint) || "stage_checkpoint";
3264
+ const stage = nonEmptyString(input.engineResult.stage) || stageFromCheckpoint(checkpoint);
3265
+ const runId = input.runState.run_id || "unknown";
3266
+ const fullState = input.fullRiddleState || {};
3267
+ const decisionDetails = recordValue(input.engineResult.decisionRequest?.details);
3268
+ const checkpointContract = recordValue(input.engineResult.checkpointContract);
3269
+ const summary = nonEmptyString(input.engineResult.summary) || nonEmptyString(fullState.stage_summary) || `${stage} checkpoint needs a supervising decision.`;
3270
+ const kind = packetKindForStage(stage, checkpoint);
3271
+ return {
3272
+ version: RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
3273
+ run_id: runId,
3274
+ state_path: input.runState.state_path,
3275
+ stage,
3276
+ checkpoint,
3277
+ kind,
3278
+ summary,
3279
+ question: questionForStage(stage, checkpoint),
3280
+ change_request: input.request.change_request || nonEmptyString(fullState.change_request) || "",
3281
+ context: input.request.context,
3282
+ artifacts: artifactsFromState(fullState),
3283
+ state_excerpt: compactRecord({
3284
+ repo: input.request.repo || fullState.repo,
3285
+ branch: input.request.branch || fullState.branch,
3286
+ after_worktree: fullState.after_worktree || input.runState.worktree_path,
3287
+ verification_mode: input.request.verification_mode || fullState.verification_mode,
3288
+ reference: input.request.reference || fullState.reference,
3289
+ server_path: fullState.server_path,
3290
+ wait_for_selector: fullState.wait_for_selector,
3291
+ recon_status: fullState.recon_status,
3292
+ author_status: fullState.author_status,
3293
+ implementation_status: fullState.implementation_status,
3294
+ verify_status: fullState.verify_status,
3295
+ stage_decision_request: jsonCloneRecord(fullState.stage_decision_request)
3296
+ }),
3297
+ evidence_excerpt: compactRecord({
3298
+ before_cdn: fullState.before_cdn || null,
3299
+ prod_cdn: fullState.prod_cdn || null,
3300
+ after_cdn: fullState.after_cdn || null,
3301
+ recon_results: jsonCloneRecord(fullState.recon_results),
3302
+ checkpoint_contract: jsonCloneRecord(checkpointContract),
3303
+ decision_details: jsonCloneRecord(decisionDetails)
3304
+ }),
3305
+ allowed_decisions: allowedDecisionsForStage(stage, checkpoint),
3306
+ response_schema: responseSchemaForStage(stage, checkpoint),
3307
+ routing_hint: {
3308
+ suggested_role: stage === "implement" ? "builder_agent" : checkpoint.includes("human") ? "human" : "main_agent",
3309
+ visibility: input.visibility || "quiet",
3310
+ urgency: stage === "ship" ? "high" : "normal",
3311
+ can_auto_answer: input.visibility !== "manual"
3312
+ },
3313
+ resume_token: resumeTokenFor({
3314
+ runId,
3315
+ statePath: input.engineResult.state_path || input.request.engine_state_path || null,
3316
+ checkpoint,
3317
+ stage
3318
+ }),
3319
+ created_at: input.created_at || timestamp()
3320
+ };
3321
+ }
3309
3322
  function buildAuthorCheckpointPacket(input) {
3310
3323
  const checkpoint = nonEmptyString(input.engineResult.checkpoint) || "author_supervisor_judgment";
3311
3324
  const stage = "author";
@@ -3359,7 +3372,7 @@ function buildAuthorCheckpointPacket(input) {
3359
3372
  checkpoint,
3360
3373
  stage
3361
3374
  }),
3362
- created_at: input.created_at || timestamp2()
3375
+ created_at: input.created_at || timestamp()
3363
3376
  };
3364
3377
  }
3365
3378
  function visualDeltaFromState(fullState) {
@@ -3408,16 +3421,16 @@ function buildProofAssessmentCheckpointPacket(input) {
3408
3421
  const visualDelta = visualDeltaFromState(fullState);
3409
3422
  const verificationMode = nonEmptyString(input.request.verification_mode) || nonEmptyString(fullState.verification_mode) || nonEmptyString(bundle?.verification_mode) || "proof";
3410
3423
  const visualDeltaRequired = requiredSignals?.visual_delta === true || verificationModeRequiresVisualDelta(verificationMode);
3411
- const evidenceIssueCode = visualDeltaIssueCode(visualDelta, visualDeltaRequired);
3424
+ const evidenceIssueCode2 = visualDeltaIssueCode(visualDelta, visualDeltaRequired);
3412
3425
  const summary = nonEmptyString(input.engineResult.summary) || nonEmptyString(fullState.verify_summary) || "Verify captured evidence and needs a supervising proof assessment.";
3413
- const recoveryHint = evidenceIssueCode ? "Required visual_delta evidence is incomplete. Keep this same run in verify/evidence recovery with decision=revise_capture and continue_with_stage=verify unless the evidence proves an implementation or recon problem." : "Assess whether the current artifacts prove the requested change, then choose the next stage.";
3426
+ const recoveryHint = evidenceIssueCode2 ? "Required visual_delta evidence is incomplete. Keep this same run in verify/evidence recovery with decision=revise_capture and continue_with_stage=verify unless the evidence proves an implementation or recon problem." : "Assess whether the current artifacts prove the requested change, then choose the next stage.";
3414
3427
  return {
3415
3428
  version: RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
3416
3429
  run_id: runId,
3417
3430
  state_path: input.runState.state_path,
3418
3431
  stage,
3419
3432
  checkpoint,
3420
- kind: evidenceIssueCode ? "recover_evidence" : "assess_proof",
3433
+ kind: evidenceIssueCode2 ? "recover_evidence" : "assess_proof",
3421
3434
  summary,
3422
3435
  question: `Assess the current Riddle Proof evidence. ${recoveryHint} Return a CheckpointResponse using one allowed decision.`,
3423
3436
  change_request: input.request.change_request || nonEmptyString(fullState.change_request) || "",
@@ -3442,7 +3455,7 @@ function buildProofAssessmentCheckpointPacket(input) {
3442
3455
  visual_delta_required: visualDeltaRequired,
3443
3456
  visual_delta_ready: visualDelta?.status === "measured" && visualDelta?.passed === true,
3444
3457
  visual_delta: jsonCloneRecord(visualDelta),
3445
- evidence_issue_code: evidenceIssueCode,
3458
+ evidence_issue_code: evidenceIssueCode2,
3446
3459
  proof_assessment_request: jsonCloneRecord(proofAssessmentRequest),
3447
3460
  verify_decision_request: jsonCloneRecord(fullState.verify_decision_request),
3448
3461
  checkpoint_contract: jsonCloneRecord(input.engineResult.checkpointContract)
@@ -3459,9 +3472,9 @@ function buildProofAssessmentCheckpointPacket(input) {
3459
3472
  ],
3460
3473
  response_schema: responseSchemaForProofAssessmentPacket(),
3461
3474
  routing_hint: {
3462
- suggested_role: evidenceIssueCode ? "proof_judge" : "proof_judge",
3475
+ suggested_role: evidenceIssueCode2 ? "proof_judge" : "proof_judge",
3463
3476
  visibility: input.visibility || "quiet",
3464
- urgency: evidenceIssueCode ? "high" : "normal",
3477
+ urgency: evidenceIssueCode2 ? "high" : "normal",
3465
3478
  can_auto_answer: input.visibility !== "manual"
3466
3479
  },
3467
3480
  resume_token: resumeTokenFor({
@@ -3470,7 +3483,7 @@ function buildProofAssessmentCheckpointPacket(input) {
3470
3483
  checkpoint,
3471
3484
  stage
3472
3485
  }),
3473
- created_at: input.created_at || timestamp2()
3486
+ created_at: input.created_at || timestamp()
3474
3487
  };
3475
3488
  }
3476
3489
  function buildCheckpointPacketForEngineResult(input) {
@@ -3478,7 +3491,12 @@ function buildCheckpointPacketForEngineResult(input) {
3478
3491
  if (checkpoint === "verify_supervisor_judgment" || checkpoint === "verify_supervisor_judgment_required" || checkpoint === "verify_human_escalation") {
3479
3492
  return buildProofAssessmentCheckpointPacket(input);
3480
3493
  }
3481
- return buildAuthorCheckpointPacket(input);
3494
+ const resume = recordValue(input.engineResult.checkpointContract?.resume);
3495
+ const continueStage = nonEmptyString(resume?.continue_with_stage);
3496
+ if (checkpoint === "author_supervisor_judgment" || checkpoint === "verify_capture_retry" || checkpoint === "verify_agent_retry" && continueStage === "author") {
3497
+ return buildAuthorCheckpointPacket(input);
3498
+ }
3499
+ return buildStageCheckpointPacket(input);
3482
3500
  }
3483
3501
  function normalizeCheckpointResponse(value) {
3484
3502
  const record = recordValue(value);
@@ -3502,98 +3520,431 @@ function normalizeCheckpointResponse(value) {
3502
3520
  reasons: Array.isArray(record.reasons) ? record.reasons.filter((item) => typeof item === "string") : void 0,
3503
3521
  continue_with_stage: nonEmptyString(record.continue_with_stage),
3504
3522
  source: jsonCloneRecord(record.source),
3505
- created_at: nonEmptyString(record.created_at) || timestamp2()
3523
+ created_at: nonEmptyString(record.created_at) || timestamp()
3524
+ });
3525
+ }
3526
+ function checkpointSummaryFromState(state, engineStatePath2) {
3527
+ const history = state.checkpoint_history || [];
3528
+ const packets = history.filter((entry) => entry.packet);
3529
+ const responses = history.filter((entry) => entry.response);
3530
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3531
+ const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3532
+ const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3533
+ const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
3534
+ const latestResponse = latestResponseEntry?.response;
3535
+ const latestResumeToken = latestPacket?.resume_token || null;
3536
+ const latestResponseToken = latestResponse?.resume_token || null;
3537
+ const tokenMatches = latestResumeToken && latestResponseToken ? latestResumeToken === latestResponseToken : latestResumeToken || latestResponseToken ? false : null;
3538
+ return compactRecord({
3539
+ pending: Boolean(state.checkpoint_packet),
3540
+ packet_count: packets.length,
3541
+ response_count: responses.length,
3542
+ duplicate_response_count: duplicateResponses.length,
3543
+ latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3544
+ latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3545
+ latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
3546
+ latest_decision: latestResponse?.decision || null,
3547
+ latest_packet_summary: latestPacket?.summary || null,
3548
+ latest_response_summary: latestResponse?.summary || null,
3549
+ latest_resume_token: latestResumeToken,
3550
+ latest_response_token: latestResponseToken,
3551
+ token_matches: tokenMatches,
3552
+ last_packet_at: latestPacketEntry?.ts || null,
3553
+ last_response_at: latestResponseEntry?.ts || null,
3554
+ state_paths: statePathsForRunState(state, engineStatePath2)
3555
+ });
3556
+ }
3557
+ function isDuplicateCheckpointResponse(state, response) {
3558
+ const identity = checkpointResponseIdentity(response);
3559
+ return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
3560
+ }
3561
+ function checkpointResponseIdentity(response) {
3562
+ const logicalResponse = compactRecord({
3563
+ run_id: response.run_id,
3564
+ checkpoint: response.checkpoint,
3565
+ resume_token: response.resume_token,
3566
+ decision: response.decision,
3567
+ summary: response.summary,
3568
+ payload: response.payload,
3569
+ reasons: response.reasons,
3570
+ continue_with_stage: response.continue_with_stage,
3571
+ source: response.source
3572
+ });
3573
+ return import_node_crypto.default.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
3574
+ }
3575
+ function authorPacketPayloadFromCheckpointResponse(response) {
3576
+ if (response.decision !== "author_packet") return null;
3577
+ const payload = recordValue(response.payload);
3578
+ if (!payload) return null;
3579
+ const nested = recordValue(payload.author_packet);
3580
+ const candidate = nested || payload;
3581
+ if (!nonEmptyString(candidate.proof_plan) || !nonEmptyString(candidate.capture_script)) return null;
3582
+ return candidate;
3583
+ }
3584
+ function proofContractFromAuthorCheckpointResponse(response, packet, payload) {
3585
+ const refinedInputs = recordValue(payload.refined_inputs) || {};
3586
+ return compactRecord({
3587
+ version: "riddle-proof.proof-contract.v1",
3588
+ checkpoint: packet.checkpoint,
3589
+ source_response: compactRecord({
3590
+ run_id: response.run_id,
3591
+ checkpoint: response.checkpoint,
3592
+ resume_token: response.resume_token,
3593
+ decision: response.decision,
3594
+ summary: response.summary,
3595
+ created_at: response.created_at
3596
+ }),
3597
+ proof_plan: nonEmptyString(payload.proof_plan),
3598
+ capture_script: nonEmptyString(payload.capture_script),
3599
+ artifact_contract: jsonCloneRecord(payload.artifact_contract),
3600
+ assertions: jsonCloneValue(payload.assertions),
3601
+ baseline_understanding: jsonCloneRecord(payload.baseline_understanding) || jsonCloneRecord(payload.recon_baseline_understanding) || jsonCloneRecord(packet.state_excerpt?.recon_baseline_understanding),
3602
+ route_assumptions: compactRecord({
3603
+ server_path: nonEmptyString(refinedInputs.server_path) || nonEmptyString(payload.server_path) || nonEmptyString(packet.state_excerpt?.server_path),
3604
+ wait_for_selector: nonEmptyString(refinedInputs.wait_for_selector) || nonEmptyString(payload.wait_for_selector) || nonEmptyString(packet.state_excerpt?.wait_for_selector),
3605
+ reference: nonEmptyString(refinedInputs.reference) || nonEmptyString(payload.reference),
3606
+ expected_path: nonEmptyString(payload.expected_path) || nonEmptyString(refinedInputs.expected_path)
3607
+ }),
3608
+ stop_condition: nonEmptyString(payload.stop_condition),
3609
+ rationale: jsonCloneValue(payload.rationale),
3610
+ verdict_dimensions: jsonCloneRecord(payload.verdict_dimensions),
3611
+ payload: jsonCloneRecord(payload),
3612
+ created_at: timestamp()
3613
+ });
3614
+ }
3615
+
3616
+ // src/run-card.ts
3617
+ var RIDDLE_PROOF_RUN_CARD_VERSION = "riddle-proof.run-card.v1";
3618
+ function elapsedMs(start, end) {
3619
+ const startMs = start ? Date.parse(start) : NaN;
3620
+ const endMs = end ? Date.parse(end) : NaN;
3621
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return void 0;
3622
+ return Math.max(0, endMs - startMs);
3623
+ }
3624
+ function jsonCloneRecord2(value) {
3625
+ const record = recordValue(value);
3626
+ if (!record) return void 0;
3627
+ try {
3628
+ return JSON.parse(JSON.stringify(record));
3629
+ } catch {
3630
+ return { ...record };
3631
+ }
3632
+ }
3633
+ function compactText2(value, limit = 600) {
3634
+ const text = nonEmptyString(value);
3635
+ if (!text) return void 0;
3636
+ return text.length <= limit ? text : `${text.slice(0, limit - 20).trimEnd()}...`;
3637
+ }
3638
+ function visualDeltaFrom(input) {
3639
+ const fullState = input.fullRiddleState || {};
3640
+ const bundle = recordValue(fullState.evidence_bundle);
3641
+ const after = recordValue(bundle?.after);
3642
+ const afterDelta = recordValue(after?.visual_delta);
3643
+ if (afterDelta && Object.keys(afterDelta).length) return afterDelta;
3644
+ const requestDelta = recordValue(recordValue(fullState.proof_assessment_request)?.visual_delta);
3645
+ if (requestDelta && Object.keys(requestDelta).length) return requestDelta;
3646
+ const packetDelta = recordValue(input.runState.checkpoint_packet?.evidence_excerpt?.visual_delta);
3647
+ return packetDelta && Object.keys(packetDelta).length ? packetDelta : void 0;
3648
+ }
3649
+ function artifactsFrom(input) {
3650
+ const packetArtifacts = input.runState.checkpoint_packet?.artifacts;
3651
+ if (packetArtifacts?.length) return packetArtifacts.slice(0, 12);
3652
+ const fullState = input.fullRiddleState || {};
3653
+ const artifacts = [];
3654
+ for (const role of ["before", "prod", "after"]) {
3655
+ const url = nonEmptyString(fullState[`${role}_cdn`]) || nonEmptyString(input.runState[`${role}_artifact_url`]);
3656
+ if (url) artifacts.push({ role, url, name: `${role}.png`, mime_type: "image/png" });
3657
+ }
3658
+ return artifacts.length ? artifacts : void 0;
3659
+ }
3660
+ function ownerFor(state) {
3661
+ if (state.status === "awaiting_checkpoint") {
3662
+ const role = nonEmptyString(state.checkpoint_packet?.routing_hint?.suggested_role);
3663
+ return role || "supervising_agent";
3664
+ }
3665
+ if (state.status === "running") return "engine";
3666
+ if (state.status === "blocked" || state.status === "failed") return "human_or_operator";
3667
+ return "none";
3668
+ }
3669
+ function actionFor(state) {
3670
+ if (state.status === "awaiting_checkpoint") return state.checkpoint_packet?.question || "Answer the pending checkpoint.";
3671
+ if (state.status === "running") return "Continue the current Riddle Proof stage.";
3672
+ if (state.status === "blocked" || state.status === "failed") return state.blocker?.message || "Inspect the blocker and decide whether a new run or infrastructure repair is needed.";
3673
+ if (state.status === "ready_to_ship") return "Ship is held by policy; review PR/ship policy before advancing.";
3674
+ return "No next action; run is terminal.";
3675
+ }
3676
+ function evidenceIssueCode(input) {
3677
+ const packetIssue = nonEmptyString(input.runState.checkpoint_packet?.evidence_excerpt?.evidence_issue_code);
3678
+ if (packetIssue) return packetIssue;
3679
+ const assessmentIssue = nonEmptyString(recordValue(input.fullRiddleState?.proof_assessment)?.evidence_issue_code);
3680
+ if (assessmentIssue) return assessmentIssue;
3681
+ const delta = visualDeltaFrom(input);
3682
+ const status = nonEmptyString(delta?.status);
3683
+ if (status === "unmeasured") {
3684
+ const reason = `${nonEmptyString(delta?.reason) || ""}
3685
+ ${input.runState.blocker?.message || ""}`.toLowerCase();
3686
+ return reason.includes("fetch") || reason.includes("allowlist") || reason.includes("registered domain") || reason.includes("high risk") || reason.includes("comparator") ? "comparator_fetch_blocked" : "visual_delta_unmeasured";
3687
+ }
3688
+ if (status === "measured" && delta?.passed === false) return "semantic_proof_failed";
3689
+ return void 0;
3690
+ }
3691
+ function createRiddleProofRunCard(state, input = {}) {
3692
+ const at = input.at || (/* @__PURE__ */ new Date()).toISOString();
3693
+ const fullState = input.fullRiddleState || {};
3694
+ const packet = state.checkpoint_packet;
3695
+ const latestEvent = state.events[state.events.length - 1];
3696
+ const bundle = recordValue(fullState.evidence_bundle);
3697
+ const artifactContract = jsonCloneRecord2(packet?.artifact_contract) || jsonCloneRecord2(recordValue(fullState.proof_assessment_request)?.artifact_contract) || jsonCloneRecord2(recordValue(bundle?.artifact_contract)) || jsonCloneRecord2(state.proof_contract?.artifact_contract);
3698
+ const required = jsonCloneRecord2(recordValue(artifactContract)?.required);
3699
+ const statePaths = input.state_paths || state.state_paths || statePathsForRunState(state);
3700
+ const visualDelta = visualDeltaFrom({ fullRiddleState: fullState, runState: state });
3701
+ const artifacts = artifactsFrom({ fullRiddleState: fullState, runState: state });
3702
+ return {
3703
+ version: RIDDLE_PROOF_RUN_CARD_VERSION,
3704
+ run_id: state.run_id || "unknown",
3705
+ status: state.status,
3706
+ goal: compactRecord({
3707
+ repo: state.request.repo || nonEmptyString(fullState.repo),
3708
+ branch: state.request.branch || nonEmptyString(fullState.branch),
3709
+ change_request: state.request.change_request || nonEmptyString(fullState.change_request),
3710
+ verification_mode: state.request.verification_mode || nonEmptyString(fullState.verification_mode),
3711
+ success_criteria: state.request.success_criteria
3712
+ }),
3713
+ durable_state: compactRecord({
3714
+ ...statePaths,
3715
+ worktree_path: state.worktree_path || nonEmptyString(fullState.after_worktree) || null,
3716
+ branch: state.branch || nonEmptyString(fullState.branch) || null
3717
+ }),
3718
+ current_phase: compactRecord({
3719
+ stage: state.current_stage ?? null,
3720
+ checkpoint: state.last_checkpoint ?? packet?.checkpoint ?? null,
3721
+ latest_event: latestEvent?.kind ?? null,
3722
+ elapsed_ms: elapsedMs(state.created_at, at),
3723
+ stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
3724
+ iterations: state.iterations
3725
+ }),
3726
+ owner_next_action: compactRecord({
3727
+ owner: ownerFor(state),
3728
+ action: actionFor(state),
3729
+ checkpoint_kind: packet?.kind || null,
3730
+ allowed_decisions: packet?.allowed_decisions,
3731
+ retryable: state.status === "running" || state.status === "awaiting_checkpoint",
3732
+ reason: state.blocker?.code || packet?.summary || latestEvent?.summary || null
3733
+ }),
3734
+ evidence_contract: compactRecord({
3735
+ verification_mode: state.request.verification_mode || nonEmptyString(fullState.verification_mode),
3736
+ required,
3737
+ artifact_contract: artifactContract,
3738
+ proof_plan: compactText2(state.proof_contract?.proof_plan || fullState.proof_plan, 600),
3739
+ stop_condition: compactText2(state.proof_contract?.stop_condition, 400)
3740
+ }),
3741
+ latest_evidence: compactRecord({
3742
+ before_url: nonEmptyString(fullState.before_cdn) || state.before_artifact_url || null,
3743
+ prod_url: nonEmptyString(fullState.prod_cdn) || state.prod_artifact_url || null,
3744
+ after_url: nonEmptyString(fullState.after_cdn) || state.after_artifact_url || null,
3745
+ visual_delta: visualDelta || null,
3746
+ evidence_issue_code: evidenceIssueCode({ fullRiddleState: fullState, runState: state }) || null,
3747
+ proof_evidence_present: fullState.proof_evidence_present === true || Boolean(bundle?.proof_evidence || bundle?.proof_evidence_sample),
3748
+ artifacts
3749
+ }),
3750
+ stop_condition: compactRecord({
3751
+ status: state.status,
3752
+ terminal: isTerminalStatus(state.status),
3753
+ blocker_code: state.blocker?.code || null,
3754
+ blocker_message: state.blocker?.message || null,
3755
+ proof_decision: state.proof_decision,
3756
+ merge_recommendation: state.merge_recommendation,
3757
+ monitor_should_continue: !isTerminalStatus(state.status)
3758
+ }),
3759
+ updated_at: state.updated_at
3760
+ };
3761
+ }
3762
+
3763
+ // src/state.ts
3764
+ var RIDDLE_PROOF_RUN_STATE_VERSION = "riddle-proof.run-state.v1";
3765
+ function timestamp2() {
3766
+ return (/* @__PURE__ */ new Date()).toISOString();
3767
+ }
3768
+ function createRunId(createdAt) {
3769
+ const stamp = createdAt.replace(/\D/g, "").slice(0, 14) || "unknown";
3770
+ const entropy = Math.random().toString(36).slice(2, 8) || "run";
3771
+ return `rp_${stamp}_${entropy}`;
3772
+ }
3773
+ function elapsedMs2(start, end) {
3774
+ const startMs = start ? Date.parse(start) : NaN;
3775
+ const endMs = end ? Date.parse(end) : NaN;
3776
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return void 0;
3777
+ return Math.max(0, endMs - startMs);
3778
+ }
3779
+ function normalizeIntegrationContext(input, fallbackSource) {
3780
+ const value = recordValue(input);
3781
+ if (!value) {
3782
+ return fallbackSource ? { source: fallbackSource } : void 0;
3783
+ }
3784
+ const metadata = recordValue(value.metadata);
3785
+ return compactRecord({
3786
+ source: nonEmptyString(value.source) || fallbackSource,
3787
+ channel_id: nonEmptyString(value.channel_id),
3788
+ thread_id: nonEmptyString(value.thread_id),
3789
+ message_id: nonEmptyString(value.message_id),
3790
+ source_url: nonEmptyString(value.source_url),
3791
+ metadata: metadata && Object.keys(metadata).length ? metadata : void 0
3792
+ });
3793
+ }
3794
+ function normalizeRunParams(input) {
3795
+ return compactRecord({
3796
+ repo: input.repo,
3797
+ branch: input.branch,
3798
+ change_request: input.change_request,
3799
+ commit_message: input.commit_message,
3800
+ prod_url: input.prod_url,
3801
+ capture_script: input.capture_script,
3802
+ success_criteria: input.success_criteria,
3803
+ assertions: input.assertions,
3804
+ verification_mode: input.verification_mode,
3805
+ resume_session: input.resume_session,
3806
+ target_image_url: input.target_image_url,
3807
+ target_image_hash: input.target_image_hash,
3808
+ viewport_matrix: input.viewport_matrix,
3809
+ deterministic_setup: input.deterministic_setup,
3810
+ reference: input.reference,
3811
+ base_branch: input.base_branch,
3812
+ before_ref: input.before_ref,
3813
+ allow_static_preview_fallback: input.allow_static_preview_fallback,
3814
+ context: input.context,
3815
+ reviewer: input.reviewer,
3816
+ mode: input.mode,
3817
+ build_command: input.build_command,
3818
+ build_output: input.build_output,
3819
+ server_image: input.server_image,
3820
+ server_command: input.server_command,
3821
+ server_port: input.server_port,
3822
+ server_path: input.server_path,
3823
+ use_auth: input.use_auth,
3824
+ auth_localStorage_json: input.auth_localStorage_json,
3825
+ auth_cookies_json: input.auth_cookies_json,
3826
+ auth_headers_json: input.auth_headers_json,
3827
+ color_scheme: input.color_scheme,
3828
+ wait_for_selector: input.wait_for_selector,
3829
+ ship_mode: input.ship_mode,
3830
+ leave_draft: input.leave_draft,
3831
+ engine_state_path: input.engine_state_path,
3832
+ harness_state_path: input.harness_state_path,
3833
+ max_iterations: input.max_iterations,
3834
+ auto_approve: input.auto_approve,
3835
+ dry_run: input.dry_run,
3836
+ integration_context: normalizeIntegrationContext(input.integration_context)
3506
3837
  });
3507
3838
  }
3508
- function checkpointSummaryFromState(state, engineStatePath2) {
3509
- const history = state.checkpoint_history || [];
3510
- const packets = history.filter((entry) => entry.packet);
3511
- const responses = history.filter((entry) => entry.response);
3512
- const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3513
- const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3514
- const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3515
- const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
3516
- const latestResponse = latestResponseEntry?.response;
3517
- const latestResumeToken = latestPacket?.resume_token || null;
3518
- const latestResponseToken = latestResponse?.resume_token || null;
3519
- const tokenMatches = latestResumeToken && latestResponseToken ? latestResumeToken === latestResponseToken : latestResumeToken || latestResponseToken ? false : null;
3839
+ function createRunState(input) {
3840
+ const createdAt = input.created_at || timestamp2();
3520
3841
  return compactRecord({
3521
- pending: Boolean(state.checkpoint_packet),
3522
- packet_count: packets.length,
3523
- response_count: responses.length,
3524
- duplicate_response_count: duplicateResponses.length,
3525
- latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3526
- latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3527
- latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
3528
- latest_decision: latestResponse?.decision || null,
3529
- latest_packet_summary: latestPacket?.summary || null,
3530
- latest_response_summary: latestResponse?.summary || null,
3531
- latest_resume_token: latestResumeToken,
3532
- latest_response_token: latestResponseToken,
3533
- token_matches: tokenMatches,
3534
- last_packet_at: latestPacketEntry?.ts || null,
3535
- last_response_at: latestResponseEntry?.ts || null,
3536
- state_paths: statePathsForRunState(state, engineStatePath2)
3842
+ version: RIDDLE_PROOF_RUN_STATE_VERSION,
3843
+ run_id: input.run_id || createRunId(createdAt),
3844
+ state_path: input.state_path,
3845
+ worktree_path: input.worktree_path,
3846
+ branch: input.branch || input.request.branch,
3847
+ current_stage: input.current_stage ?? null,
3848
+ stage_started_at: input.stage_started_at ?? null,
3849
+ status: input.status || "running",
3850
+ created_at: createdAt,
3851
+ updated_at: input.updated_at || createdAt,
3852
+ request: normalizeRunParams(input.request),
3853
+ iterations: input.iterations ?? 0,
3854
+ last_checkpoint: input.last_checkpoint ?? null,
3855
+ checkpoint_packet: input.checkpoint_packet,
3856
+ checkpoint_summary: input.checkpoint_summary,
3857
+ state_paths: input.state_paths,
3858
+ proof_contract: input.proof_contract,
3859
+ run_card: input.run_card,
3860
+ checkpoint_history: input.checkpoint_history,
3861
+ events: input.events ? [...input.events] : []
3537
3862
  });
3538
3863
  }
3539
- function isDuplicateCheckpointResponse(state, response) {
3540
- const identity = checkpointResponseIdentity(response);
3541
- return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
3864
+ function appendRunEvent(state, input) {
3865
+ const event = {
3866
+ ts: input.ts || timestamp2(),
3867
+ kind: input.kind,
3868
+ checkpoint: input.checkpoint,
3869
+ stage: input.stage,
3870
+ summary: input.summary,
3871
+ details: input.details
3872
+ };
3873
+ state.events.push(compactRecord({
3874
+ ts: event.ts,
3875
+ kind: event.kind,
3876
+ checkpoint: event.checkpoint,
3877
+ stage: event.stage,
3878
+ summary: event.summary,
3879
+ details: event.details
3880
+ }));
3881
+ if (input.checkpoint !== void 0) state.last_checkpoint = input.checkpoint;
3882
+ if (input.stage !== void 0) {
3883
+ if (state.current_stage !== input.stage) state.stage_started_at = event.ts;
3884
+ state.current_stage = input.stage;
3885
+ }
3886
+ state.updated_at = event.ts;
3887
+ return state;
3542
3888
  }
3543
- function checkpointResponseIdentity(response) {
3544
- const logicalResponse = compactRecord({
3545
- run_id: response.run_id,
3546
- checkpoint: response.checkpoint,
3547
- resume_token: response.resume_token,
3548
- decision: response.decision,
3549
- summary: response.summary,
3550
- payload: response.payload,
3551
- reasons: response.reasons,
3552
- continue_with_stage: response.continue_with_stage,
3553
- source: response.source
3889
+ function appendStageHeartbeat(state, input) {
3890
+ const at = input.ts || timestamp2();
3891
+ return appendRunEvent(state, {
3892
+ ts: at,
3893
+ kind: "stage.heartbeat",
3894
+ checkpoint: input.checkpoint || `${input.stage}_heartbeat`,
3895
+ stage: input.stage,
3896
+ summary: input.summary || `${input.stage} stage is active.`,
3897
+ details: compactRecord({
3898
+ elapsed_ms: elapsedMs2(state.created_at, at),
3899
+ stage_elapsed_ms: elapsedMs2(state.stage_started_at, at),
3900
+ wait_reason: input.wait_reason,
3901
+ blocker: input.blocker,
3902
+ ...input.details
3903
+ })
3554
3904
  });
3555
- return import_node_crypto.default.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
3556
- }
3557
- function authorPacketPayloadFromCheckpointResponse(response) {
3558
- if (response.decision !== "author_packet") return null;
3559
- const payload = recordValue(response.payload);
3560
- if (!payload) return null;
3561
- const nested = recordValue(payload.author_packet);
3562
- const candidate = nested || payload;
3563
- if (!nonEmptyString(candidate.proof_plan) || !nonEmptyString(candidate.capture_script)) return null;
3564
- return candidate;
3565
3905
  }
3566
- function proofContractFromAuthorCheckpointResponse(response, packet, payload) {
3567
- const refinedInputs = recordValue(payload.refined_inputs) || {};
3906
+ function createRunStatusSnapshot(state, at = timestamp2()) {
3907
+ const latestEvent = state.events[state.events.length - 1];
3908
+ const runId = state.run_id || "unknown";
3568
3909
  return compactRecord({
3569
- version: "riddle-proof.proof-contract.v1",
3570
- checkpoint: packet.checkpoint,
3571
- source_response: compactRecord({
3572
- run_id: response.run_id,
3573
- checkpoint: response.checkpoint,
3574
- resume_token: response.resume_token,
3575
- decision: response.decision,
3576
- summary: response.summary,
3577
- created_at: response.created_at
3578
- }),
3579
- proof_plan: nonEmptyString(payload.proof_plan),
3580
- capture_script: nonEmptyString(payload.capture_script),
3581
- artifact_contract: jsonCloneRecord(payload.artifact_contract),
3582
- assertions: jsonCloneValue(payload.assertions),
3583
- baseline_understanding: jsonCloneRecord(payload.baseline_understanding) || jsonCloneRecord(payload.recon_baseline_understanding) || jsonCloneRecord(packet.state_excerpt?.recon_baseline_understanding),
3584
- route_assumptions: compactRecord({
3585
- server_path: nonEmptyString(refinedInputs.server_path) || nonEmptyString(payload.server_path) || nonEmptyString(packet.state_excerpt?.server_path),
3586
- wait_for_selector: nonEmptyString(refinedInputs.wait_for_selector) || nonEmptyString(payload.wait_for_selector) || nonEmptyString(packet.state_excerpt?.wait_for_selector),
3587
- reference: nonEmptyString(refinedInputs.reference) || nonEmptyString(payload.reference),
3588
- expected_path: nonEmptyString(payload.expected_path) || nonEmptyString(refinedInputs.expected_path)
3589
- }),
3590
- stop_condition: nonEmptyString(payload.stop_condition),
3591
- rationale: jsonCloneValue(payload.rationale),
3592
- verdict_dimensions: jsonCloneRecord(payload.verdict_dimensions),
3593
- payload: jsonCloneRecord(payload),
3594
- created_at: timestamp2()
3910
+ run_id: runId,
3911
+ status: state.status,
3912
+ is_terminal: isTerminalStatus(state.status),
3913
+ monitor_should_continue: !isTerminalStatus(state.status),
3914
+ current_stage: state.current_stage ?? null,
3915
+ state_path: state.state_path ?? null,
3916
+ worktree_path: state.worktree_path ?? null,
3917
+ branch: state.branch ?? null,
3918
+ pr_url: state.pr_url ?? null,
3919
+ pr_branch: state.pr_branch ?? null,
3920
+ pr_state: state.pr_state,
3921
+ ci_status: state.ci_status,
3922
+ ship_commit: state.ship_commit,
3923
+ ship_remote_head: state.ship_remote_head,
3924
+ merge_commit: state.merge_commit,
3925
+ merged_at: state.merged_at,
3926
+ proof_comment_url: state.proof_comment_url,
3927
+ cleanup_report: state.cleanup_report,
3928
+ iterations: state.iterations,
3929
+ last_checkpoint: state.last_checkpoint ?? null,
3930
+ updated_at: state.updated_at,
3931
+ elapsed_ms: elapsedMs2(state.created_at, at),
3932
+ stage_elapsed_ms: elapsedMs2(state.stage_started_at, at),
3933
+ blocker: state.blocker,
3934
+ checkpoint_packet: state.checkpoint_packet,
3935
+ checkpoint_summary: state.checkpoint_summary,
3936
+ state_paths: state.state_paths,
3937
+ proof_contract: state.proof_contract,
3938
+ run_card: createRiddleProofRunCard(state, { at }),
3939
+ latest_event: latestEvent
3595
3940
  });
3596
3941
  }
3942
+ function setRunStatus(state, status, at = timestamp2()) {
3943
+ state.status = status;
3944
+ state.ok = status !== "blocked" && status !== "failed";
3945
+ state.updated_at = at;
3946
+ return state;
3947
+ }
3597
3948
 
3598
3949
  // src/engine-harness.ts
3599
3950
  init_proof_run_core();
@@ -3672,6 +4023,10 @@ function shouldPreserveFinalizedRunState(filePath, incoming) {
3672
4023
  function persist(state) {
3673
4024
  state.state_paths = statePathsForRunState(state);
3674
4025
  state.checkpoint_summary = checkpointSummaryFromState(state);
4026
+ state.run_card = createRiddleProofRunCard(state, {
4027
+ fullRiddleState: readJson(state.request.engine_state_path),
4028
+ state_paths: state.state_paths
4029
+ });
3675
4030
  if (!state.state_path) return;
3676
4031
  if (shouldPreserveFinalizedRunState(state.state_path, state)) return;
3677
4032
  writeJson(state.state_path, state);
@@ -3751,7 +4106,7 @@ function removeEmptyToolArtifacts(workdir) {
3751
4106
  }
3752
4107
  return [];
3753
4108
  }
3754
- function stageFromCheckpoint(result) {
4109
+ function stageFromCheckpoint2(result) {
3755
4110
  const explicitStage = nonEmptyString(result.stage);
3756
4111
  if (explicitStage) return explicitStage;
3757
4112
  const checkpoint = String(result.checkpoint || "");
@@ -3896,6 +4251,41 @@ function proofAssessmentPayloadFromCheckpointResponse(response) {
3896
4251
  checkpoint_response_created_at: response.created_at
3897
4252
  });
3898
4253
  }
4254
+ function reconAssessmentPayloadFromCheckpointResponse(response) {
4255
+ if (![
4256
+ "ready_for_author",
4257
+ "retry_recon",
4258
+ "recon_stuck",
4259
+ "needs_recon"
4260
+ ].includes(response.decision)) {
4261
+ return null;
4262
+ }
4263
+ const payload = recordValue(response.payload) || {};
4264
+ const decision = response.decision === "needs_recon" ? "retry_recon" : response.decision;
4265
+ const continueStage = response.continue_with_stage || nonEmptyString(payload.continue_with_stage) || (decision === "ready_for_author" ? "author" : "recon");
4266
+ return compactRecord({
4267
+ ...payload,
4268
+ decision,
4269
+ summary: response.summary,
4270
+ continue_with_stage: continueStage,
4271
+ escalation_target: nonEmptyString(payload.escalation_target) || (decision === "recon_stuck" ? "human" : "agent"),
4272
+ reasons: Array.isArray(response.reasons) ? response.reasons : Array.isArray(payload.reasons) ? payload.reasons : [],
4273
+ source: "supervising_agent",
4274
+ checkpoint_response_source: response.source || null,
4275
+ checkpoint_response_created_at: response.created_at
4276
+ });
4277
+ }
4278
+ function implementationNotesFromCheckpointResponse(response) {
4279
+ const payload = recordValue(response.payload) || {};
4280
+ const notes = nonEmptyString(payload.implementation_notes) || nonEmptyString(payload.implementationNotes) || nonEmptyString(payload.summary) || response.summary;
4281
+ const changedFiles = Array.isArray(payload.changed_files) ? payload.changed_files.filter((item) => typeof item === "string") : [];
4282
+ const testsRun = Array.isArray(payload.tests_run) ? payload.tests_run.filter((item) => typeof item === "string") : [];
4283
+ return [
4284
+ notes,
4285
+ changedFiles.length ? `changed_files=${changedFiles.join(", ")}` : "",
4286
+ testsRun.length ? `tests_run=${testsRun.join(", ")}` : ""
4287
+ ].filter(Boolean).join("\n");
4288
+ }
3899
4289
  function proofAssessmentVisualBlocker(state, payload) {
3900
4290
  if (!proofAssessmentRequestsShip(payload)) return null;
3901
4291
  const source = nonEmptyString(payload.source) || "supervising_agent";
@@ -3984,7 +4374,7 @@ function engineFailureBlocker(result, checkpoint) {
3984
4374
  }
3985
4375
  function terminalResult(state, status, result, summary, raw = {}) {
3986
4376
  if (result) {
3987
- const terminalStage = stageFromCheckpoint(result);
4377
+ const terminalStage = stageFromCheckpoint2(result);
3988
4378
  if (terminalStage !== "setup") state.current_stage = terminalStage;
3989
4379
  }
3990
4380
  setRunStatus(state, status);
@@ -4010,7 +4400,7 @@ function terminalResult(state, status, result, summary, raw = {}) {
4010
4400
  function blockerResult(state, result, blocker) {
4011
4401
  state.blocker = blocker;
4012
4402
  const blockerStage = nonEmptyString(recordValue(blocker.details)?.stage);
4013
- const stage = blockerStage || stageFromCheckpoint(result || { checkpoint: blocker.checkpoint || void 0 });
4403
+ const stage = blockerStage || stageFromCheckpoint2(result || { checkpoint: blocker.checkpoint || void 0 });
4014
4404
  recordEvent(state, {
4015
4405
  kind: "run.blocked",
4016
4406
  checkpoint: blocker.checkpoint || result?.checkpoint || null,
@@ -4197,6 +4587,67 @@ function checkpointResponseContinuation(state, value) {
4197
4587
  appendCheckpointResponse(state, response);
4198
4588
  return { next: { ...base, author_packet_json: jsonParam(payload) } };
4199
4589
  }
4590
+ if (packet.kind === "assess_recon" || packet.stage === "recon") {
4591
+ const assessment = reconAssessmentPayloadFromCheckpointResponse(response);
4592
+ if (assessment) {
4593
+ appendCheckpointResponse(state, response);
4594
+ return { next: { ...base, recon_assessment_json: jsonParam(assessment) } };
4595
+ }
4596
+ if (response.decision === "blocked" || response.decision === "human_review") {
4597
+ appendCheckpointResponse(state, response, { clear_packet: false });
4598
+ return {
4599
+ blocker: {
4600
+ code: `checkpoint_response_${response.decision}`,
4601
+ checkpoint: packet.checkpoint,
4602
+ message: response.summary || `Checkpoint response stopped recon with decision=${response.decision}.`,
4603
+ details: { stage: packet.stage, response }
4604
+ }
4605
+ };
4606
+ }
4607
+ }
4608
+ if (packet.kind === "implement_change" || packet.stage === "implement") {
4609
+ if (response.decision === "implementation_complete") {
4610
+ const workdir = nonEmptyString(packet.state_excerpt?.after_worktree) || state.worktree_path;
4611
+ if (workdir) state.worktree_path = workdir;
4612
+ if (!hasGitDiff(workdir)) {
4613
+ return {
4614
+ blocker: {
4615
+ code: "implementation_diff_missing",
4616
+ checkpoint: packet.checkpoint,
4617
+ message: "Checkpoint response claimed implementation_complete, but the after worktree has no detectable git diff.",
4618
+ details: { stage: packet.stage, worktree_path: workdir || null, response }
4619
+ }
4620
+ };
4621
+ }
4622
+ appendCheckpointResponse(state, response);
4623
+ return {
4624
+ next: {
4625
+ ...base,
4626
+ advance_stage: "implement",
4627
+ implementation_notes: implementationNotesFromCheckpointResponse(response)
4628
+ }
4629
+ };
4630
+ }
4631
+ if (response.decision === "needs_author") {
4632
+ appendCheckpointResponse(state, response);
4633
+ return { next: { ...base, advance_stage: "author" } };
4634
+ }
4635
+ if (response.decision === "needs_recon") {
4636
+ appendCheckpointResponse(state, response);
4637
+ return { next: { ...base, advance_stage: "recon" } };
4638
+ }
4639
+ if (response.decision === "blocked" || response.decision === "human_review") {
4640
+ appendCheckpointResponse(state, response, { clear_packet: false });
4641
+ return {
4642
+ blocker: {
4643
+ code: `checkpoint_response_${response.decision}`,
4644
+ checkpoint: packet.checkpoint,
4645
+ message: response.summary || `Checkpoint response stopped implementation with decision=${response.decision}.`,
4646
+ details: { stage: packet.stage, response }
4647
+ }
4648
+ };
4649
+ }
4650
+ }
4200
4651
  if (response.decision === "needs_recon") {
4201
4652
  appendCheckpointResponse(state, response);
4202
4653
  if (packet.kind === "assess_proof" || packet.kind === "recover_evidence" || packet.stage === "verify") {
@@ -4464,6 +4915,9 @@ async function routeCheckpoint(request, state, result, agent, input) {
4464
4915
  };
4465
4916
  }
4466
4917
  if (checkpoint === "recon_supervisor_judgment") {
4918
+ if (input.checkpoint_mode === "yield") {
4919
+ return { terminal: checkpointAwaitingResult(state, result, input.checkpoint_visibility) };
4920
+ }
4467
4921
  const assessment = await agent.assessRecon(context);
4468
4922
  const blocker = requirePayload("recon_assessment", assessment, state, result);
4469
4923
  if (blocker) return { blocker };
@@ -4499,6 +4953,13 @@ async function routeCheckpoint(request, state, result, agent, input) {
4499
4953
  };
4500
4954
  }
4501
4955
  if (checkpoint === "implement_changes_missing" || checkpoint === "implement_required" || checkpoint === "verify_agent_retry" && continueStage === "implement") {
4956
+ if (input.checkpoint_mode === "yield") {
4957
+ const fullState = context.fullRiddleState || {};
4958
+ state.worktree_path = workdirFromState(fullState) || state.worktree_path;
4959
+ state.branch = nonEmptyString(fullState.branch) || state.branch;
4960
+ persist(state);
4961
+ return { terminal: checkpointAwaitingResult(state, result, input.checkpoint_visibility) };
4962
+ }
4502
4963
  return handleImplementation(request, state, result, agent);
4503
4964
  }
4504
4965
  if (checkpoint === "implement_review") {
@@ -4711,7 +5172,7 @@ async function runRiddleProofEngineHarness(input) {
4711
5172
  const engineState = engineStatePath(result, state);
4712
5173
  if (engineState) state.request.engine_state_path = engineState;
4713
5174
  state.last_checkpoint = result.checkpoint || state.last_checkpoint || null;
4714
- const resultStage = stageFromCheckpoint(result);
5175
+ const resultStage = stageFromCheckpoint2(result);
4715
5176
  stageIterations[resultStage] = (stageIterations[resultStage] || 0) + 1;
4716
5177
  heartbeat(state, {
4717
5178
  stage: resultStage,