Skip to content

Commit d751da9

Browse files
committed
Fill release readiness from score smoke artifacts
1 parent fa316a0 commit d751da9

2 files changed

Lines changed: 128 additions & 1 deletion

File tree

src/microplex_us/pipelines/dashboard.py

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ def build_dashboard_payload(
9494
actual_l0_runs = collect_actual_l0_objective_runs(artifact_root)
9595
materialized_l0_scores = collect_materialized_policyengine_l0_scores(artifact_root)
9696
artifact_gate_reports = collect_mp300k_artifact_gate_reports(artifact_root)
97+
release_gate_reports = [
98+
*artifact_gate_reports,
99+
*_release_gate_reports_from_score_runs(
100+
score_runs,
101+
artifact_gate_reports,
102+
),
103+
]
97104
run_contracts = collect_run_contracts(artifact_root)
98105
active_logs = collect_recent_log_summaries(artifact_root)
99106
tmux_sessions = collect_tmux_sessions() if include_tmux else []
@@ -116,7 +123,7 @@ def build_dashboard_payload(
116123
"actual_l0_objective_runs": actual_l0_runs,
117124
"materialized_policyengine_l0_scores": materialized_l0_scores,
118125
"mp300k_artifact_gate_reports": artifact_gate_reports,
119-
"release_readiness": build_release_readiness(artifact_gate_reports),
126+
"release_readiness": build_release_readiness(release_gate_reports),
120127
"run_contracts": run_contracts,
121128
"active_logs": active_logs,
122129
"tmux_sessions": tmux_sessions,
@@ -293,6 +300,114 @@ def collect_mp300k_artifact_gate_reports(
293300
)
294301

295302

303+
def _release_gate_reports_from_score_runs(
304+
score_runs: list[dict[str, Any]],
305+
artifact_gate_reports: list[dict[str, Any]],
306+
) -> list[dict[str, Any]]:
307+
"""Build release-readiness rows from scored artifacts with smoke metadata.
308+
309+
Full gate reports are preferred when present. This fallback keeps the living
310+
dashboard useful for older candidate artifacts that persisted PE-native
311+
scores and loader-smoke results before the full gate sidecar existed.
312+
"""
313+
314+
gate_report_dirs = {
315+
str(row.get("artifact_dir"))
316+
for row in artifact_gate_reports
317+
if row.get("artifact_dir")
318+
}
319+
reports: list[dict[str, Any]] = []
320+
for score in score_runs:
321+
artifact_dir = str(score.get("artifact_dir") or "")
322+
if not artifact_dir or artifact_dir in gate_report_dirs:
323+
continue
324+
release_smoke = score.get("release_smoke")
325+
if not isinstance(release_smoke, dict):
326+
continue
327+
product = score.get("record_count_tier")
328+
if not product:
329+
continue
330+
331+
file_size_passes = release_smoke.get("passes_file_size_ratio_2x")
332+
runtime_passes = release_smoke.get("passes_runtime_ratio_1_25x")
333+
candidate_beats_baseline = score.get("candidate_beats_baseline")
334+
failed_required_gates = []
335+
unmeasured_required_gates = []
336+
for gate_name, gate_value in (
337+
("artifact_size", file_size_passes),
338+
("runtime", runtime_passes),
339+
("ecps_comparison", candidate_beats_baseline),
340+
):
341+
if gate_value is True:
342+
continue
343+
if gate_value is False:
344+
failed_required_gates.append(gate_name)
345+
else:
346+
unmeasured_required_gates.append(gate_name)
347+
348+
reports.append(
349+
{
350+
"artifact_path": release_smoke.get("artifact_path")
351+
or score.get("artifact_path"),
352+
"artifact_dir": artifact_dir,
353+
"artifact_id": Path(artifact_dir).name,
354+
"product": product,
355+
"period": score.get("period"),
356+
"status": _release_smoke_gate_status(
357+
failed_required_gates,
358+
unmeasured_required_gates,
359+
),
360+
"passing_required_gate_count": 3
361+
- len(failed_required_gates)
362+
- len(unmeasured_required_gates),
363+
"failed_required_gate_count": len(failed_required_gates),
364+
"unmeasured_required_gate_count": len(unmeasured_required_gates),
365+
"failed_required_gates": failed_required_gates,
366+
"unmeasured_required_gates": unmeasured_required_gates,
367+
"candidate_dataset_path": score.get("candidate_dataset"),
368+
"candidate_size_bytes": release_smoke.get(
369+
"candidate_file_size_bytes"
370+
),
371+
"candidate_households": release_smoke.get("candidate_households"),
372+
"candidate_persons": None,
373+
"compatibility_status": "smoke_only",
374+
"artifact_size_status": _gate_bool_status(file_size_passes),
375+
"artifact_size_ratio": release_smoke.get("file_size_ratio"),
376+
"runtime_status": _gate_bool_status(runtime_passes),
377+
"runtime_ratio": release_smoke.get("median_runtime_ratio"),
378+
"ecps_comparison_status": _gate_bool_status(
379+
candidate_beats_baseline
380+
),
381+
"candidate_loss": score.get("candidate_loss"),
382+
"baseline_loss": score.get("baseline_loss"),
383+
"loss_delta": score.get("loss_delta"),
384+
"n_targets_kept": score.get("n_targets_kept"),
385+
"metric_runtime": score.get("metric_runtime"),
386+
"source_kind": "score_release_smoke",
387+
}
388+
)
389+
return reports
390+
391+
392+
def _release_smoke_gate_status(
393+
failed_required_gates: list[str],
394+
unmeasured_required_gates: list[str],
395+
) -> str:
396+
if failed_required_gates:
397+
return "failed"
398+
if unmeasured_required_gates:
399+
return "incomplete"
400+
return "passed"
401+
402+
403+
def _gate_bool_status(value: Any) -> str | None:
404+
if value is True:
405+
return "pass"
406+
if value is False:
407+
return "fail"
408+
return None
409+
410+
296411
def build_release_readiness(
297412
artifact_gate_reports: list[dict[str, Any]],
298413
) -> list[dict[str, Any]]:

tests/pipelines/test_dashboard.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,18 @@ def test_dashboard_payload_reads_release_smoke_for_record_tiers(tmp_path):
264264
assertions = payload["run_board"]["assertions"]
265265
assert assertions["microplex_current_best_has_release_smoke"] is True
266266
assert assertions["microplex_current_best_release_smoke_passes"] is True
267+
readiness = payload["run_board"]["release_readiness"]
268+
assert len(readiness) == 1
269+
assert readiness[0]["product"] == "mp-120k"
270+
assert readiness[0]["metric_runtime"] == "latest_policyengine_us"
271+
assert readiness[0]["status"] == "release_ready"
272+
assert readiness[0]["best_passing_artifact"]["artifact_id"] == (
273+
"mp120k_latest_us_data_refit"
274+
)
275+
assert readiness[0]["best_passing_artifact"]["compatibility_status"] == (
276+
"smoke_only"
277+
)
278+
assert readiness[0]["best_passing_artifact"]["candidate_households"] == 120_000
267279

268280

269281
def test_dashboard_payload_wires_materialized_pe_l0_score_jsons(tmp_path):

0 commit comments

Comments
 (0)