@riddledc/riddle-proof 0.5.31 → 0.5.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -340,6 +340,44 @@ function normalizedProofAssessment(state = {}) {
340
340
  source: source || null
341
341
  };
342
342
  }
343
+ function objectValue(value) {
344
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
345
+ }
346
+ function normalizedVerificationMode(state = {}) {
347
+ const bundle = objectValue(state?.evidence_bundle);
348
+ const bundleMode = String(bundle.verification_mode || "").trim().toLowerCase();
349
+ if (bundleMode) return bundleMode;
350
+ return String(state?.verification_mode || "proof").trim().toLowerCase() || "proof";
351
+ }
352
+ function visualDeltaRequiredForState(state = {}) {
353
+ const bundle = objectValue(state?.evidence_bundle);
354
+ const contract = objectValue(bundle.artifact_contract);
355
+ const required = objectValue(contract.required);
356
+ return required.visual_delta === true || VISUAL_FIRST_MODES.has(normalizedVerificationMode(state));
357
+ }
358
+ function visualDeltaForState(state = {}) {
359
+ const bundle = objectValue(state?.evidence_bundle);
360
+ const after = objectValue(bundle.after);
361
+ const afterDelta = objectValue(after.visual_delta);
362
+ if (Object.keys(afterDelta).length) return afterDelta;
363
+ const request = objectValue(state?.proof_assessment_request);
364
+ return objectValue(request.visual_delta);
365
+ }
366
+ function visualDeltaShipGateReason(state = {}) {
367
+ if (!visualDeltaRequiredForState(state)) return null;
368
+ const visualDelta = visualDeltaForState(state);
369
+ if (visualDelta.status === "measured" && visualDelta.passed === true) return null;
370
+ const status = String(visualDelta.status || "missing");
371
+ if (status === "unmeasured") {
372
+ return "visual_delta.status=unmeasured blocks ready_to_ship for visual/UI proof";
373
+ }
374
+ if (status === "measured" && visualDelta.passed === false) {
375
+ return "visual_delta.status=measured but visual_delta.passed=false blocks ready_to_ship for visual/UI proof";
376
+ }
377
+ const reason = String(visualDelta.reason || "").trim();
378
+ if (reason) return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof: ${reason}`;
379
+ return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof`;
380
+ }
343
381
  function requiredBaselineLabelsForState(state = {}) {
344
382
  const reference = normalizedReference(state);
345
383
  const labels = [];
@@ -355,6 +393,10 @@ function validateShipGate(state = {}) {
355
393
  const afterCdn = String(state?.after_cdn || "").trim();
356
394
  const verifyStatus = String(state?.verify_status || "").trim();
357
395
  const proofAssessment = normalizedProofAssessment(state);
396
+ const verificationMode = normalizedVerificationMode(state);
397
+ const visualDelta = visualDeltaForState(state);
398
+ const visualDeltaRequired = visualDeltaRequiredForState(state);
399
+ const visualDeltaBlocker = visualDeltaShipGateReason(state);
358
400
  const reasons = [];
359
401
  if (!["before", "prod", "both"].includes(reference)) {
360
402
  reasons.push(`reference must be before, prod, or both; got ${reference}`);
@@ -383,19 +425,26 @@ function validateShipGate(state = {}) {
383
425
  if (proofAssessment.decision !== "ready_to_ship") {
384
426
  reasons.push("proof_assessment.decision must be ready_to_ship before ship");
385
427
  }
428
+ if (visualDeltaBlocker) {
429
+ reasons.push(visualDeltaBlocker);
430
+ }
386
431
  return {
387
432
  ok: reasons.length === 0,
388
433
  reasons,
389
434
  required_baselines: requiredBaselines,
390
435
  evidence: {
391
436
  reference,
437
+ verification_mode: verificationMode || null,
392
438
  prod_url: prodUrl || null,
393
439
  before_cdn: beforeCdn || null,
394
440
  prod_cdn: prodCdn || null,
395
441
  after_cdn: afterCdn || null,
396
442
  verify_status: verifyStatus || null,
397
443
  proof_assessment_decision: proofAssessment.decision,
398
- proof_assessment_source: proofAssessment.source
444
+ proof_assessment_source: proofAssessment.source,
445
+ visual_delta_required: visualDeltaRequired,
446
+ visual_delta_status: typeof visualDelta.status === "string" ? visualDelta.status : null,
447
+ visual_delta_passed: typeof visualDelta.passed === "boolean" ? visualDelta.passed : null
399
448
  }
400
449
  };
401
450
  }
@@ -541,23 +590,36 @@ function mergeStateFromParams(statePath, params) {
541
590
  state.proof_assessment_source = null;
542
591
  } else {
543
592
  const parsed = JSON.parse(raw);
544
- state.proof_assessment = {
593
+ const assessment = {
545
594
  ...parsed,
546
595
  source: (parsed?.source || "supervising_agent").toString()
547
596
  };
597
+ const readyBlocker = assessment?.decision === "ready_to_ship" ? visualDeltaShipGateReason({ ...state, proof_assessment: assessment, proof_assessment_source: assessment.source }) : null;
598
+ if (readyBlocker) {
599
+ assessment.blocked_decision = assessment.decision;
600
+ assessment.decision = "needs_richer_proof";
601
+ if (assessment.recommended_stage === "ship") assessment.recommended_stage = "verify";
602
+ if (assessment.continue_with_stage === "ship") assessment.continue_with_stage = "verify";
603
+ const blockers = Array.isArray(assessment.blockers) ? assessment.blockers : [];
604
+ assessment.blockers = [...blockers, readyBlocker];
605
+ }
606
+ state.proof_assessment = assessment;
548
607
  state.proof_assessment_source = state.proof_assessment.source;
549
- if (typeof parsed?.decision === "string") {
550
- state.proof_decision = parsed.decision;
608
+ if (typeof state.proof_assessment?.decision === "string") {
609
+ state.proof_decision = state.proof_assessment.decision;
551
610
  }
552
611
  if (typeof parsed?.summary === "string") {
553
612
  state.proof_assessment_summary = normalizeOptionalString(parsed.summary) || null;
554
613
  }
555
- if (parsed?.decision === "ready_to_ship") {
614
+ if (state.proof_assessment?.decision === "ready_to_ship") {
556
615
  state.merge_recommendation = "ready-to-ship";
557
- } else if (typeof parsed?.decision === "string" && parsed.decision.trim()) {
616
+ } else if (typeof state.proof_assessment?.decision === "string" && state.proof_assessment.decision.trim()) {
558
617
  state.merge_recommendation = "do-not-merge";
559
618
  }
560
619
  appendProofSummaryLine(state, `Supervising proof assessment: ${state.proof_assessment.decision || "unknown"}`);
620
+ if (readyBlocker) {
621
+ appendProofSummaryLine(state, `Ready-to-ship assessment blocked: ${readyBlocker}`);
622
+ }
561
623
  if (state.proof_assessment_summary) {
562
624
  appendProofSummaryLine(state, `Assessment summary: ${state.proof_assessment_summary}`);
563
625
  }
@@ -679,7 +741,7 @@ function summarizeState(state) {
679
741
  state: selected
680
742
  };
681
743
  }
682
- var import_node_fs, import_node_crypto, import_node_path, import_node_url, import_meta, WORKFLOW_STAGE_ORDER, CHECKPOINT_CONTRACT_VERSION, BUNDLED_RIDDLE_PROOF_DIR, RIDDLE_PROOF_DIR_CANDIDATES, CHECKPOINT_CONTRACT_SPECS;
744
+ var import_node_fs, import_node_crypto, import_node_path, import_node_url, import_meta, WORKFLOW_STAGE_ORDER, CHECKPOINT_CONTRACT_VERSION, BUNDLED_RIDDLE_PROOF_DIR, RIDDLE_PROOF_DIR_CANDIDATES, VISUAL_FIRST_MODES, CHECKPOINT_CONTRACT_SPECS;
683
745
  var init_proof_run_core = __esm({
684
746
  "src/proof-run-core.ts"() {
685
747
  "use strict";
@@ -698,6 +760,16 @@ var init_proof_run_core = __esm({
698
760
  RIDDLE_PROOF_DIR_CANDIDATES = [
699
761
  BUNDLED_RIDDLE_PROOF_DIR
700
762
  ];
763
+ VISUAL_FIRST_MODES = /* @__PURE__ */ new Set([
764
+ "visual",
765
+ "render",
766
+ "interaction",
767
+ "ui",
768
+ "layout",
769
+ "screenshot",
770
+ "canvas",
771
+ "animation"
772
+ ]);
701
773
  CHECKPOINT_CONTRACT_SPECS = {
702
774
  setup_review: {
703
775
  purpose: "Inspect prepared workspace state before moving into recon."
@@ -1624,6 +1696,9 @@ async function executeWorkflow(params, pluginConfig, resolvedConfig) {
1624
1696
  if (reasons.some((reason) => reason.includes("proof_assessment"))) {
1625
1697
  return "resume with riddle_proof_review using decision=ready_to_ship only after the screenshots and semantic evidence visibly prove the request; otherwise choose needs_implementation or needs_richer_proof";
1626
1698
  }
1699
+ if (reasons.some((reason) => reason.includes("visual_delta"))) {
1700
+ return "rerun verify with a measured before/after visual delta, or choose needs_richer_proof instead of ready_to_ship for this visual proof";
1701
+ }
1627
1702
  if (reasons.some((reason) => reason.includes("after_cdn") || reason.includes("verify_status"))) {
1628
1703
  return "rerun verify with stronger proof framing so after evidence is captured before shipping";
1629
1704
  }
@@ -1716,7 +1791,7 @@ async function executeWorkflow(params, pluginConfig, resolvedConfig) {
1716
1791
  }
1717
1792
  state = readState(config.statePath);
1718
1793
  const continuedStage = params.continue_from_checkpoint ? checkpointContinueStage(state) : null;
1719
- if (params.continue_from_checkpoint && !continuedStage) {
1794
+ if (params.continue_from_checkpoint && !params.advance_stage && !continuedStage) {
1720
1795
  const recommended = recommendedAdvanceStage(state);
1721
1796
  return checkpoint(
1722
1797
  state?.active_checkpoint_stage || recommended || "recon",
@@ -3584,6 +3659,7 @@ var import_node_child_process2 = require("child_process");
3584
3659
  var import_node_fs3 = require("fs");
3585
3660
  var import_node_path3 = __toESM(require("path"), 1);
3586
3661
  var import_node_crypto2 = __toESM(require("crypto"), 1);
3662
+ init_proof_run_core();
3587
3663
  var DEFAULT_MAX_ITERATIONS = 12;
3588
3664
  var DEFAULT_STAGE_ITERATION_LIMITS = {
3589
3665
  setup: 2,
@@ -3848,6 +3924,26 @@ function proofAssessmentContinuation(result, payload) {
3848
3924
  const proof_assessment_json = jsonParam(payload);
3849
3925
  return { ...baseContinuation(result), proof_assessment_json };
3850
3926
  }
3927
+ function proofAssessmentVisualBlocker(state, payload) {
3928
+ if (!proofAssessmentRequestsShip(payload)) return null;
3929
+ const source = nonEmptyString(payload.source) || "supervising_agent";
3930
+ return visualDeltaShipGateReason({
3931
+ ...state || {},
3932
+ proof_assessment: { ...payload, source },
3933
+ proof_assessment_source: source
3934
+ });
3935
+ }
3936
+ function blockedProofAssessmentPayload(payload, blocker) {
3937
+ const blockers = Array.isArray(payload.blockers) ? payload.blockers.filter((item) => typeof item === "string") : [];
3938
+ return {
3939
+ ...payload,
3940
+ blocked_decision: payload.decision || "ready_to_ship",
3941
+ decision: "needs_richer_proof",
3942
+ recommended_stage: payload.recommended_stage === "ship" ? "verify" : payload.recommended_stage || "verify",
3943
+ continue_with_stage: payload.continue_with_stage === "ship" ? "verify" : payload.continue_with_stage || "verify",
3944
+ blockers: [...blockers, blocker]
3945
+ };
3946
+ }
3851
3947
  function contextFor(request, state, result) {
3852
3948
  return {
3853
3949
  request,
@@ -4081,7 +4177,8 @@ async function handleImplementation(request, state, result, agent) {
4081
4177
  });
4082
4178
  return {
4083
4179
  next: compactRecord({
4084
- ...baseContinuation(result),
4180
+ action: "run",
4181
+ state_path: String(result.state_path || ""),
4085
4182
  advance_stage: "implement",
4086
4183
  implementation_notes: implementation.implementationNotes || implementation.summary
4087
4184
  })
@@ -4216,6 +4313,20 @@ async function routeCheckpoint(request, state, result, agent, input) {
4216
4313
  summary: assessment.summary,
4217
4314
  details: { payload }
4218
4315
  });
4316
+ const visualBlocker = proofAssessmentVisualBlocker({
4317
+ ...context.fullRiddleState || {},
4318
+ verification_mode: context.fullRiddleState?.verification_mode || request.verification_mode
4319
+ }, payload);
4320
+ if (visualBlocker) {
4321
+ recordEvent(state, {
4322
+ kind: "agent.proof_assessment.blocked",
4323
+ checkpoint,
4324
+ stage: "verify",
4325
+ summary: visualBlocker,
4326
+ details: { payload }
4327
+ });
4328
+ return { next: proofAssessmentContinuation(result, blockedProofAssessmentPayload(payload, visualBlocker)) };
4329
+ }
4219
4330
  if (effectiveShipMode(request, input.config) !== "ship" && proofAssessmentRequestsShip(payload)) {
4220
4331
  return {
4221
4332
  terminal: terminalResult(
package/dist/index.js CHANGED
@@ -13,7 +13,8 @@ import {
13
13
  createDisabledRiddleProofAgentAdapter,
14
14
  readRiddleProofRunStatus,
15
15
  runRiddleProofEngineHarness
16
- } from "./chunk-A3H7GU7H.js";
16
+ } from "./chunk-CHKYSZLU.js";
17
+ import "./chunk-A5AWVY5A.js";
17
18
  import {
18
19
  runRiddleProof
19
20
  } from "./chunk-F6VFKS7K.js";
@@ -50,6 +50,9 @@ __export(proof_run_core_exports, {
50
50
  setStageDecisionRequest: () => setStageDecisionRequest,
51
51
  summarizeState: () => summarizeState,
52
52
  validateShipGate: () => validateShipGate,
53
+ visualDeltaForState: () => visualDeltaForState,
54
+ visualDeltaRequiredForState: () => visualDeltaRequiredForState,
55
+ visualDeltaShipGateReason: () => visualDeltaShipGateReason,
53
56
  workflowFile: () => workflowFile,
54
57
  writeState: () => writeState
55
58
  });
@@ -378,6 +381,54 @@ function normalizedProofAssessment(state = {}) {
378
381
  source: source || null
379
382
  };
380
383
  }
384
+ var VISUAL_FIRST_MODES = /* @__PURE__ */ new Set([
385
+ "visual",
386
+ "render",
387
+ "interaction",
388
+ "ui",
389
+ "layout",
390
+ "screenshot",
391
+ "canvas",
392
+ "animation"
393
+ ]);
394
+ function objectValue(value) {
395
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
396
+ }
397
+ function normalizedVerificationMode(state = {}) {
398
+ const bundle = objectValue(state?.evidence_bundle);
399
+ const bundleMode = String(bundle.verification_mode || "").trim().toLowerCase();
400
+ if (bundleMode) return bundleMode;
401
+ return String(state?.verification_mode || "proof").trim().toLowerCase() || "proof";
402
+ }
403
+ function visualDeltaRequiredForState(state = {}) {
404
+ const bundle = objectValue(state?.evidence_bundle);
405
+ const contract = objectValue(bundle.artifact_contract);
406
+ const required = objectValue(contract.required);
407
+ return required.visual_delta === true || VISUAL_FIRST_MODES.has(normalizedVerificationMode(state));
408
+ }
409
+ function visualDeltaForState(state = {}) {
410
+ const bundle = objectValue(state?.evidence_bundle);
411
+ const after = objectValue(bundle.after);
412
+ const afterDelta = objectValue(after.visual_delta);
413
+ if (Object.keys(afterDelta).length) return afterDelta;
414
+ const request = objectValue(state?.proof_assessment_request);
415
+ return objectValue(request.visual_delta);
416
+ }
417
+ function visualDeltaShipGateReason(state = {}) {
418
+ if (!visualDeltaRequiredForState(state)) return null;
419
+ const visualDelta = visualDeltaForState(state);
420
+ if (visualDelta.status === "measured" && visualDelta.passed === true) return null;
421
+ const status = String(visualDelta.status || "missing");
422
+ if (status === "unmeasured") {
423
+ return "visual_delta.status=unmeasured blocks ready_to_ship for visual/UI proof";
424
+ }
425
+ if (status === "measured" && visualDelta.passed === false) {
426
+ return "visual_delta.status=measured but visual_delta.passed=false blocks ready_to_ship for visual/UI proof";
427
+ }
428
+ const reason = String(visualDelta.reason || "").trim();
429
+ if (reason) return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof: ${reason}`;
430
+ return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof`;
431
+ }
381
432
  function requiredBaselineLabelsForState(state = {}) {
382
433
  const reference = normalizedReference(state);
383
434
  const labels = [];
@@ -393,6 +444,10 @@ function validateShipGate(state = {}) {
393
444
  const afterCdn = String(state?.after_cdn || "").trim();
394
445
  const verifyStatus = String(state?.verify_status || "").trim();
395
446
  const proofAssessment = normalizedProofAssessment(state);
447
+ const verificationMode = normalizedVerificationMode(state);
448
+ const visualDelta = visualDeltaForState(state);
449
+ const visualDeltaRequired = visualDeltaRequiredForState(state);
450
+ const visualDeltaBlocker = visualDeltaShipGateReason(state);
396
451
  const reasons = [];
397
452
  if (!["before", "prod", "both"].includes(reference)) {
398
453
  reasons.push(`reference must be before, prod, or both; got ${reference}`);
@@ -421,19 +476,26 @@ function validateShipGate(state = {}) {
421
476
  if (proofAssessment.decision !== "ready_to_ship") {
422
477
  reasons.push("proof_assessment.decision must be ready_to_ship before ship");
423
478
  }
479
+ if (visualDeltaBlocker) {
480
+ reasons.push(visualDeltaBlocker);
481
+ }
424
482
  return {
425
483
  ok: reasons.length === 0,
426
484
  reasons,
427
485
  required_baselines: requiredBaselines,
428
486
  evidence: {
429
487
  reference,
488
+ verification_mode: verificationMode || null,
430
489
  prod_url: prodUrl || null,
431
490
  before_cdn: beforeCdn || null,
432
491
  prod_cdn: prodCdn || null,
433
492
  after_cdn: afterCdn || null,
434
493
  verify_status: verifyStatus || null,
435
494
  proof_assessment_decision: proofAssessment.decision,
436
- proof_assessment_source: proofAssessment.source
495
+ proof_assessment_source: proofAssessment.source,
496
+ visual_delta_required: visualDeltaRequired,
497
+ visual_delta_status: typeof visualDelta.status === "string" ? visualDelta.status : null,
498
+ visual_delta_passed: typeof visualDelta.passed === "boolean" ? visualDelta.passed : null
437
499
  }
438
500
  };
439
501
  }
@@ -747,23 +809,36 @@ function mergeStateFromParams(statePath, params) {
747
809
  state.proof_assessment_source = null;
748
810
  } else {
749
811
  const parsed = JSON.parse(raw);
750
- state.proof_assessment = {
812
+ const assessment = {
751
813
  ...parsed,
752
814
  source: (parsed?.source || "supervising_agent").toString()
753
815
  };
816
+ const readyBlocker = assessment?.decision === "ready_to_ship" ? visualDeltaShipGateReason({ ...state, proof_assessment: assessment, proof_assessment_source: assessment.source }) : null;
817
+ if (readyBlocker) {
818
+ assessment.blocked_decision = assessment.decision;
819
+ assessment.decision = "needs_richer_proof";
820
+ if (assessment.recommended_stage === "ship") assessment.recommended_stage = "verify";
821
+ if (assessment.continue_with_stage === "ship") assessment.continue_with_stage = "verify";
822
+ const blockers = Array.isArray(assessment.blockers) ? assessment.blockers : [];
823
+ assessment.blockers = [...blockers, readyBlocker];
824
+ }
825
+ state.proof_assessment = assessment;
754
826
  state.proof_assessment_source = state.proof_assessment.source;
755
- if (typeof parsed?.decision === "string") {
756
- state.proof_decision = parsed.decision;
827
+ if (typeof state.proof_assessment?.decision === "string") {
828
+ state.proof_decision = state.proof_assessment.decision;
757
829
  }
758
830
  if (typeof parsed?.summary === "string") {
759
831
  state.proof_assessment_summary = normalizeOptionalString(parsed.summary) || null;
760
832
  }
761
- if (parsed?.decision === "ready_to_ship") {
833
+ if (state.proof_assessment?.decision === "ready_to_ship") {
762
834
  state.merge_recommendation = "ready-to-ship";
763
- } else if (typeof parsed?.decision === "string" && parsed.decision.trim()) {
835
+ } else if (typeof state.proof_assessment?.decision === "string" && state.proof_assessment.decision.trim()) {
764
836
  state.merge_recommendation = "do-not-merge";
765
837
  }
766
838
  appendProofSummaryLine(state, `Supervising proof assessment: ${state.proof_assessment.decision || "unknown"}`);
839
+ if (readyBlocker) {
840
+ appendProofSummaryLine(state, `Ready-to-ship assessment blocked: ${readyBlocker}`);
841
+ }
767
842
  if (state.proof_assessment_summary) {
768
843
  appendProofSummaryLine(state, `Assessment summary: ${state.proof_assessment_summary}`);
769
844
  }
@@ -907,6 +982,9 @@ function summarizeState(state) {
907
982
  setStageDecisionRequest,
908
983
  summarizeState,
909
984
  validateShipGate,
985
+ visualDeltaForState,
986
+ visualDeltaRequiredForState,
987
+ visualDeltaShipGateReason,
910
988
  workflowFile,
911
989
  writeState
912
990
  });
@@ -70,6 +70,7 @@ interface ShipGateValidation {
70
70
  required_baselines: string[];
71
71
  evidence: {
72
72
  reference: string;
73
+ verification_mode: string | null;
73
74
  prod_url: string | null;
74
75
  before_cdn: string | null;
75
76
  prod_cdn: string | null;
@@ -77,6 +78,9 @@ interface ShipGateValidation {
77
78
  verify_status: string | null;
78
79
  proof_assessment_decision: string | null;
79
80
  proof_assessment_source: string | null;
81
+ visual_delta_required: boolean;
82
+ visual_delta_status: string | null;
83
+ visual_delta_passed: boolean | null;
80
84
  };
81
85
  }
82
86
  declare function resolveRiddleProofDir(config?: PluginConfig): string;
@@ -192,6 +196,9 @@ declare function invalidateVerifyEvidence(state?: any): {
192
196
  hadProofAssessment: boolean;
193
197
  hadProofAssessmentRequest: boolean;
194
198
  };
199
+ declare function visualDeltaRequiredForState(state?: any): boolean;
200
+ declare function visualDeltaForState(state?: any): Record<string, any>;
201
+ declare function visualDeltaShipGateReason(state?: any): string | null;
195
202
  declare function requiredBaselineLabelsForState(state?: any): string[];
196
203
  declare function validateShipGate(state?: any): ShipGateValidation;
197
204
  declare function buildCheckpointContract(state: any, request: {
@@ -283,4 +290,4 @@ declare function summarizeState(state: any): {
283
290
  };
284
291
  };
285
292
 
286
- export { BUNDLED_RIDDLE_PROOF_DIR, CHECKPOINT_CONTRACT_VERSION, type CheckpointInputContract, type PluginConfig, RIDDLE_PROOF_DIR_CANDIDATES, type ShipGateValidation, WORKFLOW_STAGE_ORDER, type WorkflowAction, type WorkflowParams, type WorkflowStage, buildCheckpointContract, buildSetupArgs, checkpointContinueStage, clearStageDecisionRequest, ensureAction, ensureStageLoopState, invalidateVerifyEvidence, mergeStateFromParams, readState, recordStageAttempt, requiredBaselineLabelsForState, resolveConfig, resolveRiddleProofDir, setStageDecisionRequest, summarizeState, validateShipGate, workflowFile, writeState };
293
+ export { BUNDLED_RIDDLE_PROOF_DIR, CHECKPOINT_CONTRACT_VERSION, type CheckpointInputContract, type PluginConfig, RIDDLE_PROOF_DIR_CANDIDATES, type ShipGateValidation, WORKFLOW_STAGE_ORDER, type WorkflowAction, type WorkflowParams, type WorkflowStage, buildCheckpointContract, buildSetupArgs, checkpointContinueStage, clearStageDecisionRequest, ensureAction, ensureStageLoopState, invalidateVerifyEvidence, mergeStateFromParams, readState, recordStageAttempt, requiredBaselineLabelsForState, resolveConfig, resolveRiddleProofDir, setStageDecisionRequest, summarizeState, validateShipGate, visualDeltaForState, visualDeltaRequiredForState, visualDeltaShipGateReason, workflowFile, writeState };
@@ -70,6 +70,7 @@ interface ShipGateValidation {
70
70
  required_baselines: string[];
71
71
  evidence: {
72
72
  reference: string;
73
+ verification_mode: string | null;
73
74
  prod_url: string | null;
74
75
  before_cdn: string | null;
75
76
  prod_cdn: string | null;
@@ -77,6 +78,9 @@ interface ShipGateValidation {
77
78
  verify_status: string | null;
78
79
  proof_assessment_decision: string | null;
79
80
  proof_assessment_source: string | null;
81
+ visual_delta_required: boolean;
82
+ visual_delta_status: string | null;
83
+ visual_delta_passed: boolean | null;
80
84
  };
81
85
  }
82
86
  declare function resolveRiddleProofDir(config?: PluginConfig): string;
@@ -192,6 +196,9 @@ declare function invalidateVerifyEvidence(state?: any): {
192
196
  hadProofAssessment: boolean;
193
197
  hadProofAssessmentRequest: boolean;
194
198
  };
199
+ declare function visualDeltaRequiredForState(state?: any): boolean;
200
+ declare function visualDeltaForState(state?: any): Record<string, any>;
201
+ declare function visualDeltaShipGateReason(state?: any): string | null;
195
202
  declare function requiredBaselineLabelsForState(state?: any): string[];
196
203
  declare function validateShipGate(state?: any): ShipGateValidation;
197
204
  declare function buildCheckpointContract(state: any, request: {
@@ -283,4 +290,4 @@ declare function summarizeState(state: any): {
283
290
  };
284
291
  };
285
292
 
286
- export { BUNDLED_RIDDLE_PROOF_DIR, CHECKPOINT_CONTRACT_VERSION, type CheckpointInputContract, type PluginConfig, RIDDLE_PROOF_DIR_CANDIDATES, type ShipGateValidation, WORKFLOW_STAGE_ORDER, type WorkflowAction, type WorkflowParams, type WorkflowStage, buildCheckpointContract, buildSetupArgs, checkpointContinueStage, clearStageDecisionRequest, ensureAction, ensureStageLoopState, invalidateVerifyEvidence, mergeStateFromParams, readState, recordStageAttempt, requiredBaselineLabelsForState, resolveConfig, resolveRiddleProofDir, setStageDecisionRequest, summarizeState, validateShipGate, workflowFile, writeState };
293
+ export { BUNDLED_RIDDLE_PROOF_DIR, CHECKPOINT_CONTRACT_VERSION, type CheckpointInputContract, type PluginConfig, RIDDLE_PROOF_DIR_CANDIDATES, type ShipGateValidation, WORKFLOW_STAGE_ORDER, type WorkflowAction, type WorkflowParams, type WorkflowStage, buildCheckpointContract, buildSetupArgs, checkpointContinueStage, clearStageDecisionRequest, ensureAction, ensureStageLoopState, invalidateVerifyEvidence, mergeStateFromParams, readState, recordStageAttempt, requiredBaselineLabelsForState, resolveConfig, resolveRiddleProofDir, setStageDecisionRequest, summarizeState, validateShipGate, visualDeltaForState, visualDeltaRequiredForState, visualDeltaShipGateReason, workflowFile, writeState };
@@ -19,9 +19,12 @@ import {
19
19
  setStageDecisionRequest,
20
20
  summarizeState,
21
21
  validateShipGate,
22
+ visualDeltaForState,
23
+ visualDeltaRequiredForState,
24
+ visualDeltaShipGateReason,
22
25
  workflowFile,
23
26
  writeState
24
- } from "./chunk-R4BPJNAM.js";
27
+ } from "./chunk-A5AWVY5A.js";
25
28
  export {
26
29
  BUNDLED_RIDDLE_PROOF_DIR,
27
30
  CHECKPOINT_CONTRACT_VERSION,
@@ -43,6 +46,9 @@ export {
43
46
  setStageDecisionRequest,
44
47
  summarizeState,
45
48
  validateShipGate,
49
+ visualDeltaForState,
50
+ visualDeltaRequiredForState,
51
+ visualDeltaShipGateReason,
46
52
  workflowFile,
47
53
  writeState
48
54
  };
@@ -363,6 +363,54 @@ function normalizedProofAssessment(state = {}) {
363
363
  source: source || null
364
364
  };
365
365
  }
366
+ var VISUAL_FIRST_MODES = /* @__PURE__ */ new Set([
367
+ "visual",
368
+ "render",
369
+ "interaction",
370
+ "ui",
371
+ "layout",
372
+ "screenshot",
373
+ "canvas",
374
+ "animation"
375
+ ]);
376
+ function objectValue(value) {
377
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
378
+ }
379
+ function normalizedVerificationMode(state = {}) {
380
+ const bundle = objectValue(state?.evidence_bundle);
381
+ const bundleMode = String(bundle.verification_mode || "").trim().toLowerCase();
382
+ if (bundleMode) return bundleMode;
383
+ return String(state?.verification_mode || "proof").trim().toLowerCase() || "proof";
384
+ }
385
+ function visualDeltaRequiredForState(state = {}) {
386
+ const bundle = objectValue(state?.evidence_bundle);
387
+ const contract = objectValue(bundle.artifact_contract);
388
+ const required = objectValue(contract.required);
389
+ return required.visual_delta === true || VISUAL_FIRST_MODES.has(normalizedVerificationMode(state));
390
+ }
391
+ function visualDeltaForState(state = {}) {
392
+ const bundle = objectValue(state?.evidence_bundle);
393
+ const after = objectValue(bundle.after);
394
+ const afterDelta = objectValue(after.visual_delta);
395
+ if (Object.keys(afterDelta).length) return afterDelta;
396
+ const request = objectValue(state?.proof_assessment_request);
397
+ return objectValue(request.visual_delta);
398
+ }
399
+ function visualDeltaShipGateReason(state = {}) {
400
+ if (!visualDeltaRequiredForState(state)) return null;
401
+ const visualDelta = visualDeltaForState(state);
402
+ if (visualDelta.status === "measured" && visualDelta.passed === true) return null;
403
+ const status = String(visualDelta.status || "missing");
404
+ if (status === "unmeasured") {
405
+ return "visual_delta.status=unmeasured blocks ready_to_ship for visual/UI proof";
406
+ }
407
+ if (status === "measured" && visualDelta.passed === false) {
408
+ return "visual_delta.status=measured but visual_delta.passed=false blocks ready_to_ship for visual/UI proof";
409
+ }
410
+ const reason = String(visualDelta.reason || "").trim();
411
+ if (reason) return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof: ${reason}`;
412
+ return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof`;
413
+ }
366
414
  function requiredBaselineLabelsForState(state = {}) {
367
415
  const reference = normalizedReference(state);
368
416
  const labels = [];
@@ -378,6 +426,10 @@ function validateShipGate(state = {}) {
378
426
  const afterCdn = String(state?.after_cdn || "").trim();
379
427
  const verifyStatus = String(state?.verify_status || "").trim();
380
428
  const proofAssessment = normalizedProofAssessment(state);
429
+ const verificationMode = normalizedVerificationMode(state);
430
+ const visualDelta = visualDeltaForState(state);
431
+ const visualDeltaRequired = visualDeltaRequiredForState(state);
432
+ const visualDeltaBlocker = visualDeltaShipGateReason(state);
381
433
  const reasons = [];
382
434
  if (!["before", "prod", "both"].includes(reference)) {
383
435
  reasons.push(`reference must be before, prod, or both; got ${reference}`);
@@ -406,19 +458,26 @@ function validateShipGate(state = {}) {
406
458
  if (proofAssessment.decision !== "ready_to_ship") {
407
459
  reasons.push("proof_assessment.decision must be ready_to_ship before ship");
408
460
  }
461
+ if (visualDeltaBlocker) {
462
+ reasons.push(visualDeltaBlocker);
463
+ }
409
464
  return {
410
465
  ok: reasons.length === 0,
411
466
  reasons,
412
467
  required_baselines: requiredBaselines,
413
468
  evidence: {
414
469
  reference,
470
+ verification_mode: verificationMode || null,
415
471
  prod_url: prodUrl || null,
416
472
  before_cdn: beforeCdn || null,
417
473
  prod_cdn: prodCdn || null,
418
474
  after_cdn: afterCdn || null,
419
475
  verify_status: verifyStatus || null,
420
476
  proof_assessment_decision: proofAssessment.decision,
421
- proof_assessment_source: proofAssessment.source
477
+ proof_assessment_source: proofAssessment.source,
478
+ visual_delta_required: visualDeltaRequired,
479
+ visual_delta_status: typeof visualDelta.status === "string" ? visualDelta.status : null,
480
+ visual_delta_passed: typeof visualDelta.passed === "boolean" ? visualDelta.passed : null
422
481
  }
423
482
  };
424
483
  }
@@ -732,23 +791,36 @@ function mergeStateFromParams(statePath, params) {
732
791
  state.proof_assessment_source = null;
733
792
  } else {
734
793
  const parsed = JSON.parse(raw);
735
- state.proof_assessment = {
794
+ const assessment = {
736
795
  ...parsed,
737
796
  source: (parsed?.source || "supervising_agent").toString()
738
797
  };
798
+ const readyBlocker = assessment?.decision === "ready_to_ship" ? visualDeltaShipGateReason({ ...state, proof_assessment: assessment, proof_assessment_source: assessment.source }) : null;
799
+ if (readyBlocker) {
800
+ assessment.blocked_decision = assessment.decision;
801
+ assessment.decision = "needs_richer_proof";
802
+ if (assessment.recommended_stage === "ship") assessment.recommended_stage = "verify";
803
+ if (assessment.continue_with_stage === "ship") assessment.continue_with_stage = "verify";
804
+ const blockers = Array.isArray(assessment.blockers) ? assessment.blockers : [];
805
+ assessment.blockers = [...blockers, readyBlocker];
806
+ }
807
+ state.proof_assessment = assessment;
739
808
  state.proof_assessment_source = state.proof_assessment.source;
740
- if (typeof parsed?.decision === "string") {
741
- state.proof_decision = parsed.decision;
809
+ if (typeof state.proof_assessment?.decision === "string") {
810
+ state.proof_decision = state.proof_assessment.decision;
742
811
  }
743
812
  if (typeof parsed?.summary === "string") {
744
813
  state.proof_assessment_summary = normalizeOptionalString(parsed.summary) || null;
745
814
  }
746
- if (parsed?.decision === "ready_to_ship") {
815
+ if (state.proof_assessment?.decision === "ready_to_ship") {
747
816
  state.merge_recommendation = "ready-to-ship";
748
- } else if (typeof parsed?.decision === "string" && parsed.decision.trim()) {
817
+ } else if (typeof state.proof_assessment?.decision === "string" && state.proof_assessment.decision.trim()) {
749
818
  state.merge_recommendation = "do-not-merge";
750
819
  }
751
820
  appendProofSummaryLine(state, `Supervising proof assessment: ${state.proof_assessment.decision || "unknown"}`);
821
+ if (readyBlocker) {
822
+ appendProofSummaryLine(state, `Ready-to-ship assessment blocked: ${readyBlocker}`);
823
+ }
752
824
  if (state.proof_assessment_summary) {
753
825
  appendProofSummaryLine(state, `Assessment summary: ${state.proof_assessment_summary}`);
754
826
  }
@@ -1622,6 +1694,9 @@ async function executeWorkflow(params, pluginConfig, resolvedConfig) {
1622
1694
  if (reasons.some((reason) => reason.includes("proof_assessment"))) {
1623
1695
  return "resume with riddle_proof_review using decision=ready_to_ship only after the screenshots and semantic evidence visibly prove the request; otherwise choose needs_implementation or needs_richer_proof";
1624
1696
  }
1697
+ if (reasons.some((reason) => reason.includes("visual_delta"))) {
1698
+ return "rerun verify with a measured before/after visual delta, or choose needs_richer_proof instead of ready_to_ship for this visual proof";
1699
+ }
1625
1700
  if (reasons.some((reason) => reason.includes("after_cdn") || reason.includes("verify_status"))) {
1626
1701
  return "rerun verify with stronger proof framing so after evidence is captured before shipping";
1627
1702
  }
@@ -1714,7 +1789,7 @@ async function executeWorkflow(params, pluginConfig, resolvedConfig) {
1714
1789
  }
1715
1790
  state = readState(config.statePath);
1716
1791
  const continuedStage = params.continue_from_checkpoint ? checkpointContinueStage(state) : null;
1717
- if (params.continue_from_checkpoint && !continuedStage) {
1792
+ if (params.continue_from_checkpoint && !params.advance_stage && !continuedStage) {
1718
1793
  const recommended = recommendedAdvanceStage(state);
1719
1794
  return checkpoint(
1720
1795
  state?.active_checkpoint_stage || recommended || "recon",