@riddledc/riddle-proof 0.5.40 → 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.
@@ -34,6 +34,7 @@ __export(checkpoint_exports, {
34
34
  RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION: () => RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
35
35
  authorPacketPayloadFromCheckpointResponse: () => authorPacketPayloadFromCheckpointResponse,
36
36
  buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
37
+ checkpointResponseIdentity: () => checkpointResponseIdentity,
37
38
  checkpointSummaryFromState: () => checkpointSummaryFromState,
38
39
  isDuplicateCheckpointResponse: () => isDuplicateCheckpointResponse,
39
40
  normalizeCheckpointResponse: () => normalizeCheckpointResponse,
@@ -77,6 +78,14 @@ function jsonCloneValue(value) {
77
78
  return value;
78
79
  }
79
80
  }
81
+ function stableJson(value) {
82
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
83
+ const record = recordValue(value);
84
+ if (record) {
85
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
86
+ }
87
+ return JSON.stringify(value);
88
+ }
80
89
  function compactText(value, limit = 1600) {
81
90
  const text = nonEmptyString(value);
82
91
  if (!text) return void 0;
@@ -234,6 +243,7 @@ function checkpointSummaryFromState(state, engineStatePath) {
234
243
  const history = state.checkpoint_history || [];
235
244
  const packets = history.filter((entry) => entry.packet);
236
245
  const responses = history.filter((entry) => entry.response);
246
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
237
247
  const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
238
248
  const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
239
249
  const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
@@ -245,6 +255,7 @@ function checkpointSummaryFromState(state, engineStatePath) {
245
255
  pending: Boolean(state.checkpoint_packet),
246
256
  packet_count: packets.length,
247
257
  response_count: responses.length,
258
+ duplicate_response_count: duplicateResponses.length,
248
259
  latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
249
260
  latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
250
261
  latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
@@ -260,9 +271,22 @@ function checkpointSummaryFromState(state, engineStatePath) {
260
271
  });
261
272
  }
262
273
  function isDuplicateCheckpointResponse(state, response) {
263
- const latestResponse = [...state.checkpoint_history || []].reverse().find((entry) => entry.response)?.response;
264
- if (!latestResponse) return false;
265
- return latestResponse.run_id === response.run_id && latestResponse.checkpoint === response.checkpoint && latestResponse.resume_token === response.resume_token && latestResponse.decision === response.decision;
274
+ const identity = checkpointResponseIdentity(response);
275
+ return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
276
+ }
277
+ function checkpointResponseIdentity(response) {
278
+ const logicalResponse = compactRecord({
279
+ run_id: response.run_id,
280
+ checkpoint: response.checkpoint,
281
+ resume_token: response.resume_token,
282
+ decision: response.decision,
283
+ summary: response.summary,
284
+ payload: response.payload,
285
+ reasons: response.reasons,
286
+ continue_with_stage: response.continue_with_stage,
287
+ source: response.source
288
+ });
289
+ return import_node_crypto.default.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
266
290
  }
267
291
  function authorPacketPayloadFromCheckpointResponse(response) {
268
292
  if (response.decision !== "author_packet") return null;
@@ -310,6 +334,7 @@ function proofContractFromAuthorCheckpointResponse(response, packet, payload) {
310
334
  RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
311
335
  authorPacketPayloadFromCheckpointResponse,
312
336
  buildAuthorCheckpointPacket,
337
+ checkpointResponseIdentity,
313
338
  checkpointSummaryFromState,
314
339
  isDuplicateCheckpointResponse,
315
340
  normalizeCheckpointResponse,
@@ -20,7 +20,8 @@ declare function buildAuthorCheckpointPacket(input: {
20
20
  declare function normalizeCheckpointResponse(value: unknown): RiddleProofCheckpointResponse | null;
21
21
  declare function checkpointSummaryFromState(state: RiddleProofRunState, engineStatePath?: string | null): RiddleProofCheckpointSummary;
22
22
  declare function isDuplicateCheckpointResponse(state: RiddleProofRunState, response: RiddleProofCheckpointResponse): boolean;
23
+ declare function checkpointResponseIdentity(response: RiddleProofCheckpointResponse): string;
23
24
  declare function authorPacketPayloadFromCheckpointResponse(response: RiddleProofCheckpointResponse): Record<string, unknown> | null;
24
25
  declare function proofContractFromAuthorCheckpointResponse(response: RiddleProofCheckpointResponse, packet: RiddleProofCheckpointPacket, payload: Record<string, unknown>): RiddleProofProofContract;
25
26
 
26
- export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState };
27
+ export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointResponseIdentity, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState };
@@ -20,7 +20,8 @@ declare function buildAuthorCheckpointPacket(input: {
20
20
  declare function normalizeCheckpointResponse(value: unknown): RiddleProofCheckpointResponse | null;
21
21
  declare function checkpointSummaryFromState(state: RiddleProofRunState, engineStatePath?: string | null): RiddleProofCheckpointSummary;
22
22
  declare function isDuplicateCheckpointResponse(state: RiddleProofRunState, response: RiddleProofCheckpointResponse): boolean;
23
+ declare function checkpointResponseIdentity(response: RiddleProofCheckpointResponse): string;
23
24
  declare function authorPacketPayloadFromCheckpointResponse(response: RiddleProofCheckpointResponse): Record<string, unknown> | null;
24
25
  declare function proofContractFromAuthorCheckpointResponse(response: RiddleProofCheckpointResponse, packet: RiddleProofCheckpointPacket, payload: Record<string, unknown>): RiddleProofProofContract;
25
26
 
26
- export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState };
27
+ export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointResponseIdentity, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState };
@@ -3,18 +3,20 @@ import {
3
3
  RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
4
4
  authorPacketPayloadFromCheckpointResponse,
5
5
  buildAuthorCheckpointPacket,
6
+ checkpointResponseIdentity,
6
7
  checkpointSummaryFromState,
7
8
  isDuplicateCheckpointResponse,
8
9
  normalizeCheckpointResponse,
9
10
  proofContractFromAuthorCheckpointResponse,
10
11
  statePathsForRunState
11
- } from "./chunk-5LVCGDSD.js";
12
+ } from "./chunk-RI25RGQP.js";
12
13
  import "./chunk-W7VTDN4T.js";
13
14
  export {
14
15
  RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
15
16
  RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
16
17
  authorPacketPayloadFromCheckpointResponse,
17
18
  buildAuthorCheckpointPacket,
19
+ checkpointResponseIdentity,
18
20
  checkpointSummaryFromState,
19
21
  isDuplicateCheckpointResponse,
20
22
  normalizeCheckpointResponse,
@@ -28,6 +28,14 @@ function jsonCloneValue(value) {
28
28
  return value;
29
29
  }
30
30
  }
31
+ function stableJson(value) {
32
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
33
+ const record = recordValue(value);
34
+ if (record) {
35
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
36
+ }
37
+ return JSON.stringify(value);
38
+ }
31
39
  function compactText(value, limit = 1600) {
32
40
  const text = nonEmptyString(value);
33
41
  if (!text) return void 0;
@@ -185,6 +193,7 @@ function checkpointSummaryFromState(state, engineStatePath) {
185
193
  const history = state.checkpoint_history || [];
186
194
  const packets = history.filter((entry) => entry.packet);
187
195
  const responses = history.filter((entry) => entry.response);
196
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
188
197
  const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
189
198
  const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
190
199
  const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
@@ -196,6 +205,7 @@ function checkpointSummaryFromState(state, engineStatePath) {
196
205
  pending: Boolean(state.checkpoint_packet),
197
206
  packet_count: packets.length,
198
207
  response_count: responses.length,
208
+ duplicate_response_count: duplicateResponses.length,
199
209
  latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
200
210
  latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
201
211
  latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
@@ -211,9 +221,22 @@ function checkpointSummaryFromState(state, engineStatePath) {
211
221
  });
212
222
  }
213
223
  function isDuplicateCheckpointResponse(state, response) {
214
- const latestResponse = [...state.checkpoint_history || []].reverse().find((entry) => entry.response)?.response;
215
- if (!latestResponse) return false;
216
- return latestResponse.run_id === response.run_id && latestResponse.checkpoint === response.checkpoint && latestResponse.resume_token === response.resume_token && latestResponse.decision === response.decision;
224
+ const identity = checkpointResponseIdentity(response);
225
+ return (state.checkpoint_history || []).some((entry) => entry.response ? checkpointResponseIdentity(entry.response) === identity : false);
226
+ }
227
+ function checkpointResponseIdentity(response) {
228
+ const logicalResponse = compactRecord({
229
+ run_id: response.run_id,
230
+ checkpoint: response.checkpoint,
231
+ resume_token: response.resume_token,
232
+ decision: response.decision,
233
+ summary: response.summary,
234
+ payload: response.payload,
235
+ reasons: response.reasons,
236
+ continue_with_stage: response.continue_with_stage,
237
+ source: response.source
238
+ });
239
+ return crypto.createHash("sha256").update(stableJson(logicalResponse)).digest("hex").slice(0, 24);
217
240
  }
218
241
  function authorPacketPayloadFromCheckpointResponse(response) {
219
242
  if (response.decision !== "author_packet") return null;
@@ -264,6 +287,7 @@ export {
264
287
  normalizeCheckpointResponse,
265
288
  checkpointSummaryFromState,
266
289
  isDuplicateCheckpointResponse,
290
+ checkpointResponseIdentity,
267
291
  authorPacketPayloadFromCheckpointResponse,
268
292
  proofContractFromAuthorCheckpointResponse
269
293
  };
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  authorPacketPayloadFromCheckpointResponse,
3
3
  buildAuthorCheckpointPacket,
4
+ checkpointResponseIdentity,
4
5
  checkpointSummaryFromState,
5
6
  isDuplicateCheckpointResponse,
6
7
  normalizeCheckpointResponse,
7
8
  proofContractFromAuthorCheckpointResponse,
8
9
  statePathsForRunState
9
- } from "./chunk-5LVCGDSD.js";
10
+ } from "./chunk-RI25RGQP.js";
10
11
  import {
11
12
  appendRunEvent,
12
13
  appendStageHeartbeat,
@@ -497,20 +498,35 @@ function checkpointResponseContinuation(state, value) {
497
498
  }
498
499
  };
499
500
  }
500
- if (!packet) {
501
- if (isDuplicateCheckpointResponse(state, response)) {
502
- return {
503
- blocker: {
504
- code: "checkpoint_response_duplicate",
505
- checkpoint: response.checkpoint,
506
- message: "Checkpoint response was already accepted and there is no pending checkpoint packet to resume.",
507
- details: {
508
- response,
509
- checkpoint_summary: checkpointSummaryFromState(state)
510
- }
501
+ if (isDuplicateCheckpointResponse(state, response)) {
502
+ const stage = packet?.stage || state.current_stage || "author";
503
+ recordEvent(state, {
504
+ kind: "checkpoint.response.duplicate",
505
+ checkpoint: response.checkpoint,
506
+ stage,
507
+ summary: "Duplicate checkpoint response ignored.",
508
+ details: compactRecord({
509
+ decision: response.decision,
510
+ resume_token: response.resume_token,
511
+ response_identity: checkpointResponseIdentity(response)
512
+ })
513
+ });
514
+ return {
515
+ blocker: {
516
+ code: "checkpoint_response_duplicate",
517
+ checkpoint: response.checkpoint,
518
+ message: "Checkpoint response was already accepted for this run/checkpoint/resume token and was not applied again.",
519
+ details: {
520
+ stage,
521
+ duplicate: true,
522
+ response,
523
+ response_identity: checkpointResponseIdentity(response),
524
+ checkpoint_summary: checkpointSummaryFromState(state)
511
525
  }
512
- };
513
- }
526
+ }
527
+ };
528
+ }
529
+ if (!packet) {
514
530
  return {
515
531
  blocker: {
516
532
  code: "checkpoint_response_without_packet",
@@ -3163,6 +3163,14 @@ function jsonCloneValue(value) {
3163
3163
  return value;
3164
3164
  }
3165
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
+ }
3166
3174
  function compactText(value, limit = 1600) {
3167
3175
  const text = nonEmptyString(value);
3168
3176
  if (!text) return void 0;
@@ -3320,6 +3328,7 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3320
3328
  const history = state.checkpoint_history || [];
3321
3329
  const packets = history.filter((entry) => entry.packet);
3322
3330
  const responses = history.filter((entry) => entry.response);
3331
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3323
3332
  const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3324
3333
  const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3325
3334
  const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
@@ -3331,6 +3340,7 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3331
3340
  pending: Boolean(state.checkpoint_packet),
3332
3341
  packet_count: packets.length,
3333
3342
  response_count: responses.length,
3343
+ duplicate_response_count: duplicateResponses.length,
3334
3344
  latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3335
3345
  latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3336
3346
  latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
@@ -3346,9 +3356,22 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3346
3356
  });
3347
3357
  }
3348
3358
  function isDuplicateCheckpointResponse(state, response) {
3349
- const latestResponse = [...state.checkpoint_history || []].reverse().find((entry) => entry.response)?.response;
3350
- if (!latestResponse) return false;
3351
- return latestResponse.run_id === response.run_id && latestResponse.checkpoint === response.checkpoint && latestResponse.resume_token === response.resume_token && latestResponse.decision === response.decision;
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);
3352
3375
  }
3353
3376
  function authorPacketPayloadFromCheckpointResponse(response) {
3354
3377
  if (response.decision !== "author_packet") return null;
@@ -3851,20 +3874,35 @@ function checkpointResponseContinuation(state, value) {
3851
3874
  }
3852
3875
  };
3853
3876
  }
3854
- if (!packet) {
3855
- if (isDuplicateCheckpointResponse(state, response)) {
3856
- return {
3857
- blocker: {
3858
- code: "checkpoint_response_duplicate",
3859
- checkpoint: response.checkpoint,
3860
- message: "Checkpoint response was already accepted and there is no pending checkpoint packet to resume.",
3861
- details: {
3862
- response,
3863
- checkpoint_summary: checkpointSummaryFromState(state)
3864
- }
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)
3865
3901
  }
3866
- };
3867
- }
3902
+ }
3903
+ };
3904
+ }
3905
+ if (!packet) {
3868
3906
  return {
3869
3907
  blocker: {
3870
3908
  code: "checkpoint_response_without_packet",
@@ -2,8 +2,8 @@ import {
2
2
  createDisabledRiddleProofAgentAdapter,
3
3
  readRiddleProofRunStatus,
4
4
  runRiddleProofEngineHarness
5
- } from "./chunk-COFOLRUW.js";
6
- import "./chunk-5LVCGDSD.js";
5
+ } from "./chunk-ZBM67XGB.js";
6
+ import "./chunk-RI25RGQP.js";
7
7
  import "./chunk-7S7O3NKF.js";
8
8
  import "./chunk-W7VTDN4T.js";
9
9
  import "./chunk-4YCWZVBN.js";
package/dist/index.cjs CHANGED
@@ -2751,6 +2751,7 @@ __export(index_exports, {
2751
2751
  authorPacketPayloadFromCheckpointResponse: () => authorPacketPayloadFromCheckpointResponse,
2752
2752
  buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
2753
2753
  buildVisualProofSession: () => buildVisualProofSession,
2754
+ checkpointResponseIdentity: () => checkpointResponseIdentity,
2754
2755
  checkpointSummaryFromState: () => checkpointSummaryFromState,
2755
2756
  compactRecord: () => compactRecord,
2756
2757
  compareVisualProofSessionFingerprint: () => compareVisualProofSessionFingerprint,
@@ -3254,6 +3255,14 @@ function jsonCloneValue(value) {
3254
3255
  return value;
3255
3256
  }
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
+ }
3257
3266
  function compactText(value, limit = 1600) {
3258
3267
  const text = nonEmptyString(value);
3259
3268
  if (!text) return void 0;
@@ -3411,6 +3420,7 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3411
3420
  const history = state.checkpoint_history || [];
3412
3421
  const packets = history.filter((entry) => entry.packet);
3413
3422
  const responses = history.filter((entry) => entry.response);
3423
+ const duplicateResponses = (state.events || []).filter((event) => event.kind === "checkpoint.response.duplicate");
3414
3424
  const latestPacketEntry = [...history].reverse().find((entry) => entry.packet);
3415
3425
  const latestResponseEntry = [...history].reverse().find((entry) => entry.response);
3416
3426
  const latestPacket = state.checkpoint_packet || latestPacketEntry?.packet;
@@ -3422,6 +3432,7 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3422
3432
  pending: Boolean(state.checkpoint_packet),
3423
3433
  packet_count: packets.length,
3424
3434
  response_count: responses.length,
3435
+ duplicate_response_count: duplicateResponses.length,
3425
3436
  latest_checkpoint: state.checkpoint_packet?.checkpoint || latestResponse?.checkpoint || state.last_checkpoint || null,
3426
3437
  latest_stage: state.checkpoint_packet?.stage || latestResponse?.continue_with_stage || state.current_stage || null,
3427
3438
  latest_kind: state.checkpoint_packet?.kind || latestPacket?.kind || null,
@@ -3437,9 +3448,22 @@ function checkpointSummaryFromState(state, engineStatePath2) {
3437
3448
  });
3438
3449
  }
3439
3450
  function isDuplicateCheckpointResponse(state, response) {
3440
- const latestResponse = [...state.checkpoint_history || []].reverse().find((entry) => entry.response)?.response;
3441
- if (!latestResponse) return false;
3442
- return latestResponse.run_id === response.run_id && latestResponse.checkpoint === response.checkpoint && latestResponse.resume_token === response.resume_token && latestResponse.decision === response.decision;
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);
3443
3467
  }
3444
3468
  function authorPacketPayloadFromCheckpointResponse(response) {
3445
3469
  if (response.decision !== "author_packet") return null;
@@ -4428,20 +4452,35 @@ function checkpointResponseContinuation(state, value) {
4428
4452
  }
4429
4453
  };
4430
4454
  }
4431
- if (!packet) {
4432
- if (isDuplicateCheckpointResponse(state, response)) {
4433
- return {
4434
- blocker: {
4435
- code: "checkpoint_response_duplicate",
4436
- checkpoint: response.checkpoint,
4437
- message: "Checkpoint response was already accepted and there is no pending checkpoint packet to resume.",
4438
- details: {
4439
- response,
4440
- checkpoint_summary: checkpointSummaryFromState(state)
4441
- }
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)
4442
4479
  }
4443
- };
4444
- }
4480
+ }
4481
+ };
4482
+ }
4483
+ if (!packet) {
4445
4484
  return {
4446
4485
  blocker: {
4447
4486
  code: "checkpoint_response_without_packet",
@@ -5187,12 +5226,12 @@ function hashString(value) {
5187
5226
  if (!text) return void 0;
5188
5227
  return (0, import_node_crypto4.createHash)("sha256").update(text).digest("hex");
5189
5228
  }
5190
- function stableJson(value) {
5229
+ function stableJson2(value) {
5191
5230
  if (value === void 0) return "null";
5192
5231
  if (value === null || typeof value !== "object") return JSON.stringify(value);
5193
- if (Array.isArray(value)) return `[${value.map((item) => stableJson(item)).join(",")}]`;
5232
+ if (Array.isArray(value)) return `[${value.map((item) => stableJson2(item)).join(",")}]`;
5194
5233
  const record = value;
5195
- 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(",")}}`;
5196
5235
  }
5197
5236
  function withoutUndefined(record) {
5198
5237
  for (const key of Object.keys(record)) {
@@ -5218,7 +5257,7 @@ function visualSessionFingerprintBasis(input) {
5218
5257
  }
5219
5258
  function visualSessionFingerprint(input) {
5220
5259
  const basis = input.version === RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION ? input : visualSessionFingerprintBasis(input);
5221
- 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");
5222
5261
  }
5223
5262
  function buildVisualProofSession(input) {
5224
5263
  const basis = visualSessionFingerprintBasis(input);
@@ -5279,7 +5318,7 @@ function compareVisualProofSessionFingerprint(parent, input) {
5279
5318
  for (const key of keys) {
5280
5319
  const expectedValue = expectedRecord[key];
5281
5320
  const actualValue = actualRecord[key];
5282
- if (stableJson(expectedValue) !== stableJson(actualValue)) {
5321
+ if (stableJson2(expectedValue) !== stableJson2(actualValue)) {
5283
5322
  mismatches.push({ key, expected: expectedValue, actual: actualValue });
5284
5323
  }
5285
5324
  }
@@ -5661,6 +5700,7 @@ function parseJson(value) {
5661
5700
  authorPacketPayloadFromCheckpointResponse,
5662
5701
  buildAuthorCheckpointPacket,
5663
5702
  buildVisualProofSession,
5703
+ checkpointResponseIdentity,
5664
5704
  checkpointSummaryFromState,
5665
5705
  compactRecord,
5666
5706
  compareVisualProofSessionFingerprint,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { EvidenceArtifact, EvidenceReference, ImplementationAdapter, ImplementationAdapterInput, ImplementationAdapterResult, IntegrationContext, JsonObject, JsonPrimitive, JsonValue, JudgeAdapter, NotificationAdapter, PreflightAdapter, PreflightAdapterInput, PreflightAdapterResult, ProofAdapter, ProofAdapterInput, ProofAdapterResult, RiddleProofArtifactRole, RiddleProofAssessment, RiddleProofBlocker, RiddleProofCheckpointArtifact, RiddleProofCheckpointPacket, RiddleProofCheckpointResponse, RiddleProofCheckpointRole, RiddleProofCheckpointRoutingHint, RiddleProofCheckpointSummary, RiddleProofCheckpointVisibility, RiddleProofDecision, RiddleProofEvent, RiddleProofEvidenceBundle, RiddleProofPrLifecycleState, RiddleProofPrLifecycleStatus, RiddleProofProofContract, RiddleProofRunParams, RiddleProofRunResult, RiddleProofRunState, RiddleProofRunStatusSnapshot, RiddleProofStage, RiddleProofStatePaths, RiddleProofStatus, RiddleProofTerminalMetadata, RiddleProofVerificationMode, RiddleProofVisualSession, RiddleProofVisualSessionFingerprintBasis, SetupAdapter, SetupAdapterInput, SetupAdapterResult, ShipAdapter } from './types.cjs';
2
2
  export { TerminalMetadataInput, applyTerminalMetadata, compactRecord, createRunResult, isSuccessfulStatus, isTerminalStatus, nonEmptyString, normalizeTerminalMetadata, recordValue } from './result.cjs';
3
3
  export { CreateRunStateInput, RIDDLE_PROOF_RUN_STATE_VERSION, RunEventInput, appendRunEvent, appendStageHeartbeat, applyPrLifecycleState, createRunState, createRunStatusSnapshot, normalizeIntegrationContext, normalizePrLifecycleState, normalizeRunParams, setRunStatus } from './state.cjs';
4
- export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState } from './checkpoint.cjs';
4
+ export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointResponseIdentity, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState } from './checkpoint.cjs';
5
5
  export { RiddleProofRunnerAdapters, RunRiddleProofInput, runRiddleProof } from './runner.cjs';
6
6
  export { RiddleProofAgentAdapter, RiddleProofAgentPayload, RiddleProofCheckpointMode, RiddleProofEngine, RiddleProofEngineHarnessConfig, RiddleProofEngineHarnessContext, RiddleProofEngineResult, RiddleProofShipMode, RiddleProofWorkflowParams, RunRiddleProofEngineHarnessInput, createDisabledRiddleProofAgentAdapter, readRiddleProofRunStatus, runRiddleProofEngineHarness } from './engine-harness.cjs';
7
7
  export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_DIAGNOSTIC_HISTORY_LIMIT, DEFAULT_DIAGNOSTIC_STRING_LIMIT, RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION, RiddleProofArtifactSummary, RiddleProofCaptureArtifactSummary, RiddleProofCaptureDiagnostic, RiddleProofDiagnosticRedactionOptions, appendCaptureDiagnostic, createCaptureDiagnostic, redactForProofDiagnostics, summarizeCaptureArtifacts } from './diagnostics.cjs';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { EvidenceArtifact, EvidenceReference, ImplementationAdapter, ImplementationAdapterInput, ImplementationAdapterResult, IntegrationContext, JsonObject, JsonPrimitive, JsonValue, JudgeAdapter, NotificationAdapter, PreflightAdapter, PreflightAdapterInput, PreflightAdapterResult, ProofAdapter, ProofAdapterInput, ProofAdapterResult, RiddleProofArtifactRole, RiddleProofAssessment, RiddleProofBlocker, RiddleProofCheckpointArtifact, RiddleProofCheckpointPacket, RiddleProofCheckpointResponse, RiddleProofCheckpointRole, RiddleProofCheckpointRoutingHint, RiddleProofCheckpointSummary, RiddleProofCheckpointVisibility, RiddleProofDecision, RiddleProofEvent, RiddleProofEvidenceBundle, RiddleProofPrLifecycleState, RiddleProofPrLifecycleStatus, RiddleProofProofContract, RiddleProofRunParams, RiddleProofRunResult, RiddleProofRunState, RiddleProofRunStatusSnapshot, RiddleProofStage, RiddleProofStatePaths, RiddleProofStatus, RiddleProofTerminalMetadata, RiddleProofVerificationMode, RiddleProofVisualSession, RiddleProofVisualSessionFingerprintBasis, SetupAdapter, SetupAdapterInput, SetupAdapterResult, ShipAdapter } from './types.js';
2
2
  export { TerminalMetadataInput, applyTerminalMetadata, compactRecord, createRunResult, isSuccessfulStatus, isTerminalStatus, nonEmptyString, normalizeTerminalMetadata, recordValue } from './result.js';
3
3
  export { CreateRunStateInput, RIDDLE_PROOF_RUN_STATE_VERSION, RunEventInput, appendRunEvent, appendStageHeartbeat, applyPrLifecycleState, createRunState, createRunStatusSnapshot, normalizeIntegrationContext, normalizePrLifecycleState, normalizeRunParams, setRunStatus } from './state.js';
4
- export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState } from './checkpoint.js';
4
+ export { RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION, RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION, authorPacketPayloadFromCheckpointResponse, buildAuthorCheckpointPacket, checkpointResponseIdentity, checkpointSummaryFromState, isDuplicateCheckpointResponse, normalizeCheckpointResponse, proofContractFromAuthorCheckpointResponse, statePathsForRunState } from './checkpoint.js';
5
5
  export { RiddleProofRunnerAdapters, RunRiddleProofInput, runRiddleProof } from './runner.js';
6
6
  export { RiddleProofAgentAdapter, RiddleProofAgentPayload, RiddleProofCheckpointMode, RiddleProofEngine, RiddleProofEngineHarnessConfig, RiddleProofEngineHarnessContext, RiddleProofEngineResult, RiddleProofShipMode, RiddleProofWorkflowParams, RunRiddleProofEngineHarnessInput, createDisabledRiddleProofAgentAdapter, readRiddleProofRunStatus, runRiddleProofEngineHarness } from './engine-harness.js';
7
7
  export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_DIAGNOSTIC_HISTORY_LIMIT, DEFAULT_DIAGNOSTIC_STRING_LIMIT, RIDDLE_PROOF_CAPTURE_DIAGNOSTIC_VERSION, RiddleProofArtifactSummary, RiddleProofCaptureArtifactSummary, RiddleProofCaptureDiagnostic, RiddleProofDiagnosticRedactionOptions, appendCaptureDiagnostic, createCaptureDiagnostic, redactForProofDiagnostics, summarizeCaptureArtifacts } from './diagnostics.js';
package/dist/index.js CHANGED
@@ -25,18 +25,19 @@ import {
25
25
  createDisabledRiddleProofAgentAdapter,
26
26
  readRiddleProofRunStatus,
27
27
  runRiddleProofEngineHarness
28
- } from "./chunk-COFOLRUW.js";
28
+ } from "./chunk-ZBM67XGB.js";
29
29
  import {
30
30
  RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
31
31
  RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
32
32
  authorPacketPayloadFromCheckpointResponse,
33
33
  buildAuthorCheckpointPacket,
34
+ checkpointResponseIdentity,
34
35
  checkpointSummaryFromState,
35
36
  isDuplicateCheckpointResponse,
36
37
  normalizeCheckpointResponse,
37
38
  proofContractFromAuthorCheckpointResponse,
38
39
  statePathsForRunState
39
- } from "./chunk-5LVCGDSD.js";
40
+ } from "./chunk-RI25RGQP.js";
40
41
  import {
41
42
  RIDDLE_PROOF_RUN_STATE_VERSION,
42
43
  appendRunEvent,
@@ -88,6 +89,7 @@ export {
88
89
  authorPacketPayloadFromCheckpointResponse,
89
90
  buildAuthorCheckpointPacket,
90
91
  buildVisualProofSession,
92
+ checkpointResponseIdentity,
91
93
  checkpointSummaryFromState,
92
94
  compactRecord,
93
95
  compareVisualProofSessionFingerprint,
package/dist/types.d.cts CHANGED
@@ -114,6 +114,7 @@ interface RiddleProofCheckpointSummary {
114
114
  pending: boolean;
115
115
  packet_count: number;
116
116
  response_count: number;
117
+ duplicate_response_count?: number;
117
118
  latest_checkpoint?: string | null;
118
119
  latest_stage?: RiddleProofStage | null;
119
120
  latest_kind?: string | null;
package/dist/types.d.ts CHANGED
@@ -114,6 +114,7 @@ interface RiddleProofCheckpointSummary {
114
114
  pending: boolean;
115
115
  packet_count: number;
116
116
  response_count: number;
117
+ duplicate_response_count?: number;
117
118
  latest_checkpoint?: string | null;
118
119
  latest_stage?: RiddleProofStage | null;
119
120
  latest_kind?: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.5.40",
3
+ "version": "0.5.41",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",