@@ -47,6 +47,7 @@ def validate_review(payload: Any) -> list[str]:
4747 if not isinstance (payload .get ("scorecard" ), dict ):
4848 issues .append ("scorecard must be an object" )
4949 evidence = payload .get ("evidence" )
50+ provenance : dict [str , Any ] = {}
5051 if not isinstance (evidence , dict ):
5152 issues .append ("evidence must be an object" )
5253 else :
@@ -69,6 +70,14 @@ def validate_review(payload: Any) -> list[str]:
6970 issues .append (f"evidence.provenance.{ source } .{ field } must be non-empty" )
7071 if item .get ("status" ) not in {"verified" , "legacy_missing" , "unavailable" }:
7172 issues .append (f"evidence.provenance.{ source } .status is invalid" )
73+ if item .get ("status" ) == "verified" :
74+ try :
75+ from datetime import datetime
76+ timestamp = datetime .fromisoformat (item ["data_timestamp" ].replace ("Z" , "+00:00" ))
77+ if timestamp .tzinfo is None :
78+ raise ValueError
79+ except (AttributeError , TypeError , ValueError ):
80+ issues .append (f"evidence.provenance.{ source } .verified requires a real timestamp" )
7281 if evidence .get ("placeholder_metrics" ) is not False :
7382 issues .append ("placeholder metrics are not admissible evidence" )
7483 if not isinstance (evidence .get ("sample_count" ), int ) or isinstance (evidence .get ("sample_count" ), bool ) or evidence ["sample_count" ] < 0 :
@@ -109,6 +118,18 @@ def validate_review(payload: Any) -> list[str]:
109118 issues .append (f"decision_packet.automation_boundary.{ field } is unsafe" )
110119 if not isinstance (boundary .get ("canary_limits" ), dict ):
111120 issues .append ("decision_packet.automation_boundary.canary_limits must be an object" )
121+ else :
122+ limits = boundary ["canary_limits" ]
123+ checks = {
124+ "max_capital" : lambda v : isinstance (v , (int , float )) and not isinstance (v , bool ) and v > 0 ,
125+ "capital_currency" : lambda v : isinstance (v , str ) and len (v .strip ()) >= 3 ,
126+ "max_duration_days" : lambda v : isinstance (v , int ) and not isinstance (v , bool ) and v >= 1 ,
127+ "max_drawdown_fraction" : lambda v : isinstance (v , (int , float )) and not isinstance (v , bool ) and 0 < v < 1 ,
128+ "max_leverage" : lambda v : isinstance (v , (int , float )) and not isinstance (v , bool ) and v > 0 ,
129+ "max_concurrency" : lambda v : isinstance (v , int ) and not isinstance (v , bool ) and v >= 1 ,
130+ }
131+ if set (limits ) != set (checks ) or any (not check (limits .get (key )) for key , check in checks .items ()):
132+ issues .append ("decision_packet.automation_boundary.canary_limits is incomplete or invalid" )
112133 allowed = packet .get ("allowed_human_decisions" )
113134 if not isinstance (allowed , list ) or not allowed or any (item not in {"approve_research" , "approve_shadow" , "approve_canary" , "approve_live" , "reject_rollback" } for item in allowed ):
114135 issues .append ("decision_packet.allowed_human_decisions is invalid" )
0 commit comments