@riddledc/riddle-proof 0.8.1 → 0.8.2

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 (57) hide show
  1. package/dist/adapters/openclaw.js +4 -4
  2. package/dist/advanced/engine-harness.cjs +25 -4
  3. package/dist/advanced/engine-harness.js +5 -5
  4. package/dist/advanced/index.cjs +25 -4
  5. package/dist/advanced/index.d.cts +1 -1
  6. package/dist/advanced/index.d.ts +1 -1
  7. package/dist/advanced/index.js +7 -7
  8. package/dist/advanced/proof-run-core.cjs +12 -0
  9. package/dist/advanced/proof-run-core.js +1 -1
  10. package/dist/advanced/proof-run-engine.cjs +19 -0
  11. package/dist/advanced/proof-run-engine.d.cts +1 -1
  12. package/dist/advanced/proof-run-engine.d.ts +1 -1
  13. package/dist/advanced/proof-run-engine.js +2 -2
  14. package/dist/advanced/runner.js +5 -5
  15. package/dist/checkpoint.cjs +3 -1
  16. package/dist/checkpoint.js +1 -1
  17. package/dist/{chunk-VZD5LH7U.js → chunk-OIFHYMHP.js} +2 -2
  18. package/dist/{chunk-TJ63IE65.js → chunk-RV6LK7HU.js} +12 -0
  19. package/dist/{chunk-2CFVREFI.js → chunk-SKIAZTQ7.js} +3 -1
  20. package/dist/{chunk-BTN76IGW.js → chunk-SMBZT46I.js} +1 -1
  21. package/dist/{chunk-OHJQRDST.js → chunk-TNCDVE5O.js} +1 -1
  22. package/dist/{chunk-BHL4JSGM.js → chunk-TZ3YMCDM.js} +8 -1
  23. package/dist/{chunk-Y2KTBACQ.js → chunk-U4FUFBSH.js} +1 -1
  24. package/dist/{chunk-IWLQQ5S5.js → chunk-YB5ACBZE.js} +7 -7
  25. package/dist/{chunk-COERZX63.js → chunk-ZX45XGDJ.js} +2 -2
  26. package/dist/cli/index.js +6 -6
  27. package/dist/cli.cjs +25 -4
  28. package/dist/cli.js +6 -6
  29. package/dist/engine-harness.cjs +25 -4
  30. package/dist/engine-harness.js +5 -5
  31. package/dist/index.cjs +25 -4
  32. package/dist/index.js +6 -6
  33. package/dist/openclaw.js +4 -4
  34. package/dist/proof-run-core.cjs +12 -0
  35. package/dist/proof-run-core.js +1 -1
  36. package/dist/{proof-run-engine-CSSc0mNn.d.ts → proof-run-engine-BVkeO-Yo.d.ts} +3 -3
  37. package/dist/{proof-run-engine-HSRpUeBi.d.cts → proof-run-engine-CVnboNHj.d.cts} +3 -3
  38. package/dist/proof-run-engine.cjs +19 -0
  39. package/dist/proof-run-engine.d.cts +1 -1
  40. package/dist/proof-run-engine.d.ts +1 -1
  41. package/dist/proof-run-engine.js +2 -2
  42. package/dist/run-card.js +2 -2
  43. package/dist/runner.js +5 -5
  44. package/dist/spec/checkpoint.cjs +3 -1
  45. package/dist/spec/checkpoint.js +1 -1
  46. package/dist/spec/index.cjs +3 -1
  47. package/dist/spec/index.js +3 -3
  48. package/dist/spec/run-card.js +2 -2
  49. package/dist/spec/state.js +3 -3
  50. package/dist/state.js +3 -3
  51. package/dist/types.d.cts +1 -0
  52. package/dist/types.d.ts +1 -0
  53. package/package.json +1 -1
  54. package/runtime/lib/author.py +32 -0
  55. package/runtime/lib/setup.py +3 -0
  56. package/runtime/lib/verify.py +247 -8
  57. package/runtime/tests/recon_verify_smoke.py +306 -8
@@ -228,6 +228,133 @@ class FakeRiddle:
228
228
  'RIDDLE_PROOF_EVIDENCE:' + json.dumps(proof_evidence),
229
229
  ],
230
230
  }
231
+ if 'prod.example.com/pricing' in script:
232
+ search = '?plan=pro' if 'plan=pro' in script else ''
233
+ return {
234
+ 'ok': True,
235
+ 'screenshots': [{'url': 'https://cdn.example.com/prod.png'}],
236
+ 'outputs': [{'name': 'prod.png', 'url': 'https://cdn.example.com/prod.png'}],
237
+ 'console': state_console({
238
+ 'bodyTextLength': 180,
239
+ 'visibleTextSample': 'Pricing CTA Buy Now',
240
+ 'interactiveElements': 4,
241
+ 'visibleInteractiveElements': 4,
242
+ 'pathname': '/pricing',
243
+ 'search': search,
244
+ 'title': 'Prod',
245
+ 'buttons': ['Buy Now'],
246
+ 'headings': ['Pricing'],
247
+ 'links': [],
248
+ 'canvasCount': 0,
249
+ 'largeVisibleElements': [{'tag': 'button', 'text': 'Buy Now'}],
250
+ }),
251
+ }
252
+ if 'clickedProofNavigation' in script:
253
+ page_state = {
254
+ 'bodyTextLength': 180,
255
+ 'visibleTextSample': 'Proof page Evidence Accepted',
256
+ 'interactiveElements': 2,
257
+ 'visibleInteractiveElements': 2,
258
+ 'pathname': '/proof/',
259
+ 'title': 'Proof',
260
+ 'buttons': ['Proof'],
261
+ 'headings': ['Proof'],
262
+ 'links': [],
263
+ 'canvasCount': 0,
264
+ 'largeVisibleElements': [{'tag': 'h1', 'text': 'Proof'}],
265
+ }
266
+ proof_evidence = {
267
+ 'before': {'path': '/'},
268
+ 'action': 'clicked Proof',
269
+ 'after': {'path': '/proof/'},
270
+ 'assertions': {
271
+ 'startedOnHome': True,
272
+ 'clickedProofNavigation': True,
273
+ 'terminalPathIsProof': True,
274
+ 'proofContentVisible': True,
275
+ },
276
+ }
277
+ return {
278
+ 'ok': True,
279
+ 'screenshots': [{'url': 'https://cdn.example.com/proof-after.png'}],
280
+ 'outputs': [{'name': 'after-proof.png', 'url': 'https://cdn.example.com/proof-after.png'}],
281
+ 'result': {'pageState': page_state, 'proofEvidence': proof_evidence},
282
+ 'console': [
283
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
284
+ 'RIDDLE_PROOF_EVIDENCE:' + json.dumps(proof_evidence),
285
+ ],
286
+ 'visual_diff': {
287
+ 'diffPercentage': 1.2,
288
+ 'differentPixels': 12000,
289
+ 'totalPixels': 972000,
290
+ },
291
+ }
292
+ if 'clickedHomeNavigation' in script:
293
+ page_state = {
294
+ 'bodyTextLength': 180,
295
+ 'visibleTextSample': 'Riddle Proof homepage hero Start Free',
296
+ 'interactiveElements': 4,
297
+ 'visibleInteractiveElements': 4,
298
+ 'pathname': '/',
299
+ 'title': 'Riddle',
300
+ 'buttons': ['Start Free'],
301
+ 'headings': ['Riddle Proof'],
302
+ 'links': [],
303
+ 'canvasCount': 0,
304
+ 'largeVisibleElements': [{'tag': 'h1', 'text': 'Riddle Proof'}],
305
+ }
306
+ proof_evidence = {
307
+ 'before': {'path': '/proof/'},
308
+ 'action': 'clicked Home',
309
+ 'after': {'path': '/'},
310
+ 'assertions': {
311
+ 'startedOnProof': True,
312
+ 'clickedHomeNavigation': True,
313
+ 'terminalPathIsHome': True,
314
+ 'homeContentVisible': True,
315
+ },
316
+ }
317
+ return {
318
+ 'ok': True,
319
+ 'screenshots': [{'url': 'https://cdn.example.com/home-after.png'}],
320
+ 'outputs': [{'name': 'after-home.png', 'url': 'https://cdn.example.com/home-after.png'}],
321
+ 'result': {'pageState': page_state, 'proofEvidence': proof_evidence},
322
+ 'console': [
323
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
324
+ 'RIDDLE_PROOF_EVIDENCE:' + json.dumps(proof_evidence),
325
+ ],
326
+ 'visual_diff': {
327
+ 'diffPercentage': 1.2,
328
+ 'differentPixels': 12000,
329
+ 'totalPixels': 972000,
330
+ },
331
+ }
332
+ if 'skipLinkTimeout' in script:
333
+ message = 'locator.click: Timeout 30000ms exceeded'
334
+ page_state = {
335
+ 'bodyTextLength': 180,
336
+ 'visibleTextSample': 'Riddle Proof homepage hero Start Free',
337
+ 'interactiveElements': 4,
338
+ 'visibleInteractiveElements': 4,
339
+ 'pathname': '/',
340
+ 'title': 'Riddle',
341
+ 'buttons': ['Start Free'],
342
+ 'headings': ['Riddle Proof'],
343
+ 'links': [],
344
+ 'canvasCount': 0,
345
+ 'largeVisibleElements': [{'tag': 'h1', 'text': 'Riddle Proof'}],
346
+ }
347
+ return {
348
+ 'ok': True,
349
+ 'result': {'pageState': page_state},
350
+ 'console': [
351
+ 'RIDDLE_PROOF_STATE:' + json.dumps(page_state),
352
+ message,
353
+ ],
354
+ '_artifact_json': {
355
+ 'proof.json': {'script_error': message},
356
+ },
357
+ }
231
358
  if 'after-proof' in script:
232
359
  after_url = 'https://cdn.example.com/after-artifact' if 'noVisualDelta' in script else 'https://cdn.example.com/after.png'
233
360
  outputs = [{'name': 'after.png', 'url': after_url}]
@@ -258,13 +385,6 @@ class FakeRiddle:
258
385
  'totalPixels': 972000,
259
386
  }
260
387
  return payload
261
- if 'prod.example.com/pricing' in script:
262
- return {
263
- 'ok': True,
264
- 'screenshots': [{'url': 'https://cdn.example.com/prod.png'}],
265
- 'outputs': [{'name': 'prod.png', 'url': 'https://cdn.example.com/prod.png'}],
266
- 'console': ['RIDDLE_PROOF_STATE:{"bodyTextLength":180,"interactiveElements":4,"pathname":"/pricing","title":"Prod"}'],
267
- }
268
388
  if 'prod.example.com/games/drum-sequencer' in script:
269
389
  page_state = {
270
390
  'bodyTextLength': 240,
@@ -1076,7 +1196,9 @@ def run_remote_audit_setup_without_repo():
1076
1196
  assert state['server_path'] == '/pricing?plan=pro'
1077
1197
  assert state['recon_status'] == 'ready_for_proof_plan'
1078
1198
  assert state['proof_plan_status'] == 'ready'
1079
- return {'ok': True, 'server_path': state['server_path']}
1199
+ assert state['capture_script'] == 'await page.waitForTimeout(1500);'
1200
+ assert state['capture_script_source'] == 'default_remote_audit_current_target'
1201
+ return {'ok': True, 'server_path': state['server_path'], 'capture_script_source': state['capture_script_source']}
1080
1202
  finally:
1081
1203
  sys.modules.pop('util', None)
1082
1204
  shutil.rmtree(tempdir, ignore_errors=True)
@@ -2126,6 +2248,178 @@ def run_verify_capture_retry():
2126
2248
  shutil.rmtree(tempdir, ignore_errors=True)
2127
2249
 
2128
2250
 
2251
+ def run_remote_audit_verify_uses_default_capture_script():
2252
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-remote-audit-verify-'))
2253
+ state_path = tempdir / 'state.json'
2254
+ try:
2255
+ state = base_state(tempdir, reference='prod', prod_url='https://prod.example.com/pricing?plan=pro')
2256
+ state.update({
2257
+ 'remote_audit': True,
2258
+ 'workspace_kind': 'remote_audit',
2259
+ 'mode': 'server',
2260
+ 'recon_status': 'ready_for_proof_plan',
2261
+ 'author_status': 'ready',
2262
+ 'proof_plan_status': 'ready',
2263
+ 'implementation_status': 'not_required',
2264
+ 'implementation_mode': 'none',
2265
+ 'require_diff': False,
2266
+ 'allow_code_changes': False,
2267
+ 'server_path': '/pricing?plan=pro',
2268
+ 'proof_plan': 'Audit the current pricing target.',
2269
+ 'capture_script': '',
2270
+ 'recon_results': {'baselines': {}, 'mode': 'remote_audit'},
2271
+ })
2272
+ write_state(state_path, state)
2273
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2274
+
2275
+ fake = FakeRiddle()
2276
+ load_util_with_fake(fake)
2277
+ load_module('verify_remote_audit_default_capture', VERIFY_PATH)
2278
+ after_verify = json.loads(state_path.read_text())
2279
+
2280
+ assert after_verify['verify_status'] == 'evidence_captured'
2281
+ assert after_verify['capture_script'] == 'await page.waitForTimeout(1500);'
2282
+ assert after_verify['capture_script_source'] == 'default_remote_audit_current_target'
2283
+ assert after_verify['after_cdn'] == 'https://cdn.example.com/prod.png'
2284
+ assert after_verify['evidence_bundle']['after']['visual_delta']['status'] == 'not_applicable'
2285
+ assert after_verify['verify_decision_request']['expected_path'] == '/pricing?plan=pro'
2286
+ return {
2287
+ 'ok': True,
2288
+ 'verify_status': after_verify['verify_status'],
2289
+ 'capture_script_source': after_verify['capture_script_source'],
2290
+ }
2291
+ finally:
2292
+ shutil.rmtree(tempdir, ignore_errors=True)
2293
+
2294
+
2295
+ def run_verify_interaction_terminal_route_from_proof_evidence():
2296
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-forward-'))
2297
+ state_path = tempdir / 'state.json'
2298
+ try:
2299
+ state = base_state(tempdir, reference='before')
2300
+ state.update({
2301
+ 'recon_status': 'ready_for_proof_plan',
2302
+ 'author_status': 'ready',
2303
+ 'proof_plan_status': 'ready',
2304
+ 'implementation_status': 'changes_detected',
2305
+ 'verification_mode': 'interaction',
2306
+ 'server_path': '/',
2307
+ 'before_cdn': 'https://cdn.example.com/before-home.png',
2308
+ 'proof_plan': 'Start at /, click Proof, and verify the terminal /proof/ route.',
2309
+ 'capture_script': "clickedProofNavigation(); await saveScreenshot('after-proof');",
2310
+ 'recon_results': {
2311
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before-home.png'}},
2312
+ },
2313
+ })
2314
+ write_state(state_path, state)
2315
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2316
+
2317
+ fake = FakeRiddle()
2318
+ load_util_with_fake(fake)
2319
+ load_module('verify_interaction_terminal_route', VERIFY_PATH)
2320
+ after_verify = json.loads(state_path.read_text())
2321
+
2322
+ assert after_verify['verify_status'] == 'evidence_captured'
2323
+ assert after_verify['route_expectation']['start_path'] == '/'
2324
+ assert after_verify['route_expectation']['expected_path'] == '/proof'
2325
+ assert after_verify['route_expectation']['source'] == 'proof_evidence_contract'
2326
+ route = after_verify['proof_assessment_request']['semantic_context']['route']
2327
+ assert route['expected_start_path'] == '/'
2328
+ assert route['expected_after_path'] == '/proof'
2329
+ assert route['after_observed_path'] == '/proof'
2330
+ assert 'wrong route' not in after_verify['verify_results']['after']['observation']['reason']
2331
+ return {
2332
+ 'ok': True,
2333
+ 'expected_path': after_verify['route_expectation']['expected_path'],
2334
+ 'after_observed_path': route['after_observed_path'],
2335
+ }
2336
+ finally:
2337
+ shutil.rmtree(tempdir, ignore_errors=True)
2338
+
2339
+
2340
+ def run_verify_interaction_reverse_terminal_route_from_proof_evidence():
2341
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-reverse-'))
2342
+ state_path = tempdir / 'state.json'
2343
+ try:
2344
+ state = base_state(tempdir, reference='before')
2345
+ state.update({
2346
+ 'recon_status': 'ready_for_proof_plan',
2347
+ 'author_status': 'ready',
2348
+ 'proof_plan_status': 'ready',
2349
+ 'implementation_status': 'changes_detected',
2350
+ 'verification_mode': 'interaction',
2351
+ 'server_path': '/proof/',
2352
+ 'before_cdn': 'https://cdn.example.com/before-proof.png',
2353
+ 'proof_plan': 'Start at /proof/, click Home, and verify the terminal / route.',
2354
+ 'capture_script': "clickedHomeNavigation(); await saveScreenshot('after-home');",
2355
+ 'recon_results': {
2356
+ 'baselines': {'before': {'path': '/proof/', 'url': 'https://cdn.example.com/before-proof.png'}},
2357
+ },
2358
+ })
2359
+ write_state(state_path, state)
2360
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2361
+
2362
+ fake = FakeRiddle()
2363
+ load_util_with_fake(fake)
2364
+ load_module('verify_interaction_reverse_terminal_route', VERIFY_PATH)
2365
+ after_verify = json.loads(state_path.read_text())
2366
+
2367
+ assert after_verify['verify_status'] == 'evidence_captured'
2368
+ assert after_verify['route_expectation']['start_path'] == '/proof'
2369
+ assert after_verify['route_expectation']['expected_path'] == '/'
2370
+ route = after_verify['proof_assessment_request']['semantic_context']['route']
2371
+ assert route['expected_start_path'] == '/proof'
2372
+ assert route['expected_after_path'] == '/'
2373
+ assert route['after_observed_path'] == '/'
2374
+ assert 'wrong route' not in after_verify['verify_results']['after']['observation']['reason']
2375
+ return {
2376
+ 'ok': True,
2377
+ 'expected_path': after_verify['route_expectation']['expected_path'],
2378
+ 'after_observed_path': route['after_observed_path'],
2379
+ }
2380
+ finally:
2381
+ shutil.rmtree(tempdir, ignore_errors=True)
2382
+
2383
+
2384
+ def run_verify_capture_retry_surfaces_script_timeout():
2385
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-capture-timeout-'))
2386
+ state_path = tempdir / 'state.json'
2387
+ try:
2388
+ state = base_state(tempdir, reference='before')
2389
+ state.update({
2390
+ 'recon_status': 'ready_for_proof_plan',
2391
+ 'author_status': 'ready',
2392
+ 'proof_plan_status': 'ready',
2393
+ 'implementation_status': 'changes_detected',
2394
+ 'before_cdn': 'https://cdn.example.com/before.png',
2395
+ 'proof_plan': 'Click the skip link and capture the resulting focus state.',
2396
+ 'capture_script': "skipLinkTimeout();",
2397
+ 'recon_results': {
2398
+ 'baselines': {'before': {'path': '/', 'url': 'https://cdn.example.com/before.png'}},
2399
+ },
2400
+ 'server_path': '/',
2401
+ })
2402
+ write_state(state_path, state)
2403
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2404
+
2405
+ fake = FakeRiddle()
2406
+ load_util_with_fake(fake)
2407
+ load_module('verify_capture_timeout_summary', VERIFY_PATH)
2408
+ after_verify = json.loads(state_path.read_text())
2409
+
2410
+ assert after_verify['verify_status'] == 'capture_incomplete'
2411
+ capture_quality = after_verify['verify_decision_request']['capture_quality']
2412
+ assert capture_quality['recommended_stage'] == 'author'
2413
+ assert 'locator.click: Timeout 30000ms exceeded' in capture_quality['summary']
2414
+ assert any('locator.click: Timeout 30000ms exceeded' in reason for reason in capture_quality['reasons'])
2415
+ return {
2416
+ 'ok': True,
2417
+ 'summary': capture_quality['summary'],
2418
+ }
2419
+ finally:
2420
+ shutil.rmtree(tempdir, ignore_errors=True)
2421
+
2422
+
2129
2423
  def run_verify_missing_baseline():
2130
2424
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-missing-baseline-'))
2131
2425
  state_path = tempdir / 'state.json'
@@ -2501,6 +2795,10 @@ if __name__ == '__main__':
2501
2795
  'verify_audio_rejects_failed_nested_proof_evidence': run_verify_audio_rejects_failed_nested_proof_evidence(),
2502
2796
  'verify_preserves_proof_evidence_on_capture_script_error': run_verify_preserves_proof_evidence_on_capture_script_error(),
2503
2797
  'verify_capture_retry': run_verify_capture_retry(),
2798
+ 'remote_audit_verify_uses_default_capture_script': run_remote_audit_verify_uses_default_capture_script(),
2799
+ 'verify_interaction_terminal_route_from_proof_evidence': run_verify_interaction_terminal_route_from_proof_evidence(),
2800
+ 'verify_interaction_reverse_terminal_route_from_proof_evidence': run_verify_interaction_reverse_terminal_route_from_proof_evidence(),
2801
+ 'verify_capture_retry_surfaces_script_timeout': run_verify_capture_retry_surfaces_script_timeout(),
2504
2802
  'missing_baseline_guard': run_verify_missing_baseline(),
2505
2803
  'ship_supervisor_gate': run_ship_missing_supervisor_gate(),
2506
2804
  'ship_blocks_unmeasured_visual_delta': run_ship_blocks_unmeasured_visual_delta(),