@riddledc/riddle-proof 0.5.39 → 0.5.41

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.
@@ -2946,6 +2946,9 @@ function createRunResult(input) {
2946
2946
  finalized: state.finalized,
2947
2947
  blocker: state.blocker,
2948
2948
  checkpoint_packet: state.checkpoint_packet,
2949
+ checkpoint_summary: state.checkpoint_summary,
2950
+ state_paths: state.state_paths,
2951
+ proof_contract: state.proof_contract,
2949
2952
  proof_session: state.proof_session,
2950
2953
  evidence_bundle: input.evidence_bundle,
2951
2954
  raw: input.raw
@@ -3045,6 +3048,9 @@ function createRunState(input) {
3045
3048
  iterations: input.iterations ?? 0,
3046
3049
  last_checkpoint: input.last_checkpoint ?? null,
3047
3050
  checkpoint_packet: input.checkpoint_packet,
3051
+ checkpoint_summary: input.checkpoint_summary,
3052
+ state_paths: input.state_paths,
3053
+ proof_contract: input.proof_contract,
3048
3054
  checkpoint_history: input.checkpoint_history,
3049
3055
  events: input.events ? [...input.events] : []
3050
3056
  });
@@ -3120,6 +3126,9 @@ function createRunStatusSnapshot(state, at = timestamp()) {
3120
3126
  stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
3121
3127
  blocker: state.blocker,
3122
3128
  checkpoint_packet: state.checkpoint_packet,
3129
+ checkpoint_summary: state.checkpoint_summary,
3130
+ state_paths: state.state_paths,
3131
+ proof_contract: state.proof_contract,
3123
3132
  latest_event: latestEvent
3124
3133
  });
3125
3134
  }
@@ -3146,11 +3155,34 @@ function jsonCloneRecord(value) {
3146
3155
  return { ...record };
3147
3156
  }
3148
3157
  }
3158
+ function jsonCloneValue(value) {
3159
+ if (value === void 0 || value === null) return void 0;
3160
+ try {
3161
+ return JSON.parse(JSON.stringify(value));
3162
+ } catch {
3163
+ return value;
3164
+ }
3165
+ }
3166
+ function stableJson(value) {
3167
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
3168
+ const record = recordValue(value);
3169
+ if (record) {
3170
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
3171
+ }
3172
+ return JSON.stringify(value);
3173
+ }
3149
3174
  function compactText(value, limit = 1600) {
3150
3175
  const text = nonEmptyString(value);
3151
3176
  if (!text) return void 0;
3152
3177
  return text.length <= limit ? text : `${text.slice(0, limit - 20).trimEnd()}...`;
3153
3178
  }
3179
+ function statePathsForRunState(state, engineStatePath2) {
3180
+ return compactRecord({
3181
+ wrapper_state_path: state.state_path || state.request.harness_state_path || null,
3182
+ engine_state_path: engineStatePath2 || state.request.engine_state_path || null,
3183
+ resume_state_path: engineStatePath2 || state.request.engine_state_path || null
3184
+ });
3185
+ }
3154
3186
  function responseSchemaForAuthorPacket() {
3155
3187
  return {
3156
3188
  type: "object",
@@ -3292,6 +3324,55 @@ function normalizeCheckpointResponse(value) {
3292
3324
  created_at: nonEmptyString(record.created_at) || timestamp2()
3293
3325
  });
3294
3326
  }
3327
+ function checkpointSummaryFromState(state, engineStatePath2) {
3328
+ const history = state.checkpoint_history || [];
3329
+ const packets = history.filter((entry) => entry.packet);
3330
+ const responses = history.filter((entry) => entry.response);
3331
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3332
+ const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3333
+ const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3334
+ const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
3335
+ const latestResponse = latestResponseEntry?.response;
3336
+ const latestResumeToken = latestPacket?.resume_token || null;
3337
+ const latestResponseToken = latestResponse?.resume_token || null;
3338
+ const tokenMatches = latestResumeToken && latestResponseToken ? latestResumeToken === latestResponseToken : latestResumeToken || latestResponseToken ? false : null;
3339
+ return compactRecord({
3340
+ pending: Boolean(state.checkpoint_packet),
3341
+ packet_count: packets.length,
3342
+ response_count: responses.length,
3343
+ duplicate_response_count: duplicateResponses.length,
3344
+ latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3345
+ latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3346
+ latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
3347
+ latest_decision: latestResponse?.decision || null,
3348
+ latest_packet_summary: latestPacket?.summary || null,
3349
+ latest_response_summary: latestResponse?.summary || null,
3350
+ latest_resume_token: latestResumeToken,
3351
+ latest_response_token: latestResponseToken,
3352
+ token_matches: tokenMatches,
3353
+ last_packet_at: latestPacketEntry?.ts || null,
3354
+ last_response_at: latestResponseEntry?.ts || null,
3355
+ state_paths: statePathsForRunState(state, engineStatePath2)
3356
+ });
3357
+ }
3358
+ function isDuplicateCheckpointResponse(state, response) {
3359
+ const identity = checkpointResponseIdentity(response);
3360
+ return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
3361
+ }
3362
+ function checkpointResponseIdentity(response) {
3363
+ const logicalResponse = compactRecord({
3364
+ run_id: response.run_id,
3365
+ checkpoint: response.checkpoint,
3366
+ resume_token: response.resume_token,
3367
+ decision: response.decision,
3368
+ summary: response.summary,
3369
+ payload: response.payload,
3370
+ reasons: response.reasons,
3371
+ continue_with_stage: response.continue_with_stage,
3372
+ source: response.source
3373
+ });
3374
+ return import_node_crypto.default.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
3375
+ }
3295
3376
  function authorPacketPayloadFromCheckpointResponse(response) {
3296
3377
  if (response.decision !== "author_packet") return null;
3297
3378
  const payload = recordValue(response.payload);
@@ -3301,6 +3382,37 @@ function authorPacketPayloadFromCheckpointResponse(response) {
3301
3382
  if (!nonEmptyString(candidate.proof_plan) || !nonEmptyString(candidate.capture_script)) return null;
3302
3383
  return candidate;
3303
3384
  }
3385
+ function proofContractFromAuthorCheckpointResponse(response, packet, payload) {
3386
+ const refinedInputs = recordValue(payload.refined_inputs) || {};
3387
+ return compactRecord({
3388
+ version: "riddle-proof.proof-contract.v1",
3389
+ checkpoint: packet.checkpoint,
3390
+ source_response: compactRecord({
3391
+ run_id: response.run_id,
3392
+ checkpoint: response.checkpoint,
3393
+ resume_token: response.resume_token,
3394
+ decision: response.decision,
3395
+ summary: response.summary,
3396
+ created_at: response.created_at
3397
+ }),
3398
+ proof_plan: nonEmptyString(payload.proof_plan),
3399
+ capture_script: nonEmptyString(payload.capture_script),
3400
+ artifact_contract: jsonCloneRecord(payload.artifact_contract),
3401
+ assertions: jsonCloneValue(payload.assertions),
3402
+ baseline_understanding: jsonCloneRecord(payload.baseline_understanding) || jsonCloneRecord(payload.recon_baseline_understanding) || jsonCloneRecord(packet.state_excerpt?.recon_baseline_understanding),
3403
+ route_assumptions: compactRecord({
3404
+ server_path: nonEmptyString(refinedInputs.server_path) || nonEmptyString(payload.server_path) || nonEmptyString(packet.state_excerpt?.server_path),
3405
+ wait_for_selector: nonEmptyString(refinedInputs.wait_for_selector) || nonEmptyString(payload.wait_for_selector) || nonEmptyString(packet.state_excerpt?.wait_for_selector),
3406
+ reference: nonEmptyString(refinedInputs.reference) || nonEmptyString(payload.reference),
3407
+ expected_path: nonEmptyString(payload.expected_path) || nonEmptyString(refinedInputs.expected_path)
3408
+ }),
3409
+ stop_condition: nonEmptyString(payload.stop_condition),
3410
+ rationale: jsonCloneValue(payload.rationale),
3411
+ verdict_dimensions: jsonCloneRecord(payload.verdict_dimensions),
3412
+ payload: jsonCloneRecord(payload),
3413
+ created_at: timestamp2()
3414
+ });
3415
+ }
3304
3416
 
3305
3417
  // src/engine-harness.ts
3306
3418
  init_proof_run_core();
@@ -3377,6 +3489,8 @@ function shouldPreserveFinalizedRunState(filePath, incoming) {
3377
3489
  return !(existing.status === "ready_to_ship" && incoming.status === "shipped");
3378
3490
  }
3379
3491
  function persist(state) {
3492
+ state.state_paths = statePathsForRunState(state);
3493
+ state.checkpoint_summary = checkpointSummaryFromState(state);
3380
3494
  if (!state.state_path) return;
3381
3495
  if (shouldPreserveFinalizedRunState(state.state_path, state)) return;
3382
3496
  writeJson(state.state_path, state);
@@ -3633,6 +3747,10 @@ function engineFailureBlocker(result, checkpoint) {
3633
3747
  };
3634
3748
  }
3635
3749
  function terminalResult(state, status, result, summary, raw = {}) {
3750
+ if (result) {
3751
+ const terminalStage = stageFromCheckpoint(result);
3752
+ if (terminalStage !== "setup") state.current_stage = terminalStage;
3753
+ }
3636
3754
  setRunStatus(state, status);
3637
3755
  if (isProtectedFinalStatus(status)) state.finalized = true;
3638
3756
  const metadata = normalizeTerminalMetadata({
@@ -3655,10 +3773,12 @@ function terminalResult(state, status, result, summary, raw = {}) {
3655
3773
  }
3656
3774
  function blockerResult(state, result, blocker) {
3657
3775
  state.blocker = blocker;
3776
+ const blockerStage = nonEmptyString(recordValue(blocker.details)?.stage);
3777
+ const stage = blockerStage || stageFromCheckpoint(result || { checkpoint: blocker.checkpoint || void 0 });
3658
3778
  recordEvent(state, {
3659
3779
  kind: "run.blocked",
3660
3780
  checkpoint: blocker.checkpoint || result?.checkpoint || null,
3661
- stage: stageFromCheckpoint(result || {}),
3781
+ stage,
3662
3782
  summary: blocker.message,
3663
3783
  details: {
3664
3784
  code: blocker.code,
@@ -3750,7 +3870,35 @@ function checkpointResponseContinuation(state, value) {
3750
3870
  code: "checkpoint_response_invalid",
3751
3871
  checkpoint: packet?.checkpoint || state.last_checkpoint || null,
3752
3872
  message: "Checkpoint response was not a valid riddle-proof.checkpoint_response.v1 object.",
3753
- details: { checkpoint_packet: packet || null }
3873
+ details: { checkpoint_packet: packet || null, checkpoint_summary: checkpointSummaryFromState(state) }
3874
+ }
3875
+ };
3876
+ }
3877
+ if (isDuplicateCheckpointResponse(state, response)) {
3878
+ const stage = packet?.stage || state.current_stage || "author";
3879
+ recordEvent(state, {
3880
+ kind: "checkpoint.response.duplicate",
3881
+ checkpoint: response.checkpoint,
3882
+ stage,
3883
+ summary: "Duplicate checkpoint response ignored.",
3884
+ details: compactRecord({
3885
+ decision: response.decision,
3886
+ resume_token: response.resume_token,
3887
+ response_identity: checkpointResponseIdentity(response)
3888
+ })
3889
+ });
3890
+ return {
3891
+ blocker: {
3892
+ code: "checkpoint_response_duplicate",
3893
+ checkpoint: response.checkpoint,
3894
+ message: "Checkpoint response was already accepted for this run/checkpoint/resume token and was not applied again.",
3895
+ details: {
3896
+ stage,
3897
+ duplicate: true,
3898
+ response,
3899
+ response_identity: checkpointResponseIdentity(response),
3900
+ checkpoint_summary: checkpointSummaryFromState(state)
3901
+ }
3754
3902
  }
3755
3903
  };
3756
3904
  }
@@ -3760,7 +3908,7 @@ function checkpointResponseContinuation(state, value) {
3760
3908
  code: "checkpoint_response_without_packet",
3761
3909
  checkpoint: response.checkpoint,
3762
3910
  message: "A checkpoint response was supplied, but the run state has no pending checkpoint packet.",
3763
- details: { response }
3911
+ details: { response, checkpoint_summary: checkpointSummaryFromState(state) }
3764
3912
  }
3765
3913
  };
3766
3914
  }
@@ -3771,6 +3919,7 @@ function checkpointResponseContinuation(state, value) {
3771
3919
  checkpoint: packet.checkpoint,
3772
3920
  message: "Checkpoint response does not match the pending checkpoint packet.",
3773
3921
  details: {
3922
+ stage: packet.stage,
3774
3923
  expected: { run_id: packet.run_id, checkpoint: packet.checkpoint },
3775
3924
  actual: { run_id: response.run_id, checkpoint: response.checkpoint }
3776
3925
  }
@@ -3783,7 +3932,11 @@ function checkpointResponseContinuation(state, value) {
3783
3932
  code: "checkpoint_response_resume_token_mismatch",
3784
3933
  checkpoint: packet.checkpoint,
3785
3934
  message: "Checkpoint response resume_token does not match the pending checkpoint packet.",
3786
- details: { expected_resume_token: packet.resume_token, actual_resume_token: response.resume_token || null }
3935
+ details: {
3936
+ stage: packet.stage,
3937
+ expected_resume_token: packet.resume_token,
3938
+ actual_resume_token: response.resume_token || null
3939
+ }
3787
3940
  }
3788
3941
  };
3789
3942
  }
@@ -3800,10 +3953,11 @@ function checkpointResponseContinuation(state, value) {
3800
3953
  code: "checkpoint_author_packet_missing",
3801
3954
  checkpoint: packet.checkpoint,
3802
3955
  message: "Checkpoint response decision=author_packet did not include a proof_plan and capture_script payload.",
3803
- details: { response }
3956
+ details: { stage: packet.stage, response }
3804
3957
  }
3805
3958
  };
3806
3959
  }
3960
+ state.proof_contract = proofContractFromAuthorCheckpointResponse(response, packet, payload);
3807
3961
  appendCheckpointResponse(state, response);
3808
3962
  return { next: { ...base, author_packet_json: jsonParam(payload) } };
3809
3963
  }
@@ -3817,7 +3971,7 @@ function checkpointResponseContinuation(state, value) {
3817
3971
  code: `checkpoint_response_${response.decision}`,
3818
3972
  checkpoint: packet.checkpoint,
3819
3973
  message: response.summary || `Checkpoint response stopped the run with decision=${response.decision}.`,
3820
- details: { response }
3974
+ details: { stage: packet.stage, response }
3821
3975
  }
3822
3976
  };
3823
3977
  }
@@ -2,10 +2,10 @@ import {
2
2
  createDisabledRiddleProofAgentAdapter,
3
3
  readRiddleProofRunStatus,
4
4
  runRiddleProofEngineHarness
5
- } from "./chunk-ORRP7CXT.js";
6
- import "./chunk-UQPTCP4D.js";
7
- import "./chunk-Z3BWCHFV.js";
8
- import "./chunk-Z7QUCDPT.js";
5
+ } from "./chunk-ZBM67XGB.js";
6
+ import "./chunk-RI25RGQP.js";
7
+ import "./chunk-7S7O3NKF.js";
8
+ import "./chunk-W7VTDN4T.js";
9
9
  import "./chunk-4YCWZVBN.js";
10
10
  export {
11
11
  createDisabledRiddleProofAgentAdapter,
package/dist/index.cjs CHANGED
@@ -2751,6 +2751,8 @@ __export(index_exports, {
2751
2751
  authorPacketPayloadFromCheckpointResponse: () => authorPacketPayloadFromCheckpointResponse,
2752
2752
  buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
2753
2753
  buildVisualProofSession: () => buildVisualProofSession,
2754
+ checkpointResponseIdentity: () => checkpointResponseIdentity,
2755
+ checkpointSummaryFromState: () => checkpointSummaryFromState,
2754
2756
  compactRecord: () => compactRecord,
2755
2757
  compareVisualProofSessionFingerprint: () => compareVisualProofSessionFingerprint,
2756
2758
  createCaptureDiagnostic: () => createCaptureDiagnostic,
@@ -2759,6 +2761,7 @@ __export(index_exports, {
2759
2761
  createRunState: () => createRunState,
2760
2762
  createRunStatusSnapshot: () => createRunStatusSnapshot,
2761
2763
  extractPlayabilityEvidence: () => extractPlayabilityEvidence,
2764
+ isDuplicateCheckpointResponse: () => isDuplicateCheckpointResponse,
2762
2765
  isRiddleProofPlayabilityMode: () => isRiddleProofPlayabilityMode,
2763
2766
  isSuccessfulStatus: () => isSuccessfulStatus,
2764
2767
  isTerminalStatus: () => isTerminalStatus,
@@ -2769,12 +2772,14 @@ __export(index_exports, {
2769
2772
  normalizeRunParams: () => normalizeRunParams,
2770
2773
  normalizeTerminalMetadata: () => normalizeTerminalMetadata,
2771
2774
  parseVisualProofSession: () => parseVisualProofSession,
2775
+ proofContractFromAuthorCheckpointResponse: () => proofContractFromAuthorCheckpointResponse,
2772
2776
  readRiddleProofRunStatus: () => readRiddleProofRunStatus,
2773
2777
  recordValue: () => recordValue,
2774
2778
  redactForProofDiagnostics: () => redactForProofDiagnostics,
2775
2779
  runRiddleProof: () => runRiddleProof,
2776
2780
  runRiddleProofEngineHarness: () => runRiddleProofEngineHarness,
2777
2781
  setRunStatus: () => setRunStatus,
2782
+ statePathsForRunState: () => statePathsForRunState,
2778
2783
  summarizeCaptureArtifacts: () => summarizeCaptureArtifacts,
2779
2784
  visualSessionFingerprint: () => visualSessionFingerprint,
2780
2785
  visualSessionFingerprintBasis: () => visualSessionFingerprintBasis
@@ -2986,6 +2991,9 @@ function createRunResult(input) {
2986
2991
  finalized: state.finalized,
2987
2992
  blocker: state.blocker,
2988
2993
  checkpoint_packet: state.checkpoint_packet,
2994
+ checkpoint_summary: state.checkpoint_summary,
2995
+ state_paths: state.state_paths,
2996
+ proof_contract: state.proof_contract,
2989
2997
  proof_session: state.proof_session,
2990
2998
  evidence_bundle: input.evidence_bundle,
2991
2999
  raw: input.raw
@@ -3115,6 +3123,9 @@ function createRunState(input) {
3115
3123
  iterations: input.iterations ?? 0,
3116
3124
  last_checkpoint: input.last_checkpoint ?? null,
3117
3125
  checkpoint_packet: input.checkpoint_packet,
3126
+ checkpoint_summary: input.checkpoint_summary,
3127
+ state_paths: input.state_paths,
3128
+ proof_contract: input.proof_contract,
3118
3129
  checkpoint_history: input.checkpoint_history,
3119
3130
  events: input.events ? [...input.events] : []
3120
3131
  });
@@ -3190,6 +3201,9 @@ function createRunStatusSnapshot(state, at = timestamp()) {
3190
3201
  stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
3191
3202
  blocker: state.blocker,
3192
3203
  checkpoint_packet: state.checkpoint_packet,
3204
+ checkpoint_summary: state.checkpoint_summary,
3205
+ state_paths: state.state_paths,
3206
+ proof_contract: state.proof_contract,
3193
3207
  latest_event: latestEvent
3194
3208
  });
3195
3209
  }
@@ -3233,11 +3247,34 @@ function jsonCloneRecord(value) {
3233
3247
  return { ...record };
3234
3248
  }
3235
3249
  }
3250
+ function jsonCloneValue(value) {
3251
+ if (value === void 0 || value === null) return void 0;
3252
+ try {
3253
+ return JSON.parse(JSON.stringify(value));
3254
+ } catch {
3255
+ return value;
3256
+ }
3257
+ }
3258
+ function stableJson(value) {
3259
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
3260
+ const record = recordValue(value);
3261
+ if (record) {
3262
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
3263
+ }
3264
+ return JSON.stringify(value);
3265
+ }
3236
3266
  function compactText(value, limit = 1600) {
3237
3267
  const text = nonEmptyString(value);
3238
3268
  if (!text) return void 0;
3239
3269
  return text.length <= limit ? text : `${text.slice(0, limit - 20).trimEnd()}...`;
3240
3270
  }
3271
+ function statePathsForRunState(state, engineStatePath2) {
3272
+ return compactRecord({
3273
+ wrapper_state_path: state.state_path || state.request.harness_state_path || null,
3274
+ engine_state_path: engineStatePath2 || state.request.engine_state_path || null,
3275
+ resume_state_path: engineStatePath2 || state.request.engine_state_path || null
3276
+ });
3277
+ }
3241
3278
  function responseSchemaForAuthorPacket() {
3242
3279
  return {
3243
3280
  type: "object",
@@ -3379,6 +3416,55 @@ function normalizeCheckpointResponse(value) {
3379
3416
  created_at: nonEmptyString(record.created_at) || timestamp2()
3380
3417
  });
3381
3418
  }
3419
+ function checkpointSummaryFromState(state, engineStatePath2) {
3420
+ const history = state.checkpoint_history || [];
3421
+ const packets = history.filter((entry) => entry.packet);
3422
+ const responses = history.filter((entry) => entry.response);
3423
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3424
+ const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3425
+ const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3426
+ const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
3427
+ const latestResponse = latestResponseEntry?.response;
3428
+ const latestResumeToken = latestPacket?.resume_token || null;
3429
+ const latestResponseToken = latestResponse?.resume_token || null;
3430
+ const tokenMatches = latestResumeToken && latestResponseToken ? latestResumeToken === latestResponseToken : latestResumeToken || latestResponseToken ? false : null;
3431
+ return compactRecord({
3432
+ pending: Boolean(state.checkpoint_packet),
3433
+ packet_count: packets.length,
3434
+ response_count: responses.length,
3435
+ duplicate_response_count: duplicateResponses.length,
3436
+ latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3437
+ latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3438
+ latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
3439
+ latest_decision: latestResponse?.decision || null,
3440
+ latest_packet_summary: latestPacket?.summary || null,
3441
+ latest_response_summary: latestResponse?.summary || null,
3442
+ latest_resume_token: latestResumeToken,
3443
+ latest_response_token: latestResponseToken,
3444
+ token_matches: tokenMatches,
3445
+ last_packet_at: latestPacketEntry?.ts || null,
3446
+ last_response_at: latestResponseEntry?.ts || null,
3447
+ state_paths: statePathsForRunState(state, engineStatePath2)
3448
+ });
3449
+ }
3450
+ function isDuplicateCheckpointResponse(state, response) {
3451
+ const identity = checkpointResponseIdentity(response);
3452
+ return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
3453
+ }
3454
+ function checkpointResponseIdentity(response) {
3455
+ const logicalResponse = compactRecord({
3456
+ run_id: response.run_id,
3457
+ checkpoint: response.checkpoint,
3458
+ resume_token: response.resume_token,
3459
+ decision: response.decision,
3460
+ summary: response.summary,
3461
+ payload: response.payload,
3462
+ reasons: response.reasons,
3463
+ continue_with_stage: response.continue_with_stage,
3464
+ source: response.source
3465
+ });
3466
+ return import_node_crypto.default.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
3467
+ }
3382
3468
  function authorPacketPayloadFromCheckpointResponse(response) {
3383
3469
  if (response.decision !== "author_packet") return null;
3384
3470
  const payload = recordValue(response.payload);
@@ -3388,6 +3474,37 @@ function authorPacketPayloadFromCheckpointResponse(response) {
3388
3474
  if (!nonEmptyString(candidate.proof_plan) || !nonEmptyString(candidate.capture_script)) return null;
3389
3475
  return candidate;
3390
3476
  }
3477
+ function proofContractFromAuthorCheckpointResponse(response, packet, payload) {
3478
+ const refinedInputs = recordValue(payload.refined_inputs) || {};
3479
+ return compactRecord({
3480
+ version: "riddle-proof.proof-contract.v1",
3481
+ checkpoint: packet.checkpoint,
3482
+ source_response: compactRecord({
3483
+ run_id: response.run_id,
3484
+ checkpoint: response.checkpoint,
3485
+ resume_token: response.resume_token,
3486
+ decision: response.decision,
3487
+ summary: response.summary,
3488
+ created_at: response.created_at
3489
+ }),
3490
+ proof_plan: nonEmptyString(payload.proof_plan),
3491
+ capture_script: nonEmptyString(payload.capture_script),
3492
+ artifact_contract: jsonCloneRecord(payload.artifact_contract),
3493
+ assertions: jsonCloneValue(payload.assertions),
3494
+ baseline_understanding: jsonCloneRecord(payload.baseline_understanding) || jsonCloneRecord(payload.recon_baseline_understanding) || jsonCloneRecord(packet.state_excerpt?.recon_baseline_understanding),
3495
+ route_assumptions: compactRecord({
3496
+ server_path: nonEmptyString(refinedInputs.server_path) || nonEmptyString(payload.server_path) || nonEmptyString(packet.state_excerpt?.server_path),
3497
+ wait_for_selector: nonEmptyString(refinedInputs.wait_for_selector) || nonEmptyString(payload.wait_for_selector) || nonEmptyString(packet.state_excerpt?.wait_for_selector),
3498
+ reference: nonEmptyString(refinedInputs.reference) || nonEmptyString(payload.reference),
3499
+ expected_path: nonEmptyString(payload.expected_path) || nonEmptyString(refinedInputs.expected_path)
3500
+ }),
3501
+ stop_condition: nonEmptyString(payload.stop_condition),
3502
+ rationale: jsonCloneValue(payload.rationale),
3503
+ verdict_dimensions: jsonCloneRecord(payload.verdict_dimensions),
3504
+ payload: jsonCloneRecord(payload),
3505
+ created_at: timestamp2()
3506
+ });
3507
+ }
3391
3508
 
3392
3509
  // src/runner.ts
3393
3510
  function errorDetails(error) {
@@ -3950,6 +4067,8 @@ function shouldPreserveFinalizedRunState(filePath, incoming) {
3950
4067
  return !(existing.status === "ready_to_ship" && incoming.status === "shipped");
3951
4068
  }
3952
4069
  function persist(state) {
4070
+ state.state_paths = statePathsForRunState(state);
4071
+ state.checkpoint_summary = checkpointSummaryFromState(state);
3953
4072
  if (!state.state_path) return;
3954
4073
  if (shouldPreserveFinalizedRunState(state.state_path, state)) return;
3955
4074
  writeJson(state.state_path, state);
@@ -4206,6 +4325,10 @@ function engineFailureBlocker(result, checkpoint) {
4206
4325
  };
4207
4326
  }
4208
4327
  function terminalResult(state, status, result, summary, raw = {}) {
4328
+ if (result) {
4329
+ const terminalStage = stageFromCheckpoint(result);
4330
+ if (terminalStage !== "setup") state.current_stage = terminalStage;
4331
+ }
4209
4332
  setRunStatus(state, status);
4210
4333
  if (isProtectedFinalStatus(status)) state.finalized = true;
4211
4334
  const metadata = normalizeTerminalMetadata({
@@ -4228,10 +4351,12 @@ function terminalResult(state, status, result, summary, raw = {}) {
4228
4351
  }
4229
4352
  function blockerResult(state, result, blocker) {
4230
4353
  state.blocker = blocker;
4354
+ const blockerStage = nonEmptyString(recordValue(blocker.details)?.stage);
4355
+ const stage = blockerStage || stageFromCheckpoint(result || { checkpoint: blocker.checkpoint || void 0 });
4231
4356
  recordEvent(state, {
4232
4357
  kind: "run.blocked",
4233
4358
  checkpoint: blocker.checkpoint || result?.checkpoint || null,
4234
- stage: stageFromCheckpoint(result || {}),
4359
+ stage,
4235
4360
  summary: blocker.message,
4236
4361
  details: {
4237
4362
  code: blocker.code,
@@ -4323,7 +4448,35 @@ function checkpointResponseContinuation(state, value) {
4323
4448
  code: "checkpoint_response_invalid",
4324
4449
  checkpoint: packet?.checkpoint || state.last_checkpoint || null,
4325
4450
  message: "Checkpoint response was not a valid riddle-proof.checkpoint_response.v1 object.",
4326
- details: { checkpoint_packet: packet || null }
4451
+ details: { checkpoint_packet: packet || null, checkpoint_summary: checkpointSummaryFromState(state) }
4452
+ }
4453
+ };
4454
+ }
4455
+ if (isDuplicateCheckpointResponse(state, response)) {
4456
+ const stage = packet?.stage || state.current_stage || "author";
4457
+ recordEvent(state, {
4458
+ kind: "checkpoint.response.duplicate",
4459
+ checkpoint: response.checkpoint,
4460
+ stage,
4461
+ summary: "Duplicate checkpoint response ignored.",
4462
+ details: compactRecord({
4463
+ decision: response.decision,
4464
+ resume_token: response.resume_token,
4465
+ response_identity: checkpointResponseIdentity(response)
4466
+ })
4467
+ });
4468
+ return {
4469
+ blocker: {
4470
+ code: "checkpoint_response_duplicate",
4471
+ checkpoint: response.checkpoint,
4472
+ message: "Checkpoint response was already accepted for this run/checkpoint/resume token and was not applied again.",
4473
+ details: {
4474
+ stage,
4475
+ duplicate: true,
4476
+ response,
4477
+ response_identity: checkpointResponseIdentity(response),
4478
+ checkpoint_summary: checkpointSummaryFromState(state)
4479
+ }
4327
4480
  }
4328
4481
  };
4329
4482
  }
@@ -4333,7 +4486,7 @@ function checkpointResponseContinuation(state, value) {
4333
4486
  code: "checkpoint_response_without_packet",
4334
4487
  checkpoint: response.checkpoint,
4335
4488
  message: "A checkpoint response was supplied, but the run state has no pending checkpoint packet.",
4336
- details: { response }
4489
+ details: { response, checkpoint_summary: checkpointSummaryFromState(state) }
4337
4490
  }
4338
4491
  };
4339
4492
  }
@@ -4344,6 +4497,7 @@ function checkpointResponseContinuation(state, value) {
4344
4497
  checkpoint: packet.checkpoint,
4345
4498
  message: "Checkpoint response does not match the pending checkpoint packet.",
4346
4499
  details: {
4500
+ stage: packet.stage,
4347
4501
  expected: { run_id: packet.run_id, checkpoint: packet.checkpoint },
4348
4502
  actual: { run_id: response.run_id, checkpoint: response.checkpoint }
4349
4503
  }
@@ -4356,7 +4510,11 @@ function checkpointResponseContinuation(state, value) {
4356
4510
  code: "checkpoint_response_resume_token_mismatch",
4357
4511
  checkpoint: packet.checkpoint,
4358
4512
  message: "Checkpoint response resume_token does not match the pending checkpoint packet.",
4359
- details: { expected_resume_token: packet.resume_token, actual_resume_token: response.resume_token || null }
4513
+ details: {
4514
+ stage: packet.stage,
4515
+ expected_resume_token: packet.resume_token,
4516
+ actual_resume_token: response.resume_token || null
4517
+ }
4360
4518
  }
4361
4519
  };
4362
4520
  }
@@ -4373,10 +4531,11 @@ function checkpointResponseContinuation(state, value) {
4373
4531
  code: "checkpoint_author_packet_missing",
4374
4532
  checkpoint: packet.checkpoint,
4375
4533
  message: "Checkpoint response decision=author_packet did not include a proof_plan and capture_script payload.",
4376
- details: { response }
4534
+ details: { stage: packet.stage, response }
4377
4535
  }
4378
4536
  };
4379
4537
  }
4538
+ state.proof_contract = proofContractFromAuthorCheckpointResponse(response, packet, payload);
4380
4539
  appendCheckpointResponse(state, response);
4381
4540
  return { next: { ...base, author_packet_json: jsonParam(payload) } };
4382
4541
  }
@@ -4390,7 +4549,7 @@ function checkpointResponseContinuation(state, value) {
4390
4549
  code: `checkpoint_response_${response.decision}`,
4391
4550
  checkpoint: packet.checkpoint,
4392
4551
  message: response.summary || `Checkpoint response stopped the run with decision=${response.decision}.`,
4393
- details: { response }
4552
+ details: { stage: packet.stage, response }
4394
4553
  }
4395
4554
  };
4396
4555
  }
@@ -5067,12 +5226,12 @@ function hashString(value) {
5067
5226
  if (!text) return void 0;
5068
5227
  return (0, import_node_crypto4.createHash)("sha256").update(text).digest("hex");
5069
5228
  }
5070
- function stableJson(value) {
5229
+ function stableJson2(value) {
5071
5230
  if (value === void 0) return "null";
5072
5231
  if (value === null || typeof value !== "object") return JSON.stringify(value);
5073
- if (Array.isArray(value)) return `[${value.map((item) => stableJson(item)).join(",")}]`;
5232
+ if (Array.isArray(value)) return `[${value.map((item) => stableJson2(item)).join(",")}]`;
5074
5233
  const record = value;
5075
- return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
5234
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
5076
5235
  }
5077
5236
  function withoutUndefined(record) {
5078
5237
  for (const key of Object.keys(record)) {
@@ -5098,7 +5257,7 @@ function visualSessionFingerprintBasis(input) {
5098
5257
  }
5099
5258
  function visualSessionFingerprint(input) {
5100
5259
  const basis = input.version === RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION ? input : visualSessionFingerprintBasis(input);
5101
- return (0, import_node_crypto4.createHash)("sha256").update(stableJson(basis)).digest("hex");
5260
+ return (0, import_node_crypto4.createHash)("sha256").update(stableJson2(basis)).digest("hex");
5102
5261
  }
5103
5262
  function buildVisualProofSession(input) {
5104
5263
  const basis = visualSessionFingerprintBasis(input);
@@ -5159,7 +5318,7 @@ function compareVisualProofSessionFingerprint(parent, input) {
5159
5318
  for (const key of keys) {
5160
5319
  const expectedValue = expectedRecord[key];
5161
5320
  const actualValue = actualRecord[key];
5162
- if (stableJson(expectedValue) !== stableJson(actualValue)) {
5321
+ if (stableJson2(expectedValue) !== stableJson2(actualValue)) {
5163
5322
  mismatches.push({ key, expected: expectedValue, actual: actualValue });
5164
5323
  }
5165
5324
  }
@@ -5541,6 +5700,8 @@ function parseJson(value) {
5541
5700
  authorPacketPayloadFromCheckpointResponse,
5542
5701
  buildAuthorCheckpointPacket,
5543
5702
  buildVisualProofSession,
5703
+ checkpointResponseIdentity,
5704
+ checkpointSummaryFromState,
5544
5705
  compactRecord,
5545
5706
  compareVisualProofSessionFingerprint,
5546
5707
  createCaptureDiagnostic,
@@ -5549,6 +5710,7 @@ function parseJson(value) {
5549
5710
  createRunState,
5550
5711
  createRunStatusSnapshot,
5551
5712
  extractPlayabilityEvidence,
5713
+ isDuplicateCheckpointResponse,
5552
5714
  isRiddleProofPlayabilityMode,
5553
5715
  isSuccessfulStatus,
5554
5716
  isTerminalStatus,
@@ -5559,12 +5721,14 @@ function parseJson(value) {
5559
5721
  normalizeRunParams,
5560
5722
  normalizeTerminalMetadata,
5561
5723
  parseVisualProofSession,
5724
+ proofContractFromAuthorCheckpointResponse,
5562
5725
  readRiddleProofRunStatus,
5563
5726
  recordValue,
5564
5727
  redactForProofDiagnostics,
5565
5728
  runRiddleProof,
5566
5729
  runRiddleProofEngineHarness,
5567
5730
  setRunStatus,
5731
+ statePathsForRunState,
5568
5732
  summarizeCaptureArtifacts,
5569
5733
  visualSessionFingerprint,
5570
5734
  visualSessionFingerprintBasis