Sage / scripts /summary.py
vxa8502's picture
Apply ruff format across codebase
effafc0
Raw History Blame Contribute Delete
20.5 kB
"""
Pipeline results summary.
Reads the latest evaluation result files and prints a scannable
pass/fail summary. Designed to run at the end of `make all`.
Graceful degradation: missing result files produce "(not available)"
sections rather than errors. This script never exits non-zero so it
cannot fail the pipeline.
Usage:
python scripts/summary.py
"""
import json
import sys
from pathlib import Path
from sage.config import (
RESULTS_DIR,
)
from sage.cli.eval_status import build_eval_status
WIDTH = 60
SEP = "=" * WIDTH
def load_json(path: Path) -> dict | None:
"""Load a JSON file, returning None if missing or malformed."""
try:
with open(path, encoding="utf-8") as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError, OSError):
return None
def fmt(value: float | None, decimals: int = 4) -> str:
if value is None:
return " ---"
return f"{value:.{decimals}f}"
def fmt_or_unavailable(value: float | None, decimals: int = 4) -> str:
if value is None:
return "unavailable"
return fmt(value, decimals)
def fmt_with_ci(value: float | None, ci: dict | None, decimals: int = 3) -> str:
"""Format a value with optional confidence interval."""
if value is None:
return " ---"
if ci and "ci_lower" in ci and "ci_upper" in ci:
lower = ci["ci_lower"]
upper = ci["ci_upper"]
return f"{value:.{decimals}f} [{lower:.{decimals}f}, {upper:.{decimals}f}]"
return fmt(value, decimals)
def print_section(title: str):
print(f"\n{title}")
def infer_header_presence(load: dict) -> dict:
"""Infer header presence from measured samples when summary fields are absent."""
measured = load.get("measured") or {}
explicit = measured.get("header_presence")
if explicit:
return explicit
samples = ((load.get("samples") or {}).get("measured")) or []
successful = [sample for sample in samples if sample.get("status") == 200]
total = len(successful)
if total == 0:
return {}
response_time_present = sum(
1 for sample in successful if sample.get("server_ms") is not None
)
cache_result_present = sum(
1
for sample in successful
if sample.get("cache_result") not in (None, "unknown")
)
return {
"x_response_time_ms": {
"present": response_time_present,
"missing": total - response_time_present,
},
"x_cache_result": {
"present": cache_result_present,
"missing": total - cache_result_present,
},
}
def infer_cache_observability(load: dict) -> dict:
"""Infer cache-header observability from explicit fields or measured samples."""
measured = load.get("measured") or {}
explicit = measured.get("cache_observability")
if explicit:
return explicit
header_presence = infer_header_presence(load)
cache_header = header_presence.get("x_cache_result") or {}
present = cache_header.get("present")
missing = cache_header.get("missing")
total = (present or 0) + (missing or 0)
if present is None or missing is None:
return {}
return {
"available": present > 0,
"successful_responses": total,
"header_present_responses": present,
"missing_header_responses": missing,
"reason": (
None
if present > 0 or total == 0
else "X-Cache-Result header absent on successful responses"
),
}
def main():
print(f"\n{SEP}")
print("SAGE PIPELINE RESULTS")
print(SEP)
nat = load_json(RESULTS_DIR / "eval_natural_queries_latest.json")
faith = load_json(RESULTS_DIR / "faithfulness_latest.json")
adj = load_json(RESULTS_DIR / "adjusted_faithfulness_latest.json")
boundary = load_json(RESULTS_DIR / "boundary_behavior_latest.json")
load = load_json(RESULTS_DIR / "load_test_latest.json")
eval_status = build_eval_status(results_dir=RESULTS_DIR)
print_section("Evaluation Status:")
print(f" Latest Artifacts: {eval_status['latest_artifacts']}")
print(f" Execution: {eval_status['execution_status']}")
print(f" Safety Green: {eval_status['safety_status']}")
print(f" Reportable: {eval_status['reportable_status']}")
execution_reasons = eval_status.get("execution_reasons") or []
if eval_status["execution_status"] != "COMPLETE" and isinstance(
execution_reasons, list
):
for reason in execution_reasons[:3]:
if isinstance(reason, str) and reason:
print(f" Exec Note: {reason}")
reportable_reasons = eval_status.get("reportable_reasons") or []
if eval_status["reportable_status"] != "PASS [reportable-green]" and isinstance(
reportable_reasons, list
):
for reason in reportable_reasons[:3]:
if isinstance(reason, str) and reason:
print(f" Report Note: {reason}")
# -- Recommendation Quality (Natural Queries) -----------------------------
print_section("Recommendation Quality (Natural Queries):")
if nat and "primary_metrics" in nat:
m = nat["primary_metrics"]
for label, key, ci_key in [
("NDCG@10", "ndcg_at_10", "ndcg_ci"),
("Hit@10", "hit_at_10", "hit_ci"),
("MRR", "mrr", "mrr_ci"),
]:
print(f" {label + ':':<10s} {fmt_with_ci(m.get(key), m.get(ci_key))}")
else:
print(" (not available)")
# -- Explanation Faithfulness ---------------------------------------------
print_section("Explanation Faithfulness:")
if faith and "hhem" in faith:
n_samples = faith.get("n_samples", 0)
retrieval_policy = faith.get("retrieval_policy") or {}
retrieval_profile = retrieval_policy.get("retrieval_profile")
evaluation_scope = faith.get("evaluation_scope") or {}
ragas_scope = faith.get("ragas_scope") or {}
if retrieval_profile:
print(f" Profile: {retrieval_profile}")
if evaluation_scope:
selected_case_count = evaluation_scope.get("selected_case_count", n_samples)
available_case_count = evaluation_scope.get(
"available_materialized_case_count",
evaluation_scope.get("available_case_count", selected_case_count),
)
selection_mode = evaluation_scope.get("selection_mode")
if selection_mode:
print(
" Eval Scope: "
f"{selection_mode} ({selected_case_count}/{available_case_count} selected)"
)
if evaluation_scope.get("sample_limited"):
print(
" Warning: sampled faithfulness run; headline scores are not full-benchmark"
)
# Multi-metric (primary): claim-level HHEM + quote verification
mm = faith.get("multi_metric", {})
claim_pass = mm.get("claim_level_pass_rate")
claim_avg = mm.get("claim_level_avg_score")
quote_rate = mm.get("quote_verification_rate")
quotes_found = mm.get("quotes_found", 0)
quotes_total = mm.get("quotes_total", 0)
if claim_pass is not None:
print(
f" Claim HHEM: {fmt(claim_avg, 3)} ({claim_pass * 100:.0f}% pass)"
)
print(
f" Quote Verif: {fmt(quote_rate, 3)} ({quotes_found}/{quotes_total})"
)
# Full-explanation HHEM (reference)
h = faith["hhem"]
n_grounded = n_samples - h.get("n_hallucinated", 0)
full_avg = h.get("mean_score")
print(
f" Full HHEM: {fmt(full_avg, 3)} ({n_grounded}/{n_samples} grounded, reference)"
)
# RAGAS if available
ragas = faith.get("ragas", {})
ragas_faith = ragas.get("faithfulness_mean")
if ragas_faith is not None:
print(f" RAGAS Faith: {fmt(ragas_faith, 3)}")
if ragas_scope:
print(
" RAGAS Scope: "
f"{ragas_scope.get('selection_mode')} "
f"({ragas_scope.get('selected_case_count', 0)}/"
f"{ragas_scope.get('available_case_count', 0)} cases)"
)
# Pass/fail: use claim-level as primary, fall back to RAGAS, then full HHEM
effective = (
claim_avg
if claim_avg is not None
else (ragas_faith if ragas_faith is not None else full_avg)
)
if effective is not None:
target = eval_status["metrics"]["faithfulness_target"]
status = "PASS" if effective >= target else "FAIL"
print(f" Target: {target:.3f} [{status}]")
coverage = faith.get("coverage") or {}
if coverage:
source_query_count = coverage.get("source_query_count", 0)
materialized_case_count = coverage.get("materialized_case_count", 0)
materialization_rate = coverage.get("materialization_rate")
candidate_retrieval_rate = coverage.get("candidate_retrieval_rate")
gate_pass_rate = coverage.get("gate_pass_rate")
print(
" Coverage: "
f"{fmt(materialization_rate, 3)} "
f"({materialized_case_count}/{source_query_count} materialized)"
)
print(
" Candidate Hit: "
f"{fmt(candidate_retrieval_rate, 3)} "
f"(after retrieval, before gate)"
)
print(
" Gate Pass: "
f"{fmt(gate_pass_rate, 3)} "
"(conditional on retrieved candidates)"
)
evidence_guardrails = faith.get("evidence_guardrails") or {}
if evidence_guardrails:
print(
" Evidence Age: "
f"{fmt(evidence_guardrails.get('median_evidence_age_days_mean'), 1)} days median"
)
print(
" Very Old Share: "
f"{fmt(evidence_guardrails.get('very_old_review_share_mean'), 3)}"
)
print(
" Verified Avail: "
f"{fmt(evidence_guardrails.get('verified_purchase_available_rate_mean'), 3)}"
)
print(
" Negative Evd: "
f"{fmt(evidence_guardrails.get('negative_review_rate_mean'), 3)}"
)
slice_metrics = faith.get("query_slice_metrics") or {}
for label, key in [
("Recency Slice", "recency_sensitive_query"),
("Negative Slice", "negative_problem_query"),
]:
metrics = slice_metrics.get(key)
if not metrics:
continue
print(
f" {label + ':':<15s} "
f"{fmt(metrics.get('claim_level_avg_score'), 3)} "
f"({metrics.get('evaluated_case_count', 0)} cases, refusal={fmt(metrics.get('refusal_rate'), 3)})"
)
else:
print(" (not available)")
print_section("Boundary Behavior:")
if boundary and "summary" in boundary:
summary = boundary["summary"]
methodology = boundary.get("methodology") or {}
retrieval_profile = methodology.get("retrieval_profile")
if retrieval_profile:
print(f" Profile: {retrieval_profile}")
print(
" Acceptable: "
f"{fmt(summary.get('acceptable_match_rate'), 3)} "
f"({summary.get('acceptable_matches', 0)}/{summary.get('total_queries', 0)})"
)
print(
f" False Accepts: {summary.get('refusal_required_false_accept_count', 0)}"
)
print(f" Clarify Rate: {fmt(summary.get('ambiguous_clarify_rate'), 3)}")
print(f" Boundary Safe: {fmt(summary.get('boundary_safe_behavior_rate'), 3)}")
boundary_guardrail = boundary.get("boundary_guardrail") or {}
boundary_guardrail_status = summary.get("boundary_guardrail_status")
if boundary_guardrail or boundary_guardrail_status:
status = str(
boundary_guardrail.get("status", boundary_guardrail_status)
).upper()
print(f" Boundary Guard: {status}")
freshness_guardrail = summary.get("freshness_guardrail") or {}
if freshness_guardrail:
freshness_status = str(
freshness_guardrail.get("promotion_status", "unknown")
).upper()
freshness_min_cases = freshness_guardrail.get(
"coverage_min_recency_sensitive_cases",
freshness_guardrail.get("coverage_min_cases", 0),
)
print(f" Fresh Guard: {freshness_status}")
print(
" Fresh Cases: "
f"{freshness_guardrail.get('recency_sensitive_case_count', 0)}/"
f"{freshness_min_cases}"
)
print(
" Fresh Refusal: "
f"{fmt_or_unavailable(summary.get('freshness_sensitive_refusal_rate'), 3)}"
)
if freshness_guardrail:
print(
" Fresh Safe: "
f"{fmt_or_unavailable(freshness_guardrail.get('safe_rate'), 3)}"
)
violations = boundary_guardrail.get("violations") or []
if isinstance(violations, list):
for violation in violations[:3]:
if isinstance(violation, dict):
message = violation.get("message")
if message:
print(f" Guardrail Hit: {message}")
evidence_guardrails = summary.get("evidence_guardrails") or {}
if evidence_guardrails:
print(
" Evidence Age: "
f"{fmt(evidence_guardrails.get('median_evidence_age_days_mean'), 1)} days median"
)
print(
" Very Old Share: "
f"{fmt(evidence_guardrails.get('very_old_review_share_mean'), 3)}"
)
print(
" Verified Avail: "
f"{fmt(evidence_guardrails.get('verified_purchase_available_rate_mean'), 3)}"
)
print(
" Negative Evd: "
f"{fmt(evidence_guardrails.get('negative_review_rate_mean'), 3)}"
)
else:
print(" (not available)")
# -- Refusal Rate ----------------------------------------------------------
if adj is None and faith:
adjusted_from_faith = faith.get("adjusted")
if isinstance(adjusted_from_faith, dict):
adj = adjusted_from_faith
print_section("Quality Gate (Refusals):")
if adj:
n_total = adj.get("n_total", 0)
n_refusals = adj.get("n_refusals", 0)
rate = n_refusals / n_total if n_total > 0 else 0
adj_pass = adj.get("adjusted_pass_rate")
print(f" Refusals: {n_refusals}/{n_total} ({rate * 100:.0f}%)")
print(f" Adj Pass Rate: {fmt(adj_pass, 3)}")
else:
print(" (not available)")
# -- API Quality -----------------------------------------------------------
print_section("API Quality:")
if load:
quality = ((load.get("measured") or {}).get("api_quality")) or {}
evaluated = quality.get("evaluated_requests", 0)
grounded = quality.get("grounded_successes", 0)
grounded_rate = quality.get("grounded_success_rate")
refusal_aware = quality.get("refusal_aware_successes", 0)
refusal_aware_rate = quality.get("refusal_aware_success_rate")
if evaluated > 0 and grounded_rate is not None:
print(
f" Grounded OK: {fmt(grounded_rate, 3)} ({grounded}/{evaluated})"
)
print(
" Refusal-Aware: "
f"{fmt(refusal_aware_rate, 3)} ({refusal_aware}/{evaluated})"
)
else:
print(" (not available)")
else:
print(" (not available)")
# -- Load Test -------------------------------------------------------------
print_section("Production Latency:")
if load:
headline = load.get("headline_metric") or {}
measured = load.get("measured") or {}
measured_client = measured.get("client_latency_ms") or {}
measured_server = measured.get("server_latency_ms") or {}
measured_overhead = measured.get("network_overhead_ms") or {}
header_presence = infer_header_presence(load)
cache_observability = infer_cache_observability(load)
n = measured.get("total_requests", load.get("total_requests", 0))
cache_results = measured.get("cache_results") or {}
hit_rate = measured.get("cache_hit_rate")
if headline.get("value_ms") is not None:
status = "PASS" if headline.get("pass") else "FAIL"
print(
" Headline: "
f"{headline.get('name')} = {headline['value_ms']:.0f}ms [{status}]"
)
elif load.get("p99_ms") is not None:
legacy_status = "PASS" if load.get("pass") else "FAIL"
print(
" Headline: "
f"legacy_client_p99_ms = {load['p99_ms']:.0f}ms [{legacy_status}]"
)
if measured_client:
print(
" Client RTT: "
f"p50={measured_client['p50']:.0f} "
f"p95={measured_client['p95']:.0f} "
f"p99={measured_client['p99']:.0f} (n={n})"
)
elif load.get("p50_ms") is not None:
print(
" Client RTT: "
f"p50={load['p50_ms']:.0f} "
f"p95={load['p95_ms']:.0f} "
f"p99={load['p99_ms']:.0f} (n={n})"
)
else:
print(f" Client RTT: (not available, n={n})")
if measured_server:
print(
" Server Time: "
f"p50={measured_server['p50']:.0f} "
f"p95={measured_server['p95']:.0f} "
f"p99={measured_server['p99']:.0f}"
)
if measured_overhead:
print(
" Overhead: "
f"p50={measured_overhead['p50']:.0f} "
f"p95={measured_overhead['p95']:.0f} "
f"p99={measured_overhead['p99']:.0f}"
)
if cache_results:
exact = cache_results.get("exact", 0)
semantic = cache_results.get("semantic", 0)
miss = cache_results.get("miss", 0)
print(f" Cache Split: exact={exact} semantic={semantic} miss={miss}")
if hit_rate is not None:
print(f" Cache Hit Rate: {hit_rate * 100:.0f}%")
else:
hits = load.get("cache_hits")
if hits is None:
missing = cache_observability.get("missing_header_responses")
total = cache_observability.get("successful_responses")
if missing is not None and total is not None:
print(
" Cache Split: "
f"unavailable ({missing}/{total} successful responses missing X-Cache-Result)"
)
else:
print(" Cache hits: unavailable (cache metadata absent)")
else:
fallback_hit_rate = hits / n if n > 0 else 0
print(f" Cache hits: {hits}/{n} ({fallback_hit_rate * 100:.0f}%)")
if header_presence:
response_time = header_presence.get("x_response_time_ms") or {}
cache_header = header_presence.get("x_cache_result") or {}
successful = measured.get("successful", 0)
print(
" Header Obs: "
f"X-Response-Time-Ms {response_time.get('present', 0)}/{successful}; "
f"X-Cache-Result {cache_header.get('present', 0)}/{successful}"
)
else:
print(" (not available)")
# -- Footer ---------------------------------------------------------------
print(f"\nResults: {RESULTS_DIR}/")
print(SEP)
if __name__ == "__main__":
try:
main()
except Exception as exc:
# Never fail the pipeline
print(f"\nSummary error: {exc}", file=sys.stderr)