@riddledc/riddle-proof 0.5.32 → 0.5.34
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/{chunk-R4BPJNAM.js → chunk-4YCWZVBN.js} +101 -8
- package/dist/{chunk-LIDYNU7Q.js → chunk-7R6ZQE3X.js} +39 -2
- package/dist/{chunk-TMMKRKY5.js → chunk-J2MERROF.js} +1 -0
- package/dist/{chunk-F6VFKS7K.js → chunk-MQ2BHHLX.js} +2 -2
- package/dist/{chunk-7ZJAUEUN.js → chunk-OASB3CYU.js} +6 -1
- package/dist/chunk-ODORKNSO.js +121 -0
- package/dist/engine-harness.cjs +143 -9
- package/dist/engine-harness.js +4 -3
- package/dist/index.cjs +271 -11
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +24 -7
- package/dist/openclaw.cjs +5 -0
- package/dist/openclaw.js +2 -2
- package/dist/proof-run-core.cjs +104 -8
- package/dist/proof-run-core.d.cts +24 -1
- package/dist/proof-run-core.d.ts +24 -1
- package/dist/proof-run-core.js +7 -1
- package/dist/proof-run-engine.cjs +101 -8
- package/dist/proof-run-engine.d.cts +24 -0
- package/dist/proof-run-engine.d.ts +24 -0
- package/dist/proof-run-engine.js +4 -1
- package/dist/proof-session.cjs +151 -0
- package/dist/proof-session.d.cts +37 -0
- package/dist/proof-session.d.ts +37 -0
- package/dist/proof-session.js +18 -0
- package/dist/result.cjs +1 -0
- package/dist/result.js +1 -1
- package/dist/runner.cjs +6 -0
- package/dist/runner.js +3 -3
- package/dist/state.cjs +5 -0
- package/dist/state.js +2 -2
- package/dist/types.d.cts +67 -1
- package/dist/types.d.ts +67 -1
- package/package.json +7 -2
- package/runtime/lib/preflight.py +42 -2
- package/runtime/lib/ship.py +55 -1
- package/runtime/lib/util.py +237 -0
- package/runtime/lib/verify.py +93 -6
- package/runtime/tests/recon_verify_smoke.py +181 -3
|
@@ -204,10 +204,13 @@ class FakeRiddle:
|
|
|
204
204
|
],
|
|
205
205
|
}
|
|
206
206
|
if 'after-proof' in script:
|
|
207
|
+
outputs = [{'name': 'after.png', 'url': 'https://cdn.example.com/after.png'}]
|
|
208
|
+
if 'proof-session' in script:
|
|
209
|
+
outputs.append({'name': 'proof-session.json', 'url': 'https://cdn.example.com/proof-session.json'})
|
|
207
210
|
return {
|
|
208
211
|
'ok': True,
|
|
209
212
|
'screenshots': [{'url': 'https://cdn.example.com/after.png'}],
|
|
210
|
-
'outputs':
|
|
213
|
+
'outputs': outputs,
|
|
211
214
|
'console': state_console({
|
|
212
215
|
'bodyTextLength': 180,
|
|
213
216
|
'visibleTextSample': 'Pricing CTA Buy Now',
|
|
@@ -637,6 +640,105 @@ def run_preflight_records_prod_reference_skip_reason():
|
|
|
637
640
|
shutil.rmtree(tempdir, ignore_errors=True)
|
|
638
641
|
|
|
639
642
|
|
|
643
|
+
def run_preflight_resumes_visual_proof_session():
|
|
644
|
+
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-preflight-session-'))
|
|
645
|
+
args_path = tempdir / 'args.json'
|
|
646
|
+
state_path = tempdir / 'state.json'
|
|
647
|
+
repo_dir = tempdir / 'repo'
|
|
648
|
+
try:
|
|
649
|
+
make_project(repo_dir, "export const routes = [{ path: '/pricing', element: <Pricing /> }];\n")
|
|
650
|
+
util = load_module('util_proof_session_builder', UTIL_PATH)
|
|
651
|
+
parent_session = util.build_visual_proof_session({
|
|
652
|
+
'repo': 'example/repo',
|
|
653
|
+
'server_path': '/pricing',
|
|
654
|
+
'reference': 'before',
|
|
655
|
+
'verification_mode': 'visual',
|
|
656
|
+
'target_image_url': 'https://cdn.example.com/spec.png',
|
|
657
|
+
'target_image_hash': 'sha256:spec',
|
|
658
|
+
'viewport_matrix': [
|
|
659
|
+
{'name': 'mobile', 'width': 390, 'height': 844},
|
|
660
|
+
{'name': 'desktop', 'width': 1280, 'height': 900},
|
|
661
|
+
],
|
|
662
|
+
'deterministic_setup': {'seed': 'pricing-visual-v1'},
|
|
663
|
+
'parsed_assertions': [{'kind': 'text', 'contains': 'Buy Now'}],
|
|
664
|
+
'proof_plan': 'Capture pricing route and compare CTA visual state.',
|
|
665
|
+
'capture_script': "await page.waitForSelector('[data-testid=pricing-cta]'); await saveScreenshot('after-proof');",
|
|
666
|
+
'wait_for_selector': '[data-testid=pricing-cta]',
|
|
667
|
+
}, route='/pricing', observed_after_path='/pricing', status='evidence_captured')
|
|
668
|
+
|
|
669
|
+
args_path.write_text(json.dumps({
|
|
670
|
+
'repo': 'example/repo',
|
|
671
|
+
'repo_dir': str(repo_dir),
|
|
672
|
+
'mode': 'static',
|
|
673
|
+
'change_request': 'Continue the pricing visual iteration',
|
|
674
|
+
'commit_message': 'Continue the pricing visual iteration',
|
|
675
|
+
'build_command': BUILD_SCRIPT,
|
|
676
|
+
'build_output': 'build',
|
|
677
|
+
'allow_static_preview_fallback': True,
|
|
678
|
+
'resume_session': json.dumps(parent_session),
|
|
679
|
+
}, indent=2))
|
|
680
|
+
with temporary_env(
|
|
681
|
+
RIDDLE_PROOF_ARGS_FILE=str(args_path),
|
|
682
|
+
RIDDLE_PROOF_STATE_FILE=str(state_path),
|
|
683
|
+
):
|
|
684
|
+
sys.modules.pop('util', None)
|
|
685
|
+
load_module('preflight_resume_session', PREFLIGHT_PATH)
|
|
686
|
+
after_preflight = json.loads(state_path.read_text())
|
|
687
|
+
assert after_preflight['proof_session_resume']['status'] == 'accepted'
|
|
688
|
+
assert after_preflight['proof_session_resume']['applied_fields']
|
|
689
|
+
assert after_preflight['parent_proof_session']['session_id'] == parent_session['session_id']
|
|
690
|
+
assert after_preflight['server_path'] == '/pricing'
|
|
691
|
+
assert after_preflight['server_path_source'] == 'proof_session'
|
|
692
|
+
assert after_preflight['reference'] == 'before'
|
|
693
|
+
assert after_preflight['verification_mode'] == 'visual'
|
|
694
|
+
assert after_preflight['target_image_url'] == 'https://cdn.example.com/spec.png'
|
|
695
|
+
assert after_preflight['target_image_hash'] == 'sha256:spec'
|
|
696
|
+
assert after_preflight['viewport_matrix'][0]['name'] == 'mobile'
|
|
697
|
+
assert after_preflight['deterministic_setup']['seed'] == 'pricing-visual-v1'
|
|
698
|
+
assert after_preflight['parsed_assertions'][0]['contains'] == 'Buy Now'
|
|
699
|
+
assert after_preflight['proof_plan_status'] == 'ready'
|
|
700
|
+
assert after_preflight['author_status'] == 'ready'
|
|
701
|
+
|
|
702
|
+
mismatch_args_path = tempdir / 'mismatch-args.json'
|
|
703
|
+
mismatch_state_path = tempdir / 'mismatch-state.json'
|
|
704
|
+
mismatch_args_path.write_text(json.dumps({
|
|
705
|
+
'repo': 'example/repo',
|
|
706
|
+
'repo_dir': str(repo_dir),
|
|
707
|
+
'mode': 'static',
|
|
708
|
+
'reference': 'before',
|
|
709
|
+
'verification_mode': 'visual',
|
|
710
|
+
'change_request': 'Continue the pricing visual iteration',
|
|
711
|
+
'commit_message': 'Continue the pricing visual iteration',
|
|
712
|
+
'build_command': BUILD_SCRIPT,
|
|
713
|
+
'build_output': 'build',
|
|
714
|
+
'allow_static_preview_fallback': True,
|
|
715
|
+
'server_path': '/wrong',
|
|
716
|
+
'resume_session': json.dumps(parent_session),
|
|
717
|
+
}, indent=2))
|
|
718
|
+
with temporary_env(
|
|
719
|
+
RIDDLE_PROOF_ARGS_FILE=str(mismatch_args_path),
|
|
720
|
+
RIDDLE_PROOF_STATE_FILE=str(mismatch_state_path),
|
|
721
|
+
):
|
|
722
|
+
try:
|
|
723
|
+
sys.modules.pop('util', None)
|
|
724
|
+
load_module('preflight_resume_session_mismatch', PREFLIGHT_PATH)
|
|
725
|
+
except SystemExit as exc:
|
|
726
|
+
assert 'fingerprint mismatch' in str(exc), exc
|
|
727
|
+
else:
|
|
728
|
+
raise AssertionError('route mismatch should reject resumed proof session')
|
|
729
|
+
mismatch_state = json.loads(mismatch_state_path.read_text())
|
|
730
|
+
assert mismatch_state['proof_session_resume']['status'] == 'fingerprint_mismatch'
|
|
731
|
+
assert any(item['key'] == 'route' for item in mismatch_state['proof_session_resume']['mismatches'])
|
|
732
|
+
|
|
733
|
+
return {
|
|
734
|
+
'ok': True,
|
|
735
|
+
'parent_session_id': parent_session['session_id'],
|
|
736
|
+
'fingerprint': after_preflight['proof_session_resume']['fingerprint'],
|
|
737
|
+
}
|
|
738
|
+
finally:
|
|
739
|
+
shutil.rmtree(tempdir, ignore_errors=True)
|
|
740
|
+
|
|
741
|
+
|
|
640
742
|
def base_state(tempdir: Path, *, reference='before', prod_url=''):
|
|
641
743
|
before_dir = tempdir / 'before'
|
|
642
744
|
after_dir = tempdir / 'after'
|
|
@@ -1157,6 +1259,7 @@ def run_verify_requests_supervisor_assessment():
|
|
|
1157
1259
|
try:
|
|
1158
1260
|
state = base_state(tempdir, reference='both', prod_url='https://prod.example.com/pricing')
|
|
1159
1261
|
state.update({
|
|
1262
|
+
'repo': 'example/repo',
|
|
1160
1263
|
'recon_status': 'ready_for_proof_plan',
|
|
1161
1264
|
'author_status': 'ready',
|
|
1162
1265
|
'proof_plan_status': 'ready',
|
|
@@ -1200,17 +1303,19 @@ def run_verify_requests_supervisor_assessment():
|
|
|
1200
1303
|
artifact_contract = after_verify['proof_assessment_request']['artifact_contract']
|
|
1201
1304
|
assert artifact_contract['required']['baseline_context'] is True
|
|
1202
1305
|
assert artifact_contract['required']['screenshot'] is True
|
|
1306
|
+
assert artifact_contract['required']['visual_delta'] is True
|
|
1203
1307
|
artifact_production = after_verify['proof_assessment_request']['artifact_production']
|
|
1204
1308
|
assert artifact_production['image_output_count'] >= 1
|
|
1205
1309
|
assert artifact_production['proof_evidence_present'] is False
|
|
1206
1310
|
artifact_usage = after_verify['proof_assessment_request']['artifact_usage']
|
|
1207
|
-
assert artifact_usage['missing_required_signals'] == []
|
|
1311
|
+
assert artifact_usage['missing_required_signals'] == ['visual_delta']
|
|
1208
1312
|
assert 'after-capture' in artifact_usage['supervisor_review_signals']
|
|
1209
1313
|
assert 'baseline_context' in artifact_usage['required_signals']
|
|
1210
1314
|
assert 'route_semantics' in artifact_usage['available_signals']
|
|
1315
|
+
assert 'visual_delta.status=unmeasured' in after_verify['proof_assessment_request']['hard_blockers'][0]
|
|
1211
1316
|
assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_contract']['required']['screenshot'] is True
|
|
1212
1317
|
assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_production']['image_output_count'] >= 1
|
|
1213
|
-
assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_usage']['missing_required_signals'] == []
|
|
1318
|
+
assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_usage']['missing_required_signals'] == ['visual_delta']
|
|
1214
1319
|
assert 'capture success is not proof' in '\n'.join(after_verify['proof_assessment_request']['instructions'])
|
|
1215
1320
|
assert after_verify['verify_decision_request']['continue_with_stage'] is None
|
|
1216
1321
|
assert after_verify['verify_results']['baseline']['before']['source'] == 'recon'
|
|
@@ -1221,6 +1326,21 @@ def run_verify_requests_supervisor_assessment():
|
|
|
1221
1326
|
assert after_details['observed_path_raw'] == '/s/pv-after/pricing', after_details
|
|
1222
1327
|
assert 'Buy Now' in after_details['visible_text_sample'], after_details
|
|
1223
1328
|
assert after_details['buttons'] == ['Buy Now'], after_details
|
|
1329
|
+
proof_session = after_verify['proof_session']
|
|
1330
|
+
assert proof_session['version'] == 'riddle-proof.visual-session.v1'
|
|
1331
|
+
assert proof_session['repo'] == 'example/repo'
|
|
1332
|
+
assert proof_session['route']['path'] == '/pricing'
|
|
1333
|
+
assert proof_session['route']['observed_after_path'] == '/pricing'
|
|
1334
|
+
assert proof_session['artifacts']['before'] == 'https://cdn.example.com/before.png'
|
|
1335
|
+
assert proof_session['artifacts']['prod'] == 'https://cdn.example.com/prod.png'
|
|
1336
|
+
assert proof_session['artifacts']['after'] == 'https://cdn.example.com/after.png'
|
|
1337
|
+
assert proof_session['artifacts']['session'] == 'https://cdn.example.com/proof-session.json'
|
|
1338
|
+
assert proof_session['capture']['wait_for_selector'] == '[data-testid=pricing-cta]'
|
|
1339
|
+
assert proof_session['fingerprint_basis']['route'] == '/pricing'
|
|
1340
|
+
assert after_verify['proof_session_fingerprint'] == proof_session['fingerprint']
|
|
1341
|
+
assert after_verify['proof_session_artifact_url'] == 'https://cdn.example.com/proof-session.json'
|
|
1342
|
+
assert after_verify['evidence_bundle']['proof_session']['fingerprint'] == proof_session['fingerprint']
|
|
1343
|
+
assert after_verify['proof_assessment_request']['evidence_bundle']['proof_session']['fingerprint'] == proof_session['fingerprint']
|
|
1224
1344
|
runtime_events = after_verify.get('runtime_events') or []
|
|
1225
1345
|
assert any(event.get('kind') == 'workflow.phase.started' and event.get('step') == 'verify' and event.get('phase') == 'build' for event in runtime_events)
|
|
1226
1346
|
assert any(event.get('kind') == 'workflow.phase.finished' and event.get('step') == 'verify' and event.get('phase') == 'build' for event in runtime_events)
|
|
@@ -1573,6 +1693,62 @@ def run_ship_missing_supervisor_gate():
|
|
|
1573
1693
|
shutil.rmtree(tempdir, ignore_errors=True)
|
|
1574
1694
|
|
|
1575
1695
|
|
|
1696
|
+
def run_ship_blocks_unmeasured_visual_delta():
|
|
1697
|
+
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-ship-visual-delta-'))
|
|
1698
|
+
state_path = tempdir / 'state.json'
|
|
1699
|
+
try:
|
|
1700
|
+
state = base_state(tempdir, reference='before')
|
|
1701
|
+
state.update({
|
|
1702
|
+
'recon_status': 'ready_for_proof_plan',
|
|
1703
|
+
'author_status': 'ready',
|
|
1704
|
+
'proof_plan_status': 'ready',
|
|
1705
|
+
'implementation_status': 'changes_detected',
|
|
1706
|
+
'verification_mode': 'visual',
|
|
1707
|
+
'verify_status': 'evidence_captured',
|
|
1708
|
+
'before_cdn': 'https://cdn.example.com/before.png',
|
|
1709
|
+
'after_cdn': 'https://cdn.example.com/after.png',
|
|
1710
|
+
'proof_assessment': {
|
|
1711
|
+
'decision': 'ready_to_ship',
|
|
1712
|
+
'summary': 'The screenshots look good.',
|
|
1713
|
+
'source': 'supervising_agent',
|
|
1714
|
+
},
|
|
1715
|
+
'proof_assessment_source': 'supervising_agent',
|
|
1716
|
+
'evidence_bundle': {
|
|
1717
|
+
'verification_mode': 'visual',
|
|
1718
|
+
'artifact_contract': {
|
|
1719
|
+
'required': {
|
|
1720
|
+
'baseline_context': True,
|
|
1721
|
+
'route_semantics': True,
|
|
1722
|
+
'screenshot': True,
|
|
1723
|
+
'visual_delta': True,
|
|
1724
|
+
},
|
|
1725
|
+
},
|
|
1726
|
+
'after': {
|
|
1727
|
+
'screenshot_url': 'https://cdn.example.com/after.png',
|
|
1728
|
+
'observation': {'valid': True, 'reason': 'ok'},
|
|
1729
|
+
'visual_delta': {
|
|
1730
|
+
'status': 'unmeasured',
|
|
1731
|
+
'passed': None,
|
|
1732
|
+
'reason': 'No measured before/after visual delta was found in proof evidence.',
|
|
1733
|
+
},
|
|
1734
|
+
},
|
|
1735
|
+
},
|
|
1736
|
+
})
|
|
1737
|
+
write_state(state_path, state)
|
|
1738
|
+
os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
|
|
1739
|
+
|
|
1740
|
+
try:
|
|
1741
|
+
load_module('ship_blocks_unmeasured_visual_delta', SHIP_PATH)
|
|
1742
|
+
except SystemExit as exc:
|
|
1743
|
+
message = str(exc)
|
|
1744
|
+
assert 'visual_delta.status=unmeasured' in message, message
|
|
1745
|
+
assert 'blocks ready_to_ship' in message, message
|
|
1746
|
+
return {'ok': True, 'error': message}
|
|
1747
|
+
raise AssertionError('ship should have failed when visual delta was unmeasured')
|
|
1748
|
+
finally:
|
|
1749
|
+
shutil.rmtree(tempdir, ignore_errors=True)
|
|
1750
|
+
|
|
1751
|
+
|
|
1576
1752
|
def run_ship_accepts_structured_after_evidence():
|
|
1577
1753
|
tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-ship-structured-'))
|
|
1578
1754
|
state_path = tempdir / 'state.json'
|
|
@@ -1808,6 +1984,7 @@ def run_ship_resolves_real_pr_branch():
|
|
|
1808
1984
|
if __name__ == '__main__':
|
|
1809
1985
|
payload = {
|
|
1810
1986
|
'preflight_reference_skip_reason': run_preflight_records_prod_reference_skip_reason(),
|
|
1987
|
+
'preflight_resume_visual_proof_session': run_preflight_resumes_visual_proof_session(),
|
|
1811
1988
|
'capture_artifact_enrichment': run_capture_artifact_enrichment(),
|
|
1812
1989
|
'capture_diagnostics_redaction': run_capture_diagnostics_redact_sensitive_values(),
|
|
1813
1990
|
'apply_auth_context': run_apply_auth_context_passes_supported_auth_payloads(),
|
|
@@ -1829,6 +2006,7 @@ if __name__ == '__main__':
|
|
|
1829
2006
|
'verify_capture_retry': run_verify_capture_retry(),
|
|
1830
2007
|
'missing_baseline_guard': run_verify_missing_baseline(),
|
|
1831
2008
|
'ship_supervisor_gate': run_ship_missing_supervisor_gate(),
|
|
2009
|
+
'ship_blocks_unmeasured_visual_delta': run_ship_blocks_unmeasured_visual_delta(),
|
|
1832
2010
|
'ship_structured_after_evidence': run_ship_accepts_structured_after_evidence(),
|
|
1833
2011
|
'ship_discord_thread_target': run_ship_discord_thread_target(),
|
|
1834
2012
|
'ship_filters_tool_noise_when_staging': run_ship_filters_tool_noise_when_staging(),
|