@riddledc/riddle-proof 0.8.10 → 0.8.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/advanced/engine-harness.cjs +97 -12
  2. package/dist/advanced/engine-harness.js +2 -2
  3. package/dist/advanced/index.cjs +98 -12
  4. package/dist/advanced/index.d.cts +2 -2
  5. package/dist/advanced/index.d.ts +2 -2
  6. package/dist/advanced/index.js +4 -4
  7. package/dist/advanced/proof-run-core.cjs +31 -1
  8. package/dist/advanced/proof-run-core.d.cts +1 -1
  9. package/dist/advanced/proof-run-core.d.ts +1 -1
  10. package/dist/advanced/proof-run-core.js +3 -1
  11. package/dist/advanced/proof-run-engine.cjs +46 -12
  12. package/dist/advanced/proof-run-engine.d.cts +2 -2
  13. package/dist/advanced/proof-run-engine.d.ts +2 -2
  14. package/dist/advanced/proof-run-engine.js +2 -2
  15. package/dist/advanced/runner.js +2 -2
  16. package/dist/{chunk-5N5QFI2S.js → chunk-7GZY5PLT.js} +31 -1
  17. package/dist/{chunk-46DDSZJR.js → chunk-JBY2SU5U.js} +18 -12
  18. package/dist/{chunk-5N6MQCLC.js → chunk-NGX4SUQN.js} +1 -1
  19. package/dist/{chunk-BBUO7HM4.js → chunk-RTLA6CPP.js} +53 -1
  20. package/dist/{chunk-2PXL3RDB.js → chunk-SZUC4MDN.js} +1 -1
  21. package/dist/cli/index.js +3 -3
  22. package/dist/cli.cjs +97 -12
  23. package/dist/cli.js +3 -3
  24. package/dist/engine-harness.cjs +97 -12
  25. package/dist/engine-harness.js +2 -2
  26. package/dist/index.cjs +97 -12
  27. package/dist/index.js +3 -3
  28. package/dist/{proof-run-core-Ci9uFxMc.d.cts → proof-run-core-CrpYH-qH.d.cts} +5 -2
  29. package/dist/{proof-run-core-Ci9uFxMc.d.ts → proof-run-core-CrpYH-qH.d.ts} +5 -2
  30. package/dist/proof-run-core.cjs +31 -1
  31. package/dist/proof-run-core.d.cts +1 -1
  32. package/dist/proof-run-core.d.ts +1 -1
  33. package/dist/proof-run-core.js +3 -1
  34. package/dist/{proof-run-engine-Bd1T43Dy.d.cts → proof-run-engine-C6vYAZd8.d.cts} +1 -1
  35. package/dist/{proof-run-engine-CXyhB-io.d.ts → proof-run-engine-h9C1lC0w.d.ts} +1 -1
  36. package/dist/proof-run-engine.cjs +46 -12
  37. package/dist/proof-run-engine.d.cts +2 -2
  38. package/dist/proof-run-engine.d.ts +2 -2
  39. package/dist/proof-run-engine.js +2 -2
  40. package/dist/runner.js +2 -2
  41. package/package.json +1 -1
  42. package/runtime/lib/verify.py +119 -19
  43. package/runtime/tests/recon_verify_smoke.py +208 -4
  44. package/runtime/tests/trust_boundary_regression.py +18 -0
@@ -345,7 +345,12 @@ class FakeRiddle:
345
345
  'version': 'riddle-proof.interaction.v1',
346
346
  'start': {'href': 'https://riddledc.com/'},
347
347
  'action': {'type': 'click', 'target': 'Pricing'},
348
- 'terminal': {'href': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe'},
348
+ 'terminal': {
349
+ 'pathname': '/pricing/',
350
+ 'search': '?rp_probe=1',
351
+ 'hash': '#pricing-probe',
352
+ 'href': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
353
+ },
349
354
  'afterUrl': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
350
355
  'routeMatched': True,
351
356
  'assertions': {
@@ -480,6 +485,36 @@ class FakeRiddle:
480
485
  'proof.json': {'script_error': message},
481
486
  },
482
487
  }
488
+ if 'interactionThrownError' in script:
489
+ message = 'Error: intentional-riddle-proof-0811-thrown-error'
490
+ page_state = {
491
+ 'bodyTextLength': 180,
492
+ 'visibleTextSample': 'Riddle Proof homepage hero Start Free',
493
+ 'interactiveElements': 4,
494
+ 'visibleInteractiveElements': 4,
495
+ 'pathname': '/',
496
+ 'search': '',
497
+ 'hash': '',
498
+ 'title': 'Riddle',
499
+ 'buttons': ['Start Free'],
500
+ 'headings': ['Riddle Proof'],
501
+ 'links': [],
502
+ 'canvasCount': 0,
503
+ 'largeVisibleElements': [{'tag': 'h1', 'text': 'Riddle Proof'}],
504
+ }
505
+ return {
506
+ 'ok': True,
507
+ 'screenshots': [{'url': 'https://cdn.example.com/thrown-error.png'}],
508
+ 'outputs': [{'name': 'after-thrown-error.png', 'url': 'https://cdn.example.com/thrown-error.png'}],
509
+ 'result': {'pageState': page_state},
510
+ 'console': [
511
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
512
+ 'Uncaught exception: ' + message,
513
+ ],
514
+ '_artifact_json': {
515
+ 'proof.json': {'script_error': message},
516
+ },
517
+ }
483
518
  if 'after-proof' in script:
484
519
  after_url = 'https://cdn.example.com/after-artifact' if 'noVisualDelta' in script else 'https://cdn.example.com/after.png'
485
520
  outputs = [{'name': 'after.png', 'url': after_url}]
@@ -2568,6 +2603,58 @@ def run_verify_interaction_terminal_route_from_proof_evidence():
2568
2603
  shutil.rmtree(tempdir, ignore_errors=True)
2569
2604
 
2570
2605
 
2606
+ def run_verify_interaction_proof_evidence_overrides_stale_expected_path():
2607
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-stale-route-'))
2608
+ state_path = tempdir / 'state.json'
2609
+ try:
2610
+ state = base_state(tempdir, reference='before')
2611
+ state.update({
2612
+ 'recon_status': 'ready_for_proof_plan',
2613
+ 'author_status': 'ready',
2614
+ 'proof_plan_status': 'ready',
2615
+ 'implementation_status': 'changes_detected',
2616
+ 'verification_mode': 'interaction',
2617
+ 'server_path': '/',
2618
+ 'expected_terminal_path': '/state',
2619
+ 'before_cdn': 'https://cdn.example.com/before-home.png',
2620
+ 'proof_plan': 'Start at /, click Proof, and verify the terminal /proof/ route.',
2621
+ 'capture_script': "clickedProofNavigation(); await saveScreenshot('after-proof');",
2622
+ 'supervisor_author_packet': {
2623
+ 'proof_plan': 'Click Proof and prove the terminal route.',
2624
+ 'capture_script': "clickedProofNavigation(); await saveScreenshot('after-proof');",
2625
+ 'refined_inputs': {
2626
+ 'server_path': '/',
2627
+ 'expected_terminal_path': '/state',
2628
+ },
2629
+ },
2630
+ 'recon_results': {
2631
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
2632
+ },
2633
+ })
2634
+ write_state(state_path, state)
2635
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2636
+
2637
+ fake = FakeRiddle()
2638
+ load_util_with_fake(fake)
2639
+ load_module('verify_interaction_stale_route_uses_evidence', VERIFY_PATH)
2640
+ after_verify = json.loads(state_path.read_text())
2641
+
2642
+ assert after_verify['verify_status'] == 'evidence_captured'
2643
+ assert after_verify['route_expectation']['source'] == 'proof_evidence_contract'
2644
+ assert after_verify['route_expectation']['expected_path'] == '/proof'
2645
+ route = after_verify['proof_assessment_request']['semantic_context']['route']
2646
+ assert route['expected_after_path'] == '/proof'
2647
+ assert route['after_observed_path'] == '/proof'
2648
+ assert 'wrong route' not in after_verify['verify_results']['after']['observation']['reason']
2649
+ return {
2650
+ 'ok': True,
2651
+ 'expected_path': after_verify['route_expectation']['expected_path'],
2652
+ 'source': after_verify['route_expectation']['source'],
2653
+ }
2654
+ finally:
2655
+ shutil.rmtree(tempdir, ignore_errors=True)
2656
+
2657
+
2571
2658
  def run_verify_interaction_reverse_terminal_route_from_proof_evidence():
2572
2659
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-reverse-'))
2573
2660
  state_path = tempdir / 'state.json'
@@ -2612,6 +2699,59 @@ def run_verify_interaction_reverse_terminal_route_from_proof_evidence():
2612
2699
  shutil.rmtree(tempdir, ignore_errors=True)
2613
2700
 
2614
2701
 
2702
+ def run_verify_interaction_prose_route_noise_uses_proof_evidence():
2703
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-prose-noise-'))
2704
+ state_path = tempdir / 'state.json'
2705
+ try:
2706
+ state = base_state(tempdir, reference='before')
2707
+ state.update({
2708
+ 'recon_status': 'ready_for_proof_plan',
2709
+ 'author_status': 'ready',
2710
+ 'proof_plan_status': 'ready',
2711
+ 'implementation_status': 'changes_detected',
2712
+ 'verification_mode': 'interaction',
2713
+ 'server_path': '/proof/',
2714
+ 'before_cdn': 'https://cdn.example.com/before-proof.png',
2715
+ 'proof_plan': 'Start on the proof page, click Home, and confirm the home page content is visible.',
2716
+ 'capture_script': "clickedHomeNavigation(); await saveScreenshot('after-home');",
2717
+ 'change_request': (
2718
+ 'Prior wrapper notes mentioned terminal drift to /Your and package '
2719
+ '@riddledc/openclaw-riddle-proof, but those are prose diagnostics, not route expectations.'
2720
+ ),
2721
+ 'success_criteria': (
2722
+ 'Use structured browser evidence for the terminal route; do not parse '
2723
+ '/openclaw-riddle-proof from package text as the expected path.'
2724
+ ),
2725
+ 'recon_results': {
2726
+ 'baselines': {'before': {'path': '/proof/', 'url': 'https://cdn.example.com/before-proof.png'}},
2727
+ },
2728
+ })
2729
+ write_state(state_path, state)
2730
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2731
+
2732
+ fake = FakeRiddle()
2733
+ load_util_with_fake(fake)
2734
+ load_module('verify_interaction_prose_route_noise', VERIFY_PATH)
2735
+ after_verify = json.loads(state_path.read_text())
2736
+
2737
+ assert after_verify['verify_status'] == 'evidence_captured'
2738
+ assert after_verify['route_expectation']['source'] == 'proof_evidence_contract'
2739
+ assert after_verify['route_expectation']['expected_path'] == '/'
2740
+ route = after_verify['proof_assessment_request']['semantic_context']['route']
2741
+ assert route['expected_after_path'] == '/'
2742
+ assert route['after_observed_path'] == '/'
2743
+ encoded = json.dumps(after_verify, sort_keys=True)
2744
+ assert '"expected_path": "/Your"' not in encoded
2745
+ assert '"expected_path": "/openclaw-riddle-proof"' not in encoded
2746
+ return {
2747
+ 'ok': True,
2748
+ 'expected_path': after_verify['route_expectation']['expected_path'],
2749
+ 'source': after_verify['route_expectation']['source'],
2750
+ }
2751
+ finally:
2752
+ shutil.rmtree(tempdir, ignore_errors=True)
2753
+
2754
+
2615
2755
  def run_verify_interaction_hash_terminal_route_from_proof_evidence():
2616
2756
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-hash-'))
2617
2757
  state_path = tempdir / 'state.json'
@@ -2698,9 +2838,11 @@ def run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence():
2698
2838
  assert after_verify['route_expectation']['expected_query'] == 'rp_probe=1'
2699
2839
  assert after_verify['route_expectation']['expected_hash'] == '#pricing-probe'
2700
2840
  capture_quality = request['capture_quality']
2701
- assert capture_quality['decision'] in ('revise_capture', 'failed_proof_evidence', 'visual_delta_unmeasured')
2702
- assert request['recommended_stage'] in ('author', 'verify')
2703
- assert request['continue_with_stage'] in ('author', 'verify')
2841
+ assert capture_quality['decision'] == 'failed_interaction_capture'
2842
+ assert request['recommended_stage'] is None
2843
+ assert request['continue_with_stage'] is None
2844
+ assert capture_quality['blocking'] is True
2845
+ assert capture_quality['terminal_blocker'] is True
2704
2846
  quality_text = json.dumps(capture_quality, sort_keys=True)
2705
2847
  assert 'page.waitForURL: Timeout 15000ms exceeded' in quality_text
2706
2848
  assert after_verify['proof_assessment_request'] == {}
@@ -2725,6 +2867,7 @@ def run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence():
2725
2867
  'ok': True,
2726
2868
  'summary': request['summary'],
2727
2869
  'recommended_stage': request['recommended_stage'],
2870
+ 'blocking': capture_quality['blocking'],
2728
2871
  }
2729
2872
  finally:
2730
2873
  shutil.rmtree(tempdir, ignore_errors=True)
@@ -2791,6 +2934,64 @@ def run_verify_interaction_query_hash_pass_uses_proof_evidence_route():
2791
2934
  shutil.rmtree(tempdir, ignore_errors=True)
2792
2935
 
2793
2936
 
2937
+ def run_verify_interaction_thrown_error_terminal_blocker():
2938
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-thrown-error-'))
2939
+ state_path = tempdir / 'state.json'
2940
+ try:
2941
+ state = base_state(tempdir, reference='before')
2942
+ state.update({
2943
+ 'recon_status': 'ready_for_proof_plan',
2944
+ 'author_status': 'ready',
2945
+ 'proof_plan_status': 'ready',
2946
+ 'implementation_status': 'changes_detected',
2947
+ 'verification_mode': 'interaction',
2948
+ 'server_path': '/',
2949
+ 'before_cdn': 'https://cdn.example.com/before-home.png',
2950
+ 'proof_plan': 'Run a diagnostic interaction script that intentionally throws.',
2951
+ 'capture_script': "interactionThrownError();",
2952
+ 'recon_results': {
2953
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
2954
+ },
2955
+ })
2956
+ write_state(state_path, state)
2957
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2958
+
2959
+ fake = FakeRiddle()
2960
+ load_util_with_fake(fake)
2961
+ load_module('verify_interaction_thrown_error_terminal_blocker', VERIFY_PATH)
2962
+ after_verify = json.loads(state_path.read_text())
2963
+
2964
+ assert after_verify['verify_status'] == 'capture_incomplete'
2965
+ assert after_verify['merge_recommendation'] == 'do-not-merge'
2966
+ assert after_verify['proof_assessment_request'] == {}
2967
+ capture_quality = after_verify['verify_decision_request']['capture_quality']
2968
+ assert capture_quality['decision'] == 'failed_interaction_capture'
2969
+ assert capture_quality['recommended_stage'] is None
2970
+ assert capture_quality['continue_with_stage'] is None
2971
+ assert capture_quality['blocking'] is True
2972
+ assert capture_quality['terminal_blocker'] is True
2973
+ capture_quality_text = json.dumps(capture_quality, sort_keys=True)
2974
+ assert 'intentional-riddle-proof-0811-thrown-error' in capture_quality_text
2975
+ assert after_verify['structured_interaction_capture_failure_summary']
2976
+ evidence = after_verify['evidence_bundle']['proof_evidence']
2977
+ if isinstance(evidence, list):
2978
+ evidence = next(
2979
+ record for record in evidence_records(evidence)
2980
+ if record.get('version') == 'riddle-proof.interaction.capture-failure.v1'
2981
+ )
2982
+ assert evidence['version'] == 'riddle-proof.interaction.capture-failure.v1'
2983
+ assert evidence['checks']['scriptCompleted'] is False
2984
+ assert evidence['checks']['authoredEvidenceReturned'] is False
2985
+ assert 'intentional-riddle-proof-0811-thrown-error' in evidence['capture_error']
2986
+ return {
2987
+ 'ok': True,
2988
+ 'decision': capture_quality['decision'],
2989
+ 'blocking': capture_quality['blocking'],
2990
+ }
2991
+ finally:
2992
+ shutil.rmtree(tempdir, ignore_errors=True)
2993
+
2994
+
2794
2995
  def run_verify_capture_retry_surfaces_script_timeout():
2795
2996
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-capture-timeout-'))
2796
2997
  state_path = tempdir / 'state.json'
@@ -3209,10 +3410,13 @@ if __name__ == '__main__':
3209
3410
  'verify_capture_retry': run_verify_capture_retry(),
3210
3411
  'remote_audit_verify_uses_default_capture_script': run_remote_audit_verify_uses_default_capture_script(),
3211
3412
  'verify_interaction_terminal_route_from_proof_evidence': run_verify_interaction_terminal_route_from_proof_evidence(),
3413
+ 'verify_interaction_proof_evidence_overrides_stale_expected_path': run_verify_interaction_proof_evidence_overrides_stale_expected_path(),
3212
3414
  'verify_interaction_reverse_terminal_route_from_proof_evidence': run_verify_interaction_reverse_terminal_route_from_proof_evidence(),
3415
+ 'verify_interaction_prose_route_noise_uses_proof_evidence': run_verify_interaction_prose_route_noise_uses_proof_evidence(),
3213
3416
  'verify_interaction_hash_terminal_route_from_proof_evidence': run_verify_interaction_hash_terminal_route_from_proof_evidence(),
3214
3417
  'verify_interaction_authored_query_hash_mismatch_blocks_with_evidence': run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence(),
3215
3418
  'verify_interaction_query_hash_pass_uses_proof_evidence_route': run_verify_interaction_query_hash_pass_uses_proof_evidence_route(),
3419
+ 'verify_interaction_thrown_error_terminal_blocker': run_verify_interaction_thrown_error_terminal_blocker(),
3216
3420
  'verify_capture_retry_surfaces_script_timeout': run_verify_capture_retry_surfaces_script_timeout(),
3217
3421
  'missing_baseline_guard': run_verify_missing_baseline(),
3218
3422
  'ship_supervisor_gate': run_ship_missing_supervisor_gate(),
@@ -25,12 +25,24 @@ CASES = [
25
25
  'function': 'run_verify_interaction_terminal_route_from_proof_evidence',
26
26
  'expected_terminal': 'pass',
27
27
  },
28
+ {
29
+ 'name': 'route-change-retry-state-drift-ignored',
30
+ 'covers': ['route-changing interactions', 'proof-evidence-present'],
31
+ 'function': 'run_verify_interaction_proof_evidence_overrides_stale_expected_path',
32
+ 'expected_terminal': 'pass',
33
+ },
28
34
  {
29
35
  'name': 'route-change-reverse-pass',
30
36
  'covers': ['route-changing interactions'],
31
37
  'function': 'run_verify_interaction_reverse_terminal_route_from_proof_evidence',
32
38
  'expected_terminal': 'pass',
33
39
  },
40
+ {
41
+ 'name': 'route-prose-noise-ignored',
42
+ 'covers': ['route-changing interactions', 'proof-evidence-present'],
43
+ 'function': 'run_verify_interaction_prose_route_noise_uses_proof_evidence',
44
+ 'expected_terminal': 'pass',
45
+ },
34
46
  {
35
47
  'name': 'query-hash-trailing-slash-pass',
36
48
  'covers': ['query/hash/trailing-slash URLs', 'proof-evidence-present'],
@@ -61,6 +73,12 @@ CASES = [
61
73
  'function': 'run_verify_preserves_proof_evidence_on_capture_script_error',
62
74
  'expected_terminal': 'specific_blocker',
63
75
  },
76
+ {
77
+ 'name': 'interaction-thrown-error-specific-blocker',
78
+ 'covers': ['thrown errors', 'invalid browser evidence'],
79
+ 'function': 'run_verify_interaction_thrown_error_terminal_blocker',
80
+ 'expected_terminal': 'specific_blocker',
81
+ },
64
82
  {
65
83
  'name': 'structured-proof-without-screenshot-pass',
66
84
  'covers': ['proof-evidence-present'],