@riddledc/riddle-proof 0.8.3 → 0.8.5

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 (49) hide show
  1. package/dist/adapters/openclaw.js +4 -4
  2. package/dist/advanced/engine-harness.cjs +34 -12
  3. package/dist/advanced/engine-harness.js +4 -4
  4. package/dist/advanced/index.cjs +34 -12
  5. package/dist/advanced/index.d.cts +1 -1
  6. package/dist/advanced/index.d.ts +1 -1
  7. package/dist/advanced/index.js +6 -6
  8. package/dist/advanced/proof-run-engine.cjs +29 -9
  9. package/dist/advanced/proof-run-engine.d.cts +1 -1
  10. package/dist/advanced/proof-run-engine.d.ts +1 -1
  11. package/dist/advanced/proof-run-engine.js +1 -1
  12. package/dist/advanced/runner.js +4 -4
  13. package/dist/checkpoint.cjs +3 -1
  14. package/dist/checkpoint.js +1 -1
  15. package/dist/{chunk-SKIAZTQ7.js → chunk-4FOHZ7JG.js} +3 -1
  16. package/dist/{chunk-YB5ACBZE.js → chunk-BDFSMWTI.js} +5 -5
  17. package/dist/{chunk-U4FUFBSH.js → chunk-FMOYUYH2.js} +1 -1
  18. package/dist/{chunk-TZ3YMCDM.js → chunk-GMZ57RRY.js} +29 -9
  19. package/dist/{chunk-OIFHYMHP.js → chunk-OD5UNE57.js} +2 -2
  20. package/dist/{chunk-SMBZT46I.js → chunk-RBWSCU6V.js} +1 -1
  21. package/dist/{chunk-ZX45XGDJ.js → chunk-UIJ7X63P.js} +1 -1
  22. package/dist/{chunk-TNCDVE5O.js → chunk-YZUVEJ5B.js} +1 -1
  23. package/dist/cli/index.js +5 -5
  24. package/dist/cli.cjs +34 -12
  25. package/dist/cli.js +5 -5
  26. package/dist/engine-harness.cjs +34 -12
  27. package/dist/engine-harness.js +4 -4
  28. package/dist/index.cjs +34 -12
  29. package/dist/index.js +5 -5
  30. package/dist/openclaw.js +4 -4
  31. package/dist/{proof-run-engine-Rkd_hXB-.d.cts → proof-run-engine-B7DCPzpK.d.cts} +3 -3
  32. package/dist/{proof-run-engine-DxWW1VX1.d.ts → proof-run-engine-BomAcXhA.d.ts} +3 -3
  33. package/dist/proof-run-engine.cjs +29 -9
  34. package/dist/proof-run-engine.d.cts +1 -1
  35. package/dist/proof-run-engine.d.ts +1 -1
  36. package/dist/proof-run-engine.js +1 -1
  37. package/dist/run-card.js +2 -2
  38. package/dist/runner.js +4 -4
  39. package/dist/spec/checkpoint.cjs +3 -1
  40. package/dist/spec/checkpoint.js +1 -1
  41. package/dist/spec/index.cjs +3 -1
  42. package/dist/spec/index.js +3 -3
  43. package/dist/spec/run-card.js +2 -2
  44. package/dist/spec/state.js +3 -3
  45. package/dist/state.js +3 -3
  46. package/package.json +1 -1
  47. package/runtime/lib/util.py +57 -0
  48. package/runtime/lib/verify.py +158 -14
  49. package/runtime/tests/recon_verify_smoke.py +211 -0
@@ -249,6 +249,82 @@ class FakeRiddle:
249
249
  'largeVisibleElements': [{'tag': 'button', 'text': 'Buy Now'}],
250
250
  }),
251
251
  }
252
+ if 'clickedSkipHashNavigation' in script:
253
+ page_state = {
254
+ 'bodyTextLength': 180,
255
+ 'visibleTextSample': 'Riddle Proof homepage main content',
256
+ 'interactiveElements': 4,
257
+ 'visibleInteractiveElements': 4,
258
+ 'pathname': '/',
259
+ 'search': '',
260
+ 'hash': '#main-content',
261
+ 'title': 'Riddle',
262
+ 'buttons': ['Start Free'],
263
+ 'headings': ['Riddle Proof'],
264
+ 'links': [{'text': 'Skip to main content', 'href': '#main-content'}],
265
+ 'canvasCount': 0,
266
+ 'largeVisibleElements': [{'tag': 'main', 'text': 'Riddle Proof'}],
267
+ }
268
+ proof_evidence = {
269
+ 'before': {'href': 'https://riddledc.com/'},
270
+ 'action': 'clicked Skip to main content',
271
+ 'after': {'href': 'https://riddledc.com/#main-content'},
272
+ 'assertions': {
273
+ 'startedOnHome': True,
274
+ 'hashPreserved': True,
275
+ 'mainContentFocused': True,
276
+ },
277
+ }
278
+ return {
279
+ 'ok': True,
280
+ 'screenshots': [{'url': 'https://cdn.example.com/hash-after.png'}],
281
+ 'outputs': [{'name': 'after-hash.png', 'url': 'https://cdn.example.com/hash-after.png'}],
282
+ 'result': {'pageState': page_state, 'proofEvidence': proof_evidence},
283
+ 'console': [
284
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
285
+ 'RIDDLE_PROOF_EVIDENCE:' + json.dumps(proof_evidence),
286
+ ],
287
+ 'visual_diff': {
288
+ 'diffPercentage': 1.2,
289
+ 'differentPixels': 12000,
290
+ 'totalPixels': 972000,
291
+ },
292
+ }
293
+ if 'pricingQueryHashDropsTerminal' in script:
294
+ message = (
295
+ 'page.waitForURL: Timeout 15000ms exceeded.\n'
296
+ '=========================== logs ===========================\n'
297
+ 'waiting for navigation until "load"\n'
298
+ ' navigated to "https://riddledc.com/pricing/"'
299
+ )
300
+ page_state = {
301
+ 'bodyTextLength': 260,
302
+ 'visibleTextSample': 'Pricing One rate Browser Compute Example Costs',
303
+ 'interactiveElements': 8,
304
+ 'visibleInteractiveElements': 8,
305
+ 'pathname': '/pricing/',
306
+ 'search': '',
307
+ 'hash': '',
308
+ 'title': 'Pricing',
309
+ 'buttons': [],
310
+ 'headings': ['Pricing', 'Browser Compute'],
311
+ 'links': [{'text': 'Pricing', 'href': '/pricing/?rp_probe=1#pricing-probe'}],
312
+ 'canvasCount': 0,
313
+ 'largeVisibleElements': [{'tag': 'main', 'text': 'Pricing'}],
314
+ }
315
+ return {
316
+ 'ok': True,
317
+ 'screenshots': [{'url': 'https://cdn.example.com/pricing-no-query-hash.png'}],
318
+ 'outputs': [{'name': 'after-pricing-query-hash.png', 'url': 'https://cdn.example.com/pricing-no-query-hash.png'}],
319
+ 'result': {'pageState': page_state},
320
+ 'console': [
321
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
322
+ 'Uncaught exception: ' + message,
323
+ ],
324
+ '_artifact_json': {
325
+ 'proof.json': {'script_error': message},
326
+ },
327
+ }
252
328
  if 'clickedProofNavigation' in script:
253
329
  page_state = {
254
330
  'bodyTextLength': 180,
@@ -1376,6 +1452,34 @@ def run_project_build_retries_after_clean_failure():
1376
1452
  shutil.rmtree(tempdir)
1377
1453
 
1378
1454
 
1455
+ def run_invoke_retry_stops_on_playwright_locator_timeout():
1456
+ util = load_module('util_retry_timeout', UTIL_PATH)
1457
+ calls = []
1458
+ original_invoke = util.invoke
1459
+ original_sleep = util.time.sleep
1460
+
1461
+ def fake_invoke(tool, args, timeout=180):
1462
+ calls.append({'tool': tool, 'args': args, 'timeout': timeout})
1463
+ return {
1464
+ 'ok': False,
1465
+ 'error': 'locator.scrollIntoViewIfNeeded: Timeout 30000ms exceeded',
1466
+ }
1467
+
1468
+ try:
1469
+ util.invoke = fake_invoke
1470
+ util.time.sleep = lambda _seconds: None
1471
+ result = util.invoke_retry('riddle_script', {'script': 'await page.locator("a").click();'}, retries=3, timeout=60)
1472
+ assert result['ok'] is False
1473
+ assert len(calls) == 1, calls
1474
+ calls.clear()
1475
+ generic = util.invoke_retry('riddle_preview', {'directory': '/tmp/nope'}, retries=3, timeout=60)
1476
+ assert generic['ok'] is False
1477
+ assert len(calls) == 3, calls
1478
+ finally:
1479
+ util.invoke = original_invoke
1480
+ util.time.sleep = original_sleep
1481
+
1482
+
1379
1483
  def run_implement_records_detection_when_changes_missing():
1380
1484
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-implement-missing-'))
1381
1485
  state_path = tempdir / 'state.json'
@@ -2381,6 +2485,110 @@ def run_verify_interaction_reverse_terminal_route_from_proof_evidence():
2381
2485
  shutil.rmtree(tempdir, ignore_errors=True)
2382
2486
 
2383
2487
 
2488
+ def run_verify_interaction_hash_terminal_route_from_proof_evidence():
2489
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-hash-'))
2490
+ state_path = tempdir / 'state.json'
2491
+ try:
2492
+ state = base_state(tempdir, reference='before')
2493
+ state.update({
2494
+ 'recon_status': 'ready_for_proof_plan',
2495
+ 'author_status': 'ready',
2496
+ 'proof_plan_status': 'ready',
2497
+ 'implementation_status': 'changes_detected',
2498
+ 'verification_mode': 'interaction',
2499
+ 'server_path': '/',
2500
+ 'before_cdn': 'https://cdn.example.com/before-home.png',
2501
+ 'proof_plan': 'Start at /, click the skip link, and verify the terminal /#main-content route.',
2502
+ 'capture_script': "clickedSkipHashNavigation(); await saveScreenshot('after-hash');",
2503
+ 'recon_results': {
2504
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
2505
+ },
2506
+ })
2507
+ write_state(state_path, state)
2508
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2509
+
2510
+ fake = FakeRiddle()
2511
+ load_util_with_fake(fake)
2512
+ load_module('verify_interaction_hash_terminal_route', VERIFY_PATH)
2513
+ after_verify = json.loads(state_path.read_text())
2514
+
2515
+ assert after_verify['verify_status'] == 'evidence_captured'
2516
+ assert after_verify['route_expectation']['expected_path'] == '/#main-content'
2517
+ assert after_verify['route_expectation']['expected_hash'] == '#main-content'
2518
+ route = after_verify['proof_assessment_request']['semantic_context']['route']
2519
+ assert route['expected_after_path'] == '/#main-content'
2520
+ assert route['expected_terminal_hash'] == '#main-content'
2521
+ assert route['after_observed_path'] == '/#main-content'
2522
+ assert route['after_observed_hash'] == '#main-content'
2523
+ assert 'wrong route' not in after_verify['verify_results']['after']['observation']['reason']
2524
+ return {
2525
+ 'ok': True,
2526
+ 'expected_path': after_verify['route_expectation']['expected_path'],
2527
+ 'after_observed_hash': route['after_observed_hash'],
2528
+ }
2529
+ finally:
2530
+ shutil.rmtree(tempdir, ignore_errors=True)
2531
+
2532
+
2533
+ def run_verify_interaction_authored_query_hash_mismatch_returns_author():
2534
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-query-hash-mismatch-'))
2535
+ state_path = tempdir / 'state.json'
2536
+ try:
2537
+ state = base_state(tempdir, reference='before')
2538
+ state.update({
2539
+ 'recon_status': 'ready_for_proof_plan',
2540
+ 'author_status': 'ready',
2541
+ 'proof_plan_status': 'ready',
2542
+ 'implementation_status': 'changes_detected',
2543
+ 'implementation_mode': 'none',
2544
+ 'require_diff': False,
2545
+ 'allow_code_changes': False,
2546
+ 'verification_mode': 'interaction',
2547
+ 'server_path': '/',
2548
+ 'before_cdn': 'https://cdn.example.com/before-home.png',
2549
+ 'proof_plan': 'Start at /, click Pricing, and verify /pricing/?rp_probe=1#pricing-probe.',
2550
+ 'capture_script': "pricingQueryHashDropsTerminal(); await page.waitForURL('/pricing/?rp_probe=1#pricing-probe');",
2551
+ 'supervisor_author_packet': {
2552
+ 'proof_plan': 'Click Pricing and prove the terminal query/hash route.',
2553
+ 'capture_script': "pricingQueryHashDropsTerminal(); await page.waitForURL('/pricing/?rp_probe=1#pricing-probe');",
2554
+ 'refined_inputs': {
2555
+ 'server_path': '/',
2556
+ 'expected_terminal_path': '/pricing/?rp_probe=1#pricing-probe',
2557
+ },
2558
+ },
2559
+ 'recon_results': {
2560
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
2561
+ },
2562
+ })
2563
+ write_state(state_path, state)
2564
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2565
+
2566
+ fake = FakeRiddle()
2567
+ load_util_with_fake(fake)
2568
+ load_module('verify_interaction_authored_query_hash_mismatch', VERIFY_PATH)
2569
+ after_verify = json.loads(state_path.read_text())
2570
+
2571
+ request = after_verify['verify_decision_request']
2572
+ capture_quality = request['capture_quality']
2573
+ assert after_verify['verify_status'] == 'capture_incomplete'
2574
+ assert after_verify['route_expectation']['expected_query'] == 'rp_probe=1'
2575
+ assert after_verify['route_expectation']['expected_hash'] == '#pricing-probe'
2576
+ assert request['recommended_stage'] == 'author'
2577
+ assert request['continue_with_stage'] == 'author'
2578
+ assert capture_quality['recommended_stage'] == 'author'
2579
+ assert capture_quality['mismatch']['expected_path'] == '/pricing?rp_probe=1#pricing-probe'
2580
+ assert capture_quality['mismatch']['observed_after_path'] == '/pricing/'
2581
+ assert 'page.waitForURL: Timeout 15000ms exceeded' in capture_quality['summary']
2582
+ assert any('capture plan should be revised' in reason for reason in capture_quality['reasons'])
2583
+ return {
2584
+ 'ok': True,
2585
+ 'summary': capture_quality['summary'],
2586
+ 'recommended_stage': request['recommended_stage'],
2587
+ }
2588
+ finally:
2589
+ shutil.rmtree(tempdir, ignore_errors=True)
2590
+
2591
+
2384
2592
  def run_verify_capture_retry_surfaces_script_timeout():
2385
2593
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-capture-timeout-'))
2386
2594
  state_path = tempdir / 'state.json'
@@ -2778,6 +2986,7 @@ if __name__ == '__main__':
2778
2986
  'capture_diagnostics_redaction': run_capture_diagnostics_redact_sensitive_values(),
2779
2987
  'apply_auth_context': run_apply_auth_context_passes_supported_auth_payloads(),
2780
2988
  'run_project_build_retries_after_clean_failure': run_project_build_retries_after_clean_failure(),
2989
+ 'invoke_retry_stops_on_playwright_locator_timeout': run_invoke_retry_stops_on_playwright_locator_timeout(),
2781
2990
  'implement_records_detection_when_changes_missing': run_implement_records_detection_when_changes_missing(),
2782
2991
  'implement_ignores_tool_noise_when_detecting_changes': run_implement_ignores_tool_noise_when_detecting_changes(),
2783
2992
  'verify_quality_ignores_proof_telemetry_console_text': run_verify_quality_ignores_proof_telemetry_console_text(),
@@ -2798,6 +3007,8 @@ if __name__ == '__main__':
2798
3007
  'remote_audit_verify_uses_default_capture_script': run_remote_audit_verify_uses_default_capture_script(),
2799
3008
  'verify_interaction_terminal_route_from_proof_evidence': run_verify_interaction_terminal_route_from_proof_evidence(),
2800
3009
  'verify_interaction_reverse_terminal_route_from_proof_evidence': run_verify_interaction_reverse_terminal_route_from_proof_evidence(),
3010
+ 'verify_interaction_hash_terminal_route_from_proof_evidence': run_verify_interaction_hash_terminal_route_from_proof_evidence(),
3011
+ 'verify_interaction_authored_query_hash_mismatch_returns_author': run_verify_interaction_authored_query_hash_mismatch_returns_author(),
2801
3012
  'verify_capture_retry_surfaces_script_timeout': run_verify_capture_retry_surfaces_script_timeout(),
2802
3013
  'missing_baseline_guard': run_verify_missing_baseline(),
2803
3014
  'ship_supervisor_gate': run_ship_missing_supervisor_gate(),