@riddledc/riddle-proof 0.5.16 → 0.5.17

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.5.16",
3
+ "version": "0.5.17",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -625,6 +625,111 @@ def collect_supporting_artifacts(payload):
625
625
  }
626
626
 
627
627
 
628
+ def artifact_contract_for_mode(verification_mode):
629
+ mode = normalized_verification_mode(verification_mode)
630
+ return {
631
+ 'verification_mode': mode,
632
+ 'required': {
633
+ 'baseline_context': True,
634
+ 'route_semantics': True,
635
+ 'screenshot': screenshot_required_for_mode(mode),
636
+ 'proof_evidence': proof_evidence_required_for_mode(mode),
637
+ },
638
+ 'preferred': {
639
+ 'page_state': True,
640
+ 'structured_payload': mode in STRUCTURED_FIRST_MODES or proof_evidence_required_for_mode(mode),
641
+ 'visual_delta': visual_delta_applies(mode),
642
+ },
643
+ 'optional': {
644
+ 'console_summary': True,
645
+ 'json_artifacts': True,
646
+ 'image_outputs': True,
647
+ },
648
+ }
649
+
650
+
651
+ def artifact_production_summary(payload, supporting):
652
+ artifact_summary = summarize_capture_artifacts(payload)
653
+ return {
654
+ 'output_names': [str(item.get('name') or '') for item in (artifact_summary.get('outputs') or [])[:20]],
655
+ 'screenshot_names': [str(item.get('name') or '') for item in (artifact_summary.get('screenshots') or [])[:10]],
656
+ 'artifact_json': list(artifact_summary.get('artifact_json') or []),
657
+ 'artifact_error_names': sorted((artifact_summary.get('artifact_errors') or {}).keys()),
658
+ 'image_output_count': len(supporting.get('image_outputs') or []),
659
+ 'data_output_count': len(supporting.get('data_outputs') or []),
660
+ 'other_output_count': len(supporting.get('other_outputs') or []),
661
+ 'console_entries': int(supporting.get('console_entries') or 0),
662
+ 'structured_result_keys': list(supporting.get('structured_result_keys') or []),
663
+ 'proof_evidence_present': bool(supporting.get('proof_evidence_present')),
664
+ 'has_structured_payload': bool(supporting.get('has_structured_payload')),
665
+ }
666
+
667
+
668
+ def artifact_signal_availability(state, after_observation, supporting, visual_delta, required_baseline_present, semantic_context):
669
+ details = (after_observation or {}).get('details') or {}
670
+ route = (semantic_context or {}).get('route') or {}
671
+ return {
672
+ 'baseline_context': bool(required_baseline_present),
673
+ 'route_semantics': bool(route.get('after_observed_path') or details.get('observed_path')),
674
+ 'screenshot': bool(details.get('has_screenshot')),
675
+ 'page_state': bool(
676
+ details.get('visible_text_sample')
677
+ or details.get('headings')
678
+ or details.get('buttons')
679
+ or details.get('links')
680
+ or details.get('semantic_anchor_count')
681
+ ),
682
+ 'structured_payload': bool(supporting.get('has_structured_payload')),
683
+ 'proof_evidence': bool(supporting.get('proof_evidence_present')),
684
+ 'visual_delta': bool((visual_delta or {}).get('status') not in ('', None, 'not_applicable')),
685
+ 'console_summary': bool(supporting.get('console_entries')),
686
+ 'json_artifacts': bool(supporting.get('data_outputs')),
687
+ 'image_outputs': bool(supporting.get('image_outputs')),
688
+ 'assertions': bool(state.get('parsed_assertions')),
689
+ 'success_criteria': bool((state.get('success_criteria') or '').strip()),
690
+ }
691
+
692
+
693
+ def artifact_usage_summary(state, after_observation, supporting, visual_delta, required_baseline_present, semantic_context, evidence_basis):
694
+ contract = artifact_contract_for_mode(state.get('verification_mode'))
695
+ available = artifact_signal_availability(
696
+ state,
697
+ after_observation,
698
+ supporting,
699
+ visual_delta,
700
+ required_baseline_present,
701
+ semantic_context,
702
+ )
703
+ capture_quality = []
704
+ details = (after_observation or {}).get('details') or {}
705
+ if details.get('has_screenshot'):
706
+ capture_quality.append('screenshot')
707
+ if available.get('page_state'):
708
+ capture_quality.append('page_state')
709
+ if available.get('console_summary'):
710
+ capture_quality.append('console_summary')
711
+ if available.get('structured_payload'):
712
+ capture_quality.append('structured_payload')
713
+ if available.get('proof_evidence'):
714
+ capture_quality.append('proof_evidence')
715
+ if available.get('visual_delta'):
716
+ capture_quality.append('visual_delta')
717
+
718
+ required_signals = [key for key, enabled in (contract.get('required') or {}).items() if enabled]
719
+ preferred_signals = [key for key, enabled in (contract.get('preferred') or {}).items() if enabled]
720
+ optional_signals = [key for key, enabled in (contract.get('optional') or {}).items() if enabled]
721
+
722
+ return {
723
+ 'required_signals': required_signals,
724
+ 'preferred_signals': preferred_signals,
725
+ 'optional_signals': optional_signals,
726
+ 'available_signals': [key for key, enabled in available.items() if enabled],
727
+ 'missing_required_signals': [key for key in required_signals if not available.get(key)],
728
+ 'capture_quality_signals': capture_quality,
729
+ 'supervisor_review_signals': list(evidence_basis or []),
730
+ }
731
+
732
+
628
733
  def evaluate_capture_quality(payload, expected_path, verification_mode='proof'):
629
734
  payload = enrich_capture_payload(payload)
630
735
  mode = normalized_verification_mode(verification_mode)
@@ -863,6 +968,17 @@ def build_evidence_bundle(state, results, after_payload, after_observation, requ
863
968
  else {'status': 'not_applicable', 'passed': None, 'reason': 'Verification mode does not require visual delta gating.'}
864
969
  )
865
970
  semantic_context = build_semantic_context(state, results, after_observation, expected_path)
971
+ artifact_contract = artifact_contract_for_mode(state.get('verification_mode'))
972
+ artifact_production = artifact_production_summary(after_payload, supporting)
973
+ artifact_usage = artifact_usage_summary(
974
+ state,
975
+ after_observation,
976
+ supporting,
977
+ visual_delta,
978
+ required_baseline_present,
979
+ semantic_context,
980
+ [],
981
+ )
866
982
  return {
867
983
  'verification_mode': normalized_verification_mode(state.get('verification_mode')),
868
984
  'reference': state.get('requested_reference') or state.get('reference', 'both'),
@@ -870,6 +986,9 @@ def build_evidence_bundle(state, results, after_payload, after_observation, requ
870
986
  'required_baseline_present': required_baseline_present,
871
987
  'baseline': results.get('baseline') or {},
872
988
  'semantic_context': semantic_context,
989
+ 'artifact_contract': artifact_contract,
990
+ 'artifact_production': artifact_production,
991
+ 'artifact_usage': artifact_usage,
873
992
  'after': {
874
993
  'screenshot_url': state.get('after_cdn') or '',
875
994
  'observation': after_observation,
@@ -910,6 +1029,26 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
910
1029
  if has_success_criteria:
911
1030
  evidence_basis.append('success-criteria')
912
1031
 
1032
+ artifact_contract = (evidence_bundle or {}).get('artifact_contract') if isinstance(evidence_bundle, dict) else None
1033
+ if not isinstance(artifact_contract, dict):
1034
+ artifact_contract = artifact_contract_for_mode(verification_mode)
1035
+ artifact_production = (evidence_bundle or {}).get('artifact_production') if isinstance(evidence_bundle, dict) else None
1036
+ if not isinstance(artifact_production, dict):
1037
+ artifact_production = artifact_production_summary(payload, supporting)
1038
+ artifact_usage = artifact_usage_summary(
1039
+ state,
1040
+ after_observation,
1041
+ supporting,
1042
+ visual_delta,
1043
+ required_baseline_present,
1044
+ semantic_context,
1045
+ evidence_basis,
1046
+ )
1047
+ if isinstance(evidence_bundle, dict):
1048
+ evidence_bundle['artifact_contract'] = artifact_contract
1049
+ evidence_bundle['artifact_production'] = artifact_production
1050
+ evidence_bundle['artifact_usage'] = artifact_usage
1051
+
913
1052
  return {
914
1053
  'status': 'needs_supervising_agent_assessment',
915
1054
  'verification_mode': verification_mode,
@@ -921,6 +1060,9 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
921
1060
  'semantic_context': semantic_context,
922
1061
  'evidence_bundle': evidence_bundle or {},
923
1062
  'evidence_basis': evidence_basis,
1063
+ 'artifact_contract': artifact_contract,
1064
+ 'artifact_production': artifact_production,
1065
+ 'artifact_usage': artifact_usage,
924
1066
  'instructions': [
925
1067
  'The supervising agent owns proof assessment. Inspect the recon baseline(s), after evidence, and any structured artifacts together.',
926
1068
  'Decide whether the evidence is ready_to_ship or should continue internally through author, implement, or recon.',
@@ -790,6 +790,20 @@ def run_verify_requests_supervisor_assessment():
790
790
  assert semantic_context['after']['headings'] == ['Pricing'], semantic_context
791
791
  assert 'semantic-context' in after_verify['proof_assessment_request']['evidence_basis']
792
792
  assert after_verify['proof_assessment_request']['evidence_bundle']['semantic_context']['after']['buttons'] == ['Buy Now']
793
+ artifact_contract = after_verify['proof_assessment_request']['artifact_contract']
794
+ assert artifact_contract['required']['baseline_context'] is True
795
+ assert artifact_contract['required']['screenshot'] is True
796
+ artifact_production = after_verify['proof_assessment_request']['artifact_production']
797
+ assert artifact_production['image_output_count'] >= 1
798
+ assert artifact_production['proof_evidence_present'] is False
799
+ artifact_usage = after_verify['proof_assessment_request']['artifact_usage']
800
+ assert artifact_usage['missing_required_signals'] == []
801
+ assert 'after-capture' in artifact_usage['supervisor_review_signals']
802
+ assert 'baseline_context' in artifact_usage['required_signals']
803
+ assert 'route_semantics' in artifact_usage['available_signals']
804
+ assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_contract']['required']['screenshot'] is True
805
+ assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_production']['image_output_count'] >= 1
806
+ assert after_verify['proof_assessment_request']['evidence_bundle']['artifact_usage']['missing_required_signals'] == []
793
807
  assert 'capture success is not proof' in '\n'.join(after_verify['proof_assessment_request']['instructions'])
794
808
  assert after_verify['verify_decision_request']['continue_with_stage'] is None
795
809
  assert after_verify['verify_results']['baseline']['before']['source'] == 'recon'