@@ -93,6 +93,7 @@ def build_dashboard_payload(
9393 pe_l0_models = collect_policyengine_l0_models (policyengine_us_data_repo )
9494 actual_l0_runs = collect_actual_l0_objective_runs (artifact_root )
9595 materialized_l0_scores = collect_materialized_policyengine_l0_scores (artifact_root )
96+ artifact_gate_reports = collect_mp300k_artifact_gate_reports (artifact_root )
9697 run_contracts = collect_run_contracts (artifact_root )
9798 active_logs = collect_recent_log_summaries (artifact_root )
9899 tmux_sessions = collect_tmux_sessions () if include_tmux else []
@@ -114,6 +115,7 @@ def build_dashboard_payload(
114115 "policyengine_l0_models" : pe_l0_models ,
115116 "actual_l0_objective_runs" : actual_l0_runs ,
116117 "materialized_policyengine_l0_scores" : materialized_l0_scores ,
118+ "mp300k_artifact_gate_reports" : artifact_gate_reports ,
117119 "run_contracts" : run_contracts ,
118120 "active_logs" : active_logs ,
119121 "tmux_sessions" : tmux_sessions ,
@@ -197,6 +199,100 @@ def collect_run_contracts(artifact_root: str | Path) -> list[dict[str, Any]]:
197199 )
198200
199201
202+ def collect_mp300k_artifact_gate_reports (
203+ artifact_root : str | Path ,
204+ ) -> list [dict [str , Any ]]:
205+ """Read persisted mp-300k release-gate reports under ``artifact_root``."""
206+
207+ artifact_root = Path (artifact_root )
208+ reports : list [dict [str , Any ]] = []
209+ for path in sorted (artifact_root .rglob ("mp300k_artifact_gates.json" )):
210+ payload = _read_json (path )
211+ if not isinstance (payload , dict ):
212+ continue
213+ summary = payload .get ("summary" )
214+ gates = payload .get ("gates" )
215+ candidate_dataset = payload .get ("candidate_dataset" )
216+ if not isinstance (summary , dict ) or not isinstance (gates , dict ):
217+ continue
218+ compatibility = _gate_report_gate (gates , "compatibility" )
219+ artifact_size = _gate_report_gate (gates , "artifact_size" )
220+ runtime = _gate_report_gate (gates , "runtime" )
221+ ecps = _gate_report_gate (gates , "ecps_comparison" )
222+ compatibility_metrics = compatibility .get ("metrics" , {})
223+ reports .append (
224+ {
225+ "artifact_path" : str (path ),
226+ "artifact_dir" : str (path .parent ),
227+ "artifact_id" : payload .get ("artifact_id" ) or path .parent .name ,
228+ "product" : payload .get ("product" ),
229+ "period" : payload .get ("period" ),
230+ "status" : summary .get ("status" ),
231+ "passing_required_gate_count" : summary .get (
232+ "passing_required_gate_count"
233+ ),
234+ "failed_required_gate_count" : summary .get ("failed_required_gate_count" ),
235+ "unmeasured_required_gate_count" : summary .get (
236+ "unmeasured_required_gate_count"
237+ ),
238+ "failed_required_gates" : summary .get ("failed_required_gates" ) or [],
239+ "unmeasured_required_gates" : summary .get ("unmeasured_required_gates" )
240+ or [],
241+ "candidate_dataset_path" : (
242+ candidate_dataset .get ("path" )
243+ if isinstance (candidate_dataset , dict )
244+ else None
245+ ),
246+ "candidate_size_bytes" : (
247+ candidate_dataset .get ("size_bytes" )
248+ if isinstance (candidate_dataset , dict )
249+ else None
250+ ),
251+ "candidate_households" : compatibility_metrics .get ("household_count" ),
252+ "candidate_persons" : compatibility_metrics .get ("person_count" ),
253+ "compatibility_status" : compatibility .get ("status" ),
254+ "artifact_size_status" : artifact_size .get ("status" ),
255+ "artifact_size_ratio" : _gate_metric (
256+ artifact_size ,
257+ "artifact_size_ratio" ,
258+ ),
259+ "runtime_status" : runtime .get ("status" ),
260+ "runtime_ratio" : _gate_metric (runtime , "runtime_ratio" ),
261+ "ecps_comparison_status" : ecps .get ("status" ),
262+ "candidate_loss" : _gate_metric (
263+ ecps ,
264+ "candidate_enhanced_cps_native_loss" ,
265+ ),
266+ "baseline_loss" : _gate_metric (
267+ ecps ,
268+ "baseline_enhanced_cps_native_loss" ,
269+ ),
270+ "loss_delta" : _gate_metric (ecps , "enhanced_cps_native_loss_delta" ),
271+ }
272+ )
273+ return sorted (
274+ reports ,
275+ key = lambda row : (
276+ row .get ("status" ) != "passed" ,
277+ row .get ("candidate_loss" ) is None ,
278+ row .get ("candidate_loss" ) or float ("inf" ),
279+ row .get ("artifact_path" ) or "" ,
280+ ),
281+ )
282+
283+
284+ def _gate_report_gate (gates : dict [str , Any ], name : str ) -> dict [str , Any ]:
285+ gate = gates .get (name )
286+ return gate if isinstance (gate , dict ) else {}
287+
288+
289+ def _gate_metric (gate : dict [str , Any ], metric : str ) -> Any :
290+ metrics = gate .get ("metrics" )
291+ if not isinstance (metrics , dict ):
292+ return None
293+ return metrics .get (metric )
294+
295+
200296def collect_local_target_screens (artifact_root : str | Path ) -> list [dict [str , Any ]]:
201297 """Read cheap matrix-side local target screen summaries."""
202298
0 commit comments