@riddledc/riddle-proof 0.8.11 → 0.8.13
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/advanced/engine-harness.cjs +97 -12
- package/dist/advanced/engine-harness.js +2 -2
- package/dist/advanced/index.cjs +98 -12
- package/dist/advanced/index.d.cts +2 -2
- package/dist/advanced/index.d.ts +2 -2
- package/dist/advanced/index.js +4 -4
- package/dist/advanced/proof-run-core.cjs +31 -1
- package/dist/advanced/proof-run-core.d.cts +1 -1
- package/dist/advanced/proof-run-core.d.ts +1 -1
- package/dist/advanced/proof-run-core.js +3 -1
- package/dist/advanced/proof-run-engine.cjs +46 -12
- package/dist/advanced/proof-run-engine.d.cts +2 -2
- package/dist/advanced/proof-run-engine.d.ts +2 -2
- package/dist/advanced/proof-run-engine.js +2 -2
- package/dist/advanced/runner.js +2 -2
- package/dist/{chunk-5N5QFI2S.js → chunk-7GZY5PLT.js} +31 -1
- package/dist/{chunk-46DDSZJR.js → chunk-JBY2SU5U.js} +18 -12
- package/dist/{chunk-5N6MQCLC.js → chunk-NGX4SUQN.js} +1 -1
- package/dist/{chunk-BBUO7HM4.js → chunk-RTLA6CPP.js} +53 -1
- package/dist/{chunk-2PXL3RDB.js → chunk-SZUC4MDN.js} +1 -1
- package/dist/cli/index.js +3 -3
- package/dist/cli.cjs +97 -12
- package/dist/cli.js +3 -3
- package/dist/engine-harness.cjs +97 -12
- package/dist/engine-harness.js +2 -2
- package/dist/index.cjs +97 -12
- package/dist/index.js +3 -3
- package/dist/{proof-run-core-CE0jx7wL.d.cts → proof-run-core-C8FDUhle.d.cts} +5 -2
- package/dist/{proof-run-core-CE0jx7wL.d.ts → proof-run-core-C8FDUhle.d.ts} +5 -2
- package/dist/proof-run-core.cjs +31 -1
- package/dist/proof-run-core.d.cts +1 -1
- package/dist/proof-run-core.d.ts +1 -1
- package/dist/proof-run-core.js +3 -1
- package/dist/{proof-run-engine-BomAcXhA.d.ts → proof-run-engine-By7oLsF-.d.ts} +1 -1
- package/dist/{proof-run-engine-B7DCPzpK.d.cts → proof-run-engine-D80hVFMf.d.cts} +1 -1
- package/dist/proof-run-engine.cjs +46 -12
- package/dist/proof-run-engine.d.cts +2 -2
- package/dist/proof-run-engine.d.ts +2 -2
- package/dist/proof-run-engine.js +2 -2
- package/dist/runner.js +2 -2
- package/package.json +1 -1
- package/runtime/lib/verify.py +266 -22
- package/runtime/tests/recon_verify_smoke.py +291 -4
- package/runtime/tests/trust_boundary_regression.py +18 -0
|
@@ -325,6 +325,70 @@ class FakeRiddle:
|
|
|
325
325
|
'proof.json': {'script_error': message},
|
|
326
326
|
},
|
|
327
327
|
}
|
|
328
|
+
if 'pricingQueryHashStructuredNegativeControl' in script:
|
|
329
|
+
page_state = {
|
|
330
|
+
'bodyTextLength': 260,
|
|
331
|
+
'visibleTextSample': 'Pricing One rate Browser Compute Example Costs',
|
|
332
|
+
'interactiveElements': 8,
|
|
333
|
+
'visibleInteractiveElements': 8,
|
|
334
|
+
'pathname': '/pricing/',
|
|
335
|
+
'search': '',
|
|
336
|
+
'hash': '',
|
|
337
|
+
'title': 'Pricing',
|
|
338
|
+
'buttons': [],
|
|
339
|
+
'headings': ['Pricing', 'Browser Compute'],
|
|
340
|
+
'links': [{'text': 'Pricing', 'href': '/pricing/?rp_probe=1#pricing-probe'}],
|
|
341
|
+
'canvasCount': 0,
|
|
342
|
+
'largeVisibleElements': [{'tag': 'main', 'text': 'Pricing'}],
|
|
343
|
+
}
|
|
344
|
+
proof_evidence = {
|
|
345
|
+
'version': 'riddle-proof.interaction.v1',
|
|
346
|
+
'probe': 'query-hash-dropped-negative-control',
|
|
347
|
+
'negativeControl': True,
|
|
348
|
+
'routeExpectationSource': 'capture_script.expectedUrl',
|
|
349
|
+
'expectedUrl': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
|
|
350
|
+
'expectedHref': '/pricing/?rp_probe=1#pricing-probe',
|
|
351
|
+
'intentionalObservedUrl': 'https://riddledc.com/pricing/',
|
|
352
|
+
'start': {'href': 'https://riddledc.com/', 'pathname': '/', 'search': '', 'hash': ''},
|
|
353
|
+
'action': {
|
|
354
|
+
'type': 'rewrite-pricing-link-click-then-drop-query-hash',
|
|
355
|
+
'afterClickHref': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
|
|
356
|
+
'afterClickPathname': '/pricing/',
|
|
357
|
+
'afterClickSearch': '?rp_probe=1',
|
|
358
|
+
'afterClickHash': '#pricing-probe',
|
|
359
|
+
'expectedNavigationReached': True,
|
|
360
|
+
},
|
|
361
|
+
'terminal': {
|
|
362
|
+
'href': 'https://riddledc.com/pricing/',
|
|
363
|
+
'pathname': '/pricing/',
|
|
364
|
+
'search': '',
|
|
365
|
+
'hash': '',
|
|
366
|
+
},
|
|
367
|
+
'assertions': {
|
|
368
|
+
'expectedUrlPreserved': True,
|
|
369
|
+
'expectedUrlReachedBeforeDrop': True,
|
|
370
|
+
'routeExpectationSourceIsCaptureScriptExpectedUrl': True,
|
|
371
|
+
'terminalIntentionallyDroppedQueryHash': True,
|
|
372
|
+
'terminalUrlMismatchIsIntentional': True,
|
|
373
|
+
'terminalMainVisible': True,
|
|
374
|
+
},
|
|
375
|
+
'errors': [],
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
'ok': True,
|
|
379
|
+
'screenshots': [{'url': 'https://cdn.example.com/pricing-negative-control.png'}],
|
|
380
|
+
'outputs': [{'name': 'after-pricing-negative-control.png', 'url': 'https://cdn.example.com/pricing-negative-control.png'}],
|
|
381
|
+
'result': {'pageState': page_state, 'proofEvidence': proof_evidence},
|
|
382
|
+
'console': [
|
|
383
|
+
'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
|
|
384
|
+
'RIDDLE_PROOF_EVIDENCE:' + json.dumps(proof_evidence),
|
|
385
|
+
],
|
|
386
|
+
'visual_diff': {
|
|
387
|
+
'diffPercentage': 1.2,
|
|
388
|
+
'differentPixels': 12000,
|
|
389
|
+
'totalPixels': 972000,
|
|
390
|
+
},
|
|
391
|
+
}
|
|
328
392
|
if 'pricingQueryHashPassesWithPageStateHashGap' in script:
|
|
329
393
|
page_state = {
|
|
330
394
|
'bodyTextLength': 260,
|
|
@@ -345,7 +409,12 @@ class FakeRiddle:
|
|
|
345
409
|
'version': 'riddle-proof.interaction.v1',
|
|
346
410
|
'start': {'href': 'https://riddledc.com/'},
|
|
347
411
|
'action': {'type': 'click', 'target': 'Pricing'},
|
|
348
|
-
'terminal': {
|
|
412
|
+
'terminal': {
|
|
413
|
+
'pathname': '/pricing/',
|
|
414
|
+
'search': '?rp_probe=1',
|
|
415
|
+
'hash': '#pricing-probe',
|
|
416
|
+
'href': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
|
|
417
|
+
},
|
|
349
418
|
'afterUrl': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
|
|
350
419
|
'routeMatched': True,
|
|
351
420
|
'assertions': {
|
|
@@ -480,6 +549,36 @@ class FakeRiddle:
|
|
|
480
549
|
'proof.json': {'script_error': message},
|
|
481
550
|
},
|
|
482
551
|
}
|
|
552
|
+
if 'interactionThrownError' in script:
|
|
553
|
+
message = 'Error: intentional-riddle-proof-0811-thrown-error'
|
|
554
|
+
page_state = {
|
|
555
|
+
'bodyTextLength': 180,
|
|
556
|
+
'visibleTextSample': 'Riddle Proof homepage hero Start Free',
|
|
557
|
+
'interactiveElements': 4,
|
|
558
|
+
'visibleInteractiveElements': 4,
|
|
559
|
+
'pathname': '/',
|
|
560
|
+
'search': '',
|
|
561
|
+
'hash': '',
|
|
562
|
+
'title': 'Riddle',
|
|
563
|
+
'buttons': ['Start Free'],
|
|
564
|
+
'headings': ['Riddle Proof'],
|
|
565
|
+
'links': [],
|
|
566
|
+
'canvasCount': 0,
|
|
567
|
+
'largeVisibleElements': [{'tag': 'h1', 'text': 'Riddle Proof'}],
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
'ok': True,
|
|
571
|
+
'screenshots': [{'url': 'https://cdn.example.com/thrown-error.png'}],
|
|
572
|
+
'outputs': [{'name': 'after-thrown-error.png', 'url': 'https://cdn.example.com/thrown-error.png'}],
|
|
573
|
+
'result': {'pageState': page_state},
|
|
574
|
+
'console': [
|
|
575
|
+
'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
|
|
576
|
+
'Uncaught exception: ' + message,
|
|
577
|
+
],
|
|
578
|
+
'_artifact_json': {
|
|
579
|
+
'proof.json': {'script_error': message},
|
|
580
|
+
},
|
|
581
|
+
}
|
|
483
582
|
if 'after-proof' in script:
|
|
484
583
|
after_url = 'https://cdn.example.com/after-artifact' if 'noVisualDelta' in script else 'https://cdn.example.com/after.png'
|
|
485
584
|
outputs = [{'name': 'after.png', 'url': after_url}]
|
|
@@ -2568,6 +2667,58 @@ def run_verify_interaction_terminal_route_from_proof_evidence():
|
|
|
2568
2667
|
shutil.rmtree(tempdir, ignore_errors=True)
|
|
2569
2668
|
|
|
2570
2669
|
|
|
2670
|
+
def run_verify_interaction_proof_evidence_overrides_stale_expected_path():
|
|
2671
|
+
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-stale-route-'))
|
|
2672
|
+
state_path = tempdir / 'state.json'
|
|
2673
|
+
try:
|
|
2674
|
+
state = base_state(tempdir, reference='before')
|
|
2675
|
+
state.update({
|
|
2676
|
+
'recon_status': 'ready_for_proof_plan',
|
|
2677
|
+
'author_status': 'ready',
|
|
2678
|
+
'proof_plan_status': 'ready',
|
|
2679
|
+
'implementation_status': 'changes_detected',
|
|
2680
|
+
'verification_mode': 'interaction',
|
|
2681
|
+
'server_path': '/',
|
|
2682
|
+
'expected_terminal_path': '/state',
|
|
2683
|
+
'before_cdn': 'https://cdn.example.com/before-home.png',
|
|
2684
|
+
'proof_plan': 'Start at /, click Proof, and verify the terminal /proof/ route.',
|
|
2685
|
+
'capture_script': "clickedProofNavigation(); await saveScreenshot('after-proof');",
|
|
2686
|
+
'supervisor_author_packet': {
|
|
2687
|
+
'proof_plan': 'Click Proof and prove the terminal route.',
|
|
2688
|
+
'capture_script': "clickedProofNavigation(); await saveScreenshot('after-proof');",
|
|
2689
|
+
'refined_inputs': {
|
|
2690
|
+
'server_path': '/',
|
|
2691
|
+
'expected_terminal_path': '/state',
|
|
2692
|
+
},
|
|
2693
|
+
},
|
|
2694
|
+
'recon_results': {
|
|
2695
|
+
'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
|
|
2696
|
+
},
|
|
2697
|
+
})
|
|
2698
|
+
write_state(state_path, state)
|
|
2699
|
+
os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
|
|
2700
|
+
|
|
2701
|
+
fake = FakeRiddle()
|
|
2702
|
+
load_util_with_fake(fake)
|
|
2703
|
+
load_module('verify_interaction_stale_route_uses_evidence', VERIFY_PATH)
|
|
2704
|
+
after_verify = json.loads(state_path.read_text())
|
|
2705
|
+
|
|
2706
|
+
assert after_verify['verify_status'] == 'evidence_captured'
|
|
2707
|
+
assert after_verify['route_expectation']['source'] == 'proof_evidence_contract'
|
|
2708
|
+
assert after_verify['route_expectation']['expected_path'] == '/proof'
|
|
2709
|
+
route = after_verify['proof_assessment_request']['semantic_context']['route']
|
|
2710
|
+
assert route['expected_after_path'] == '/proof'
|
|
2711
|
+
assert route['after_observed_path'] == '/proof'
|
|
2712
|
+
assert 'wrong route' not in after_verify['verify_results']['after']['observation']['reason']
|
|
2713
|
+
return {
|
|
2714
|
+
'ok': True,
|
|
2715
|
+
'expected_path': after_verify['route_expectation']['expected_path'],
|
|
2716
|
+
'source': after_verify['route_expectation']['source'],
|
|
2717
|
+
}
|
|
2718
|
+
finally:
|
|
2719
|
+
shutil.rmtree(tempdir, ignore_errors=True)
|
|
2720
|
+
|
|
2721
|
+
|
|
2571
2722
|
def run_verify_interaction_reverse_terminal_route_from_proof_evidence():
|
|
2572
2723
|
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-reverse-'))
|
|
2573
2724
|
state_path = tempdir / 'state.json'
|
|
@@ -2751,9 +2902,11 @@ def run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence():
|
|
|
2751
2902
|
assert after_verify['route_expectation']['expected_query'] == 'rp_probe=1'
|
|
2752
2903
|
assert after_verify['route_expectation']['expected_hash'] == '#pricing-probe'
|
|
2753
2904
|
capture_quality = request['capture_quality']
|
|
2754
|
-
assert capture_quality['decision']
|
|
2755
|
-
assert request['recommended_stage']
|
|
2756
|
-
assert request['continue_with_stage']
|
|
2905
|
+
assert capture_quality['decision'] == 'failed_interaction_capture'
|
|
2906
|
+
assert request['recommended_stage'] is None
|
|
2907
|
+
assert request['continue_with_stage'] is None
|
|
2908
|
+
assert capture_quality['blocking'] is True
|
|
2909
|
+
assert capture_quality['terminal_blocker'] is True
|
|
2757
2910
|
quality_text = json.dumps(capture_quality, sort_keys=True)
|
|
2758
2911
|
assert 'page.waitForURL: Timeout 15000ms exceeded' in quality_text
|
|
2759
2912
|
assert after_verify['proof_assessment_request'] == {}
|
|
@@ -2778,6 +2931,7 @@ def run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence():
|
|
|
2778
2931
|
'ok': True,
|
|
2779
2932
|
'summary': request['summary'],
|
|
2780
2933
|
'recommended_stage': request['recommended_stage'],
|
|
2934
|
+
'blocking': capture_quality['blocking'],
|
|
2781
2935
|
}
|
|
2782
2936
|
finally:
|
|
2783
2937
|
shutil.rmtree(tempdir, ignore_errors=True)
|
|
@@ -2844,6 +2998,136 @@ def run_verify_interaction_query_hash_pass_uses_proof_evidence_route():
|
|
|
2844
2998
|
shutil.rmtree(tempdir, ignore_errors=True)
|
|
2845
2999
|
|
|
2846
3000
|
|
|
3001
|
+
def run_verify_interaction_explicit_expected_url_blocks_dropped_terminal_route():
|
|
3002
|
+
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-explicit-expected-url-mismatch-'))
|
|
3003
|
+
state_path = tempdir / 'state.json'
|
|
3004
|
+
try:
|
|
3005
|
+
state = base_state(tempdir, reference='before')
|
|
3006
|
+
state.update({
|
|
3007
|
+
'recon_status': 'ready_for_proof_plan',
|
|
3008
|
+
'author_status': 'ready',
|
|
3009
|
+
'proof_plan_status': 'ready',
|
|
3010
|
+
'implementation_status': 'changes_detected',
|
|
3011
|
+
'verification_mode': 'interaction',
|
|
3012
|
+
'server_path': '/',
|
|
3013
|
+
'before_cdn': 'https://cdn.example.com/before-home.png',
|
|
3014
|
+
'proof_plan': 'Start at /, click Pricing, and intentionally prove the query/hash route mismatch.',
|
|
3015
|
+
'capture_script': "pricingQueryHashStructuredNegativeControl();",
|
|
3016
|
+
'supervisor_author_packet': {
|
|
3017
|
+
'proof_plan': 'Use expectedUrl as the route expectation and return structured evidence for the dropped query/hash terminal URL.',
|
|
3018
|
+
'capture_script': "pricingQueryHashStructuredNegativeControl();",
|
|
3019
|
+
'refined_inputs': {
|
|
3020
|
+
'server_path': '/',
|
|
3021
|
+
},
|
|
3022
|
+
},
|
|
3023
|
+
'recon_results': {
|
|
3024
|
+
'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
|
|
3025
|
+
},
|
|
3026
|
+
})
|
|
3027
|
+
write_state(state_path, state)
|
|
3028
|
+
os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
|
|
3029
|
+
|
|
3030
|
+
fake = FakeRiddle()
|
|
3031
|
+
load_util_with_fake(fake)
|
|
3032
|
+
load_module('verify_interaction_explicit_expected_url_blocks_dropped_terminal_route', VERIFY_PATH)
|
|
3033
|
+
after_verify = json.loads(state_path.read_text())
|
|
3034
|
+
|
|
3035
|
+
request = after_verify['verify_decision_request']
|
|
3036
|
+
assert after_verify['verify_status'] == 'capture_incomplete'
|
|
3037
|
+
assert after_verify['merge_recommendation'] == 'do-not-merge'
|
|
3038
|
+
assert after_verify['route_expectation']['source'] == 'proof_evidence_contract'
|
|
3039
|
+
assert after_verify['route_expectation']['expected_path'] == '/pricing?rp_probe=1#pricing-probe'
|
|
3040
|
+
assert after_verify['route_expectation']['expected_query'] == 'rp_probe=1'
|
|
3041
|
+
assert after_verify['route_expectation']['expected_hash'] == '#pricing-probe'
|
|
3042
|
+
assert request['recommended_stage'] is None
|
|
3043
|
+
assert request['continue_with_stage'] is None
|
|
3044
|
+
capture_quality = request['capture_quality']
|
|
3045
|
+
assert capture_quality['decision'] == 'failed_interaction_capture'
|
|
3046
|
+
assert capture_quality['blocking'] is True
|
|
3047
|
+
assert capture_quality['terminal_blocker'] is True
|
|
3048
|
+
assert capture_quality['mismatch']['expected_path'] == '/pricing?rp_probe=1#pricing-probe'
|
|
3049
|
+
assert capture_quality['mismatch']['observed_after_path'] in ('/pricing', '/pricing/')
|
|
3050
|
+
assert 'Interaction proof terminal route mismatch' in capture_quality['summary']
|
|
3051
|
+
assert after_verify['proof_assessment_request'] == {}
|
|
3052
|
+
observation = request['latest_observation']
|
|
3053
|
+
assert observation['valid'] is False
|
|
3054
|
+
assert 'wrong route' in observation['reason']
|
|
3055
|
+
supporting = after_verify['verify_results']['after']['supporting_artifacts']
|
|
3056
|
+
assert supporting['proof_evidence_present'] is True
|
|
3057
|
+
assert supporting['has_structured_payload'] is True
|
|
3058
|
+
route = after_verify['evidence_bundle']['semantic_context']['route']
|
|
3059
|
+
assert route['expected_terminal_query'] == 'rp_probe=1'
|
|
3060
|
+
assert route['expected_terminal_hash'] == '#pricing-probe'
|
|
3061
|
+
assert route['after_observed_path'] == '/pricing'
|
|
3062
|
+
assert route['after_observed_query'] == ''
|
|
3063
|
+
assert route['after_observed_hash'] == ''
|
|
3064
|
+
return {
|
|
3065
|
+
'ok': True,
|
|
3066
|
+
'decision': capture_quality['decision'],
|
|
3067
|
+
'summary': capture_quality['summary'],
|
|
3068
|
+
}
|
|
3069
|
+
finally:
|
|
3070
|
+
shutil.rmtree(tempdir, ignore_errors=True)
|
|
3071
|
+
|
|
3072
|
+
|
|
3073
|
+
def run_verify_interaction_thrown_error_terminal_blocker():
|
|
3074
|
+
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-thrown-error-'))
|
|
3075
|
+
state_path = tempdir / 'state.json'
|
|
3076
|
+
try:
|
|
3077
|
+
state = base_state(tempdir, reference='before')
|
|
3078
|
+
state.update({
|
|
3079
|
+
'recon_status': 'ready_for_proof_plan',
|
|
3080
|
+
'author_status': 'ready',
|
|
3081
|
+
'proof_plan_status': 'ready',
|
|
3082
|
+
'implementation_status': 'changes_detected',
|
|
3083
|
+
'verification_mode': 'interaction',
|
|
3084
|
+
'server_path': '/',
|
|
3085
|
+
'before_cdn': 'https://cdn.example.com/before-home.png',
|
|
3086
|
+
'proof_plan': 'Run a diagnostic interaction script that intentionally throws.',
|
|
3087
|
+
'capture_script': "interactionThrownError();",
|
|
3088
|
+
'recon_results': {
|
|
3089
|
+
'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
|
|
3090
|
+
},
|
|
3091
|
+
})
|
|
3092
|
+
write_state(state_path, state)
|
|
3093
|
+
os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
|
|
3094
|
+
|
|
3095
|
+
fake = FakeRiddle()
|
|
3096
|
+
load_util_with_fake(fake)
|
|
3097
|
+
load_module('verify_interaction_thrown_error_terminal_blocker', VERIFY_PATH)
|
|
3098
|
+
after_verify = json.loads(state_path.read_text())
|
|
3099
|
+
|
|
3100
|
+
assert after_verify['verify_status'] == 'capture_incomplete'
|
|
3101
|
+
assert after_verify['merge_recommendation'] == 'do-not-merge'
|
|
3102
|
+
assert after_verify['proof_assessment_request'] == {}
|
|
3103
|
+
capture_quality = after_verify['verify_decision_request']['capture_quality']
|
|
3104
|
+
assert capture_quality['decision'] == 'failed_interaction_capture'
|
|
3105
|
+
assert capture_quality['recommended_stage'] is None
|
|
3106
|
+
assert capture_quality['continue_with_stage'] is None
|
|
3107
|
+
assert capture_quality['blocking'] is True
|
|
3108
|
+
assert capture_quality['terminal_blocker'] is True
|
|
3109
|
+
capture_quality_text = json.dumps(capture_quality, sort_keys=True)
|
|
3110
|
+
assert 'intentional-riddle-proof-0811-thrown-error' in capture_quality_text
|
|
3111
|
+
assert after_verify['structured_interaction_capture_failure_summary']
|
|
3112
|
+
evidence = after_verify['evidence_bundle']['proof_evidence']
|
|
3113
|
+
if isinstance(evidence, list):
|
|
3114
|
+
evidence = next(
|
|
3115
|
+
record for record in evidence_records(evidence)
|
|
3116
|
+
if record.get('version') == 'riddle-proof.interaction.capture-failure.v1'
|
|
3117
|
+
)
|
|
3118
|
+
assert evidence['version'] == 'riddle-proof.interaction.capture-failure.v1'
|
|
3119
|
+
assert evidence['checks']['scriptCompleted'] is False
|
|
3120
|
+
assert evidence['checks']['authoredEvidenceReturned'] is False
|
|
3121
|
+
assert 'intentional-riddle-proof-0811-thrown-error' in evidence['capture_error']
|
|
3122
|
+
return {
|
|
3123
|
+
'ok': True,
|
|
3124
|
+
'decision': capture_quality['decision'],
|
|
3125
|
+
'blocking': capture_quality['blocking'],
|
|
3126
|
+
}
|
|
3127
|
+
finally:
|
|
3128
|
+
shutil.rmtree(tempdir, ignore_errors=True)
|
|
3129
|
+
|
|
3130
|
+
|
|
2847
3131
|
def run_verify_capture_retry_surfaces_script_timeout():
|
|
2848
3132
|
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-capture-timeout-'))
|
|
2849
3133
|
state_path = tempdir / 'state.json'
|
|
@@ -3262,11 +3546,14 @@ if __name__ == '__main__':
|
|
|
3262
3546
|
'verify_capture_retry': run_verify_capture_retry(),
|
|
3263
3547
|
'remote_audit_verify_uses_default_capture_script': run_remote_audit_verify_uses_default_capture_script(),
|
|
3264
3548
|
'verify_interaction_terminal_route_from_proof_evidence': run_verify_interaction_terminal_route_from_proof_evidence(),
|
|
3549
|
+
'verify_interaction_proof_evidence_overrides_stale_expected_path': run_verify_interaction_proof_evidence_overrides_stale_expected_path(),
|
|
3265
3550
|
'verify_interaction_reverse_terminal_route_from_proof_evidence': run_verify_interaction_reverse_terminal_route_from_proof_evidence(),
|
|
3266
3551
|
'verify_interaction_prose_route_noise_uses_proof_evidence': run_verify_interaction_prose_route_noise_uses_proof_evidence(),
|
|
3267
3552
|
'verify_interaction_hash_terminal_route_from_proof_evidence': run_verify_interaction_hash_terminal_route_from_proof_evidence(),
|
|
3268
3553
|
'verify_interaction_authored_query_hash_mismatch_blocks_with_evidence': run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence(),
|
|
3269
3554
|
'verify_interaction_query_hash_pass_uses_proof_evidence_route': run_verify_interaction_query_hash_pass_uses_proof_evidence_route(),
|
|
3555
|
+
'verify_interaction_explicit_expected_url_blocks_dropped_terminal_route': run_verify_interaction_explicit_expected_url_blocks_dropped_terminal_route(),
|
|
3556
|
+
'verify_interaction_thrown_error_terminal_blocker': run_verify_interaction_thrown_error_terminal_blocker(),
|
|
3270
3557
|
'verify_capture_retry_surfaces_script_timeout': run_verify_capture_retry_surfaces_script_timeout(),
|
|
3271
3558
|
'missing_baseline_guard': run_verify_missing_baseline(),
|
|
3272
3559
|
'ship_supervisor_gate': run_ship_missing_supervisor_gate(),
|
|
@@ -25,6 +25,12 @@ 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'],
|
|
@@ -49,6 +55,12 @@ CASES = [
|
|
|
49
55
|
'function': 'run_verify_interaction_authored_query_hash_mismatch_blocks_with_evidence',
|
|
50
56
|
'expected_terminal': 'specific_blocker',
|
|
51
57
|
},
|
|
58
|
+
{
|
|
59
|
+
'name': 'query-hash-dropped-structured-negative-blocker',
|
|
60
|
+
'covers': ['query/hash/trailing-slash URLs', 'invalid browser evidence', 'proof-evidence-present'],
|
|
61
|
+
'function': 'run_verify_interaction_explicit_expected_url_blocks_dropped_terminal_route',
|
|
62
|
+
'expected_terminal': 'specific_blocker',
|
|
63
|
+
},
|
|
52
64
|
{
|
|
53
65
|
'name': 'same-page-hash-pass',
|
|
54
66
|
'covers': ['same-page hashes'],
|
|
@@ -67,6 +79,12 @@ CASES = [
|
|
|
67
79
|
'function': 'run_verify_preserves_proof_evidence_on_capture_script_error',
|
|
68
80
|
'expected_terminal': 'specific_blocker',
|
|
69
81
|
},
|
|
82
|
+
{
|
|
83
|
+
'name': 'interaction-thrown-error-specific-blocker',
|
|
84
|
+
'covers': ['thrown errors', 'invalid browser evidence'],
|
|
85
|
+
'function': 'run_verify_interaction_thrown_error_terminal_blocker',
|
|
86
|
+
'expected_terminal': 'specific_blocker',
|
|
87
|
+
},
|
|
70
88
|
{
|
|
71
89
|
'name': 'structured-proof-without-screenshot-pass',
|
|
72
90
|
'covers': ['proof-evidence-present'],
|