@riddledc/riddle-proof 0.8.27 → 0.8.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.8.27",
3
+ "version": "0.8.28",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -213,6 +213,16 @@ def audit_no_diff_mode():
213
213
  )
214
214
 
215
215
 
216
+ def interaction_verification_mode():
217
+ return str(s.get('verification_mode') or '').strip().lower() in (
218
+ 'interaction',
219
+ 'interactive',
220
+ 'user_flow',
221
+ 'user-flow',
222
+ 'workflow',
223
+ )
224
+
225
+
216
226
  def remote_audit_mode():
217
227
  return bool(s.get('remote_audit')) or (
218
228
  not repo
@@ -560,10 +570,19 @@ if remote_audit_mode():
560
570
  'keyword_hits': [],
561
571
  'max_attempts': 0,
562
572
  }
563
- s['author_status'] = 'ready'
564
- s['proof_plan_status'] = 'ready'
565
- s['proof_plan'] = (s.get('proof_plan') or 'Audit the current prod_url target and capture current evidence without requiring a repo diff.').strip()
566
- if not (s.get('capture_script') or '').strip():
573
+ has_capture_script = bool((s.get('capture_script') or '').strip())
574
+ needs_authored_interaction_capture = interaction_verification_mode() and not has_capture_script
575
+ if needs_authored_interaction_capture:
576
+ s['author_status'] = 'needs_authoring'
577
+ s['proof_plan_status'] = 'needs_authoring'
578
+ s['proof_plan'] = (s.get('proof_plan') or '').strip()
579
+ s['author_summary'] = 'Remote interaction audit requires an authored browser interaction capture before verify.'
580
+ s['capture_script_source'] = ''
581
+ else:
582
+ s['author_status'] = 'ready'
583
+ s['proof_plan_status'] = 'ready'
584
+ s['proof_plan'] = (s.get('proof_plan') or 'Audit the current prod_url target and capture current evidence without requiring a repo diff.').strip()
585
+ if not has_capture_script and not needs_authored_interaction_capture:
567
586
  s['capture_script'] = 'await page.waitForTimeout(1500);'
568
587
  s['capture_script_source'] = 'default_remote_audit_current_target'
569
588
  s['dependency_install'] = {
@@ -3711,7 +3711,47 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
3711
3711
  s = load_state()
3712
3712
  capture_script = (s.get('capture_script') or '').strip()
3713
3713
  no_implementation_mode = audit_no_diff_mode(s)
3714
- if not capture_script and no_implementation_mode:
3714
+ initial_verification_mode = normalized_verification_mode(s.get('verification_mode'))
3715
+ if not capture_script and no_implementation_mode and initial_verification_mode in INTERACTION_MODES:
3716
+ s['stage'] = 'verify'
3717
+ s['verify_status'] = 'capture_incomplete'
3718
+ s['merge_recommendation'] = 'do-not-merge'
3719
+ s['structured_interaction_capture_failure_summary'] = (
3720
+ 'Interaction verification requires an authored browser interaction capture script; '
3721
+ 'the default remote audit current-target capture is passive and cannot prove an interaction.'
3722
+ )
3723
+ s['verify_summary'] = s['structured_interaction_capture_failure_summary']
3724
+ s['proof_summary'] = s['structured_interaction_capture_failure_summary']
3725
+ s['proof_assessment'] = {}
3726
+ s['proof_assessment_source'] = None
3727
+ s['proof_assessment_request'] = {}
3728
+ s['verify_decision_request'] = {
3729
+ 'status': s['verify_status'],
3730
+ 'summary': s['structured_interaction_capture_failure_summary'],
3731
+ 'expected_path': s.get('expected_terminal_path') or s.get('requested_expected_terminal_path') or s.get('server_path') or '/',
3732
+ 'expected_start_path': s.get('expected_start_path') or s.get('server_path') or '/',
3733
+ 'route_expectation': s.get('route_expectation') or {},
3734
+ 'capture_quality': {
3735
+ 'decision': 'failed_interaction_capture',
3736
+ 'summary': s['structured_interaction_capture_failure_summary'],
3737
+ 'recommended_stage': None,
3738
+ 'continue_with_stage': None,
3739
+ 'blocking': True,
3740
+ 'terminal_blocker': True,
3741
+ 'reasons': [s['structured_interaction_capture_failure_summary']],
3742
+ },
3743
+ 'next_stage_options': ['author', 'verify', 'recon'],
3744
+ 'recommended_stage': None,
3745
+ 'continue_with_stage': None,
3746
+ 'fields_agent_may_update': ['proof_plan', 'capture_script', 'server_path', 'wait_for_selector'],
3747
+ 'instructions': [
3748
+ 'Author a real Playwright browser interaction capture script before retrying verify.',
3749
+ 'Do not use the default remote audit current-target capture for interaction verification.',
3750
+ ],
3751
+ }
3752
+ save_state(s)
3753
+ raise SystemExit(s['structured_interaction_capture_failure_summary'])
3754
+ elif not capture_script and no_implementation_mode:
3715
3755
  capture_script = 'await page.waitForTimeout(1500);'
3716
3756
  s['capture_script'] = capture_script
3717
3757
  s['capture_script_source'] = s.get('capture_script_source') or 'default_remote_audit_current_target'
@@ -1658,6 +1658,61 @@ def run_remote_audit_setup_without_repo():
1658
1658
  shutil.rmtree(tempdir, ignore_errors=True)
1659
1659
 
1660
1660
 
1661
+ def run_remote_interaction_audit_setup_requires_authoring():
1662
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-remote-interaction-audit-'))
1663
+ args_path = tempdir / 'args.json'
1664
+ state_path = tempdir / 'state.json'
1665
+ try:
1666
+ args_path.write_text(json.dumps({
1667
+ 'repo': '',
1668
+ 'mode': 'server',
1669
+ 'reference': 'both',
1670
+ 'prod_url': 'https://riddledc.com/',
1671
+ 'change_request': 'Verify Home -> Proof navigation. Start at https://riddledc.com/. Click the visible Proof nav link. Expected terminal URL is https://riddledc.com/proof/.',
1672
+ 'commit_message': '',
1673
+ 'success_criteria': 'Terminal URL is https://riddledc.com/proof/ and structured proof evidence is present.',
1674
+ 'verification_mode': 'interaction',
1675
+ 'implementation_mode': 'none',
1676
+ 'require_diff': False,
1677
+ 'allow_code_changes': False,
1678
+ 'server_image': 'node:20-slim',
1679
+ 'server_command': 'npm start',
1680
+ 'server_port': '3000',
1681
+ }, indent=2))
1682
+ with temporary_env(
1683
+ RIDDLE_PROOF_ARGS_FILE=str(args_path),
1684
+ RIDDLE_PROOF_STATE_FILE=str(state_path),
1685
+ ):
1686
+ sys.modules.pop('util', None)
1687
+ load_module('util_remote_interaction_audit_preflight', UTIL_PATH)
1688
+ load_module('preflight_remote_interaction_audit', PREFLIGHT_PATH)
1689
+ sys.modules.pop('util', None)
1690
+ try:
1691
+ load_module('setup_remote_interaction_audit', SETUP_PATH)
1692
+ except SystemExit as exc:
1693
+ assert exc.code in (0, None), exc
1694
+ state = json.loads(state_path.read_text())
1695
+ assert state['remote_audit'] is True
1696
+ assert state['workspace_ready'] is True
1697
+ assert state['reference'] == 'prod'
1698
+ assert state['implementation_status'] == 'not_required'
1699
+ assert state['server_path'] == '/'
1700
+ assert state['recon_status'] == 'ready_for_proof_plan'
1701
+ assert state['author_status'] == 'needs_authoring'
1702
+ assert state['proof_plan_status'] == 'needs_authoring'
1703
+ assert state.get('capture_script', '') == ''
1704
+ assert state.get('capture_script_source', '') == ''
1705
+ assert 'requires an authored browser interaction capture' in state['author_summary']
1706
+ return {
1707
+ 'ok': True,
1708
+ 'author_status': state['author_status'],
1709
+ 'capture_script_source': state.get('capture_script_source', ''),
1710
+ }
1711
+ finally:
1712
+ sys.modules.pop('util', None)
1713
+ shutil.rmtree(tempdir, ignore_errors=True)
1714
+
1715
+
1661
1716
  def run_preflight_resumes_visual_proof_session():
1662
1717
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-preflight-session-'))
1663
1718
  args_path = tempdir / 'args.json'
@@ -2833,6 +2888,59 @@ def run_remote_audit_verify_uses_default_capture_script():
2833
2888
  shutil.rmtree(tempdir, ignore_errors=True)
2834
2889
 
2835
2890
 
2891
+ def run_remote_interaction_audit_verify_rejects_default_capture():
2892
+ tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-remote-interaction-audit-verify-'))
2893
+ state_path = tempdir / 'state.json'
2894
+ try:
2895
+ state = base_state(tempdir, reference='prod', prod_url='https://riddledc.com/')
2896
+ state.update({
2897
+ 'remote_audit': True,
2898
+ 'workspace_kind': 'remote_audit',
2899
+ 'mode': 'server',
2900
+ 'recon_status': 'ready_for_proof_plan',
2901
+ 'author_status': 'ready',
2902
+ 'proof_plan_status': 'ready',
2903
+ 'implementation_status': 'not_required',
2904
+ 'implementation_mode': 'none',
2905
+ 'require_diff': False,
2906
+ 'allow_code_changes': False,
2907
+ 'verification_mode': 'interaction',
2908
+ 'server_path': '/',
2909
+ 'expected_start_path': '/',
2910
+ 'expected_terminal_path': '/proof',
2911
+ 'requested_expected_terminal_path': '/proof',
2912
+ 'proof_plan': 'Verify Home -> Proof navigation.',
2913
+ 'capture_script': '',
2914
+ 'recon_results': {'baselines': {}, 'mode': 'remote_audit'},
2915
+ })
2916
+ write_state(state_path, state)
2917
+ os.environ['RIDDLE_PROOF_STATE_FILE'] = str(state_path)
2918
+
2919
+ fake = FakeRiddle()
2920
+ load_util_with_fake(fake)
2921
+ try:
2922
+ load_module('verify_remote_interaction_audit_rejects_default_capture', VERIFY_PATH)
2923
+ except SystemExit as exc:
2924
+ assert 'requires an authored browser interaction capture script' in str(exc), exc
2925
+ else:
2926
+ raise AssertionError('interaction remote audit verify should reject missing capture_script')
2927
+ after_verify = json.loads(state_path.read_text())
2928
+
2929
+ assert after_verify['verify_status'] == 'capture_incomplete'
2930
+ assert after_verify.get('capture_script', '') == ''
2931
+ assert after_verify.get('capture_script_source', '') == ''
2932
+ assert after_verify['verify_decision_request']['capture_quality']['decision'] == 'failed_interaction_capture'
2933
+ assert after_verify['verify_decision_request']['capture_quality']['blocking'] is True
2934
+ assert 'default remote audit current-target capture is passive' in after_verify['structured_interaction_capture_failure_summary']
2935
+ return {
2936
+ 'ok': True,
2937
+ 'verify_status': after_verify['verify_status'],
2938
+ 'capture_quality': after_verify['verify_decision_request']['capture_quality']['decision'],
2939
+ }
2940
+ finally:
2941
+ shutil.rmtree(tempdir, ignore_errors=True)
2942
+
2943
+
2836
2944
  def run_verify_interaction_terminal_route_from_proof_evidence():
2837
2945
  tempdir = Path(tempfile.mkdtemp(prefix='riddle-proof-interaction-forward-'))
2838
2946
  state_path = tempdir / 'state.json'
@@ -3941,6 +4049,7 @@ if __name__ == '__main__':
3941
4049
  payload = {
3942
4050
  'preflight_reference_skip_reason': run_preflight_records_prod_reference_skip_reason(),
3943
4051
  'remote_audit_setup_without_repo': run_remote_audit_setup_without_repo(),
4052
+ 'remote_interaction_audit_setup_requires_authoring': run_remote_interaction_audit_setup_requires_authoring(),
3944
4053
  'preflight_resume_visual_proof_session': run_preflight_resumes_visual_proof_session(),
3945
4054
  'capture_artifact_enrichment': run_capture_artifact_enrichment(),
3946
4055
  'capture_diagnostics_redaction': run_capture_diagnostics_redact_sensitive_values(),
@@ -3966,6 +4075,7 @@ if __name__ == '__main__':
3966
4075
  'verify_preserves_proof_evidence_on_capture_script_error': run_verify_preserves_proof_evidence_on_capture_script_error(),
3967
4076
  'verify_capture_retry': run_verify_capture_retry(),
3968
4077
  'remote_audit_verify_uses_default_capture_script': run_remote_audit_verify_uses_default_capture_script(),
4078
+ 'remote_interaction_audit_verify_rejects_default_capture': run_remote_interaction_audit_verify_rejects_default_capture(),
3969
4079
  'verify_interaction_terminal_route_from_proof_evidence': run_verify_interaction_terminal_route_from_proof_evidence(),
3970
4080
  'verify_interaction_iife_structured_evidence_without_screenshot': run_verify_interaction_iife_structured_evidence_without_screenshot(),
3971
4081
  'verify_interaction_proof_evidence_overrides_stale_expected_path': run_verify_interaction_proof_evidence_overrides_stale_expected_path(),