Implement PMEM-WP-0015 credentialed live pilot with ops-warden routing.
Add credential routing advisories via warden route/access, live pilot evidence helpers, managed deployment pilot probes, evaluation trend regression gates, and expanded troubleshooting. Update operator runbook and maturity scorecard.
This commit is contained in:
parent
bff90ec1ed
commit
29f893b905
15 changed files with 913 additions and 38 deletions
|
|
@ -17,6 +17,7 @@ from .utils import stable_digest, utc_now_iso
|
|||
EVALUATION_REPORT_SCHEMA = "phase_memory.evaluation.threshold_report.v1"
|
||||
EVALUATION_TREND_SCHEMA = "phase_memory.evaluation.trend_artifact.v1"
|
||||
EVALUATION_TREND_HISTORY_SCHEMA = "phase_memory.evaluation.trend_history.v1"
|
||||
EVALUATION_TREND_REGRESSION_GATE_SCHEMA = "phase_memory.evaluation.trend_regression_gate.v1"
|
||||
|
||||
DEFAULT_THRESHOLDS = {
|
||||
"policy_denial_count": 1,
|
||||
|
|
@ -165,6 +166,86 @@ def load_evaluation_trend_history(path: str | Path) -> dict[str, Any]:
|
|||
return evaluation_trend_history((data,))
|
||||
|
||||
|
||||
def evaluation_trend_regression_gate(
|
||||
history: dict[str, Any],
|
||||
*,
|
||||
min_artifacts: int = 1,
|
||||
) -> dict[str, Any]:
|
||||
artifacts = list(history.get("artifacts") or ())
|
||||
diagnostics: list[dict[str, Any]] = []
|
||||
if history.get("schema_version") != EVALUATION_TREND_HISTORY_SCHEMA:
|
||||
diagnostics.append(
|
||||
Diagnostic(
|
||||
"error",
|
||||
"evaluation_trend_history_invalid",
|
||||
"Regression gate requires a valid evaluation trend history artifact.",
|
||||
"schema_version",
|
||||
{"expected": EVALUATION_TREND_HISTORY_SCHEMA},
|
||||
).to_dict()
|
||||
)
|
||||
if len(artifacts) < min_artifacts:
|
||||
diagnostics.append(
|
||||
Diagnostic(
|
||||
"warn",
|
||||
"evaluation_trend_history_insufficient",
|
||||
"Regression gate needs at least one persisted trend artifact.",
|
||||
"count",
|
||||
{"actual": len(artifacts), "minimum": min_artifacts},
|
||||
).to_dict()
|
||||
)
|
||||
latest = artifacts[-1] if artifacts else {}
|
||||
previous = artifacts[-2] if len(artifacts) > 1 else {}
|
||||
latest_metrics = dict(latest.get("metrics") or {})
|
||||
previous_metrics = dict(previous.get("metrics") or {})
|
||||
regressions = {
|
||||
key: round(float(latest_metrics.get(key) or 0) - float(previous_metrics.get(key) or 0), 4)
|
||||
for key in sorted(set(latest_metrics) & set(previous_metrics))
|
||||
if float(latest_metrics.get(key) or 0) < float(previous_metrics.get(key) or 0)
|
||||
}
|
||||
for key, delta in regressions.items():
|
||||
diagnostics.append(
|
||||
Diagnostic(
|
||||
"warn",
|
||||
"evaluation_metric_regressed",
|
||||
"Evaluation metric declined from the previous trend artifact.",
|
||||
key,
|
||||
{
|
||||
"delta": delta,
|
||||
"current": latest_metrics.get(key),
|
||||
"previous": previous_metrics.get(key),
|
||||
},
|
||||
).to_dict()
|
||||
)
|
||||
for diagnostic in latest.get("diagnostics", ()):
|
||||
if isinstance(diagnostic, dict) and diagnostic.get("code") == "evaluation_metric_regressed":
|
||||
diagnostics.append(dict(diagnostic))
|
||||
threshold_failures = [
|
||||
dict(item)
|
||||
for item in (latest.get("report") or {}).get("diagnostics", ())
|
||||
if isinstance(item, dict) and item.get("code") == "evaluation_threshold_failed"
|
||||
]
|
||||
for failure in threshold_failures:
|
||||
diagnostics.append(failure)
|
||||
return {
|
||||
"schema_version": EVALUATION_TREND_REGRESSION_GATE_SCHEMA,
|
||||
"id": f"evaluation-trend-regression-gate:{stable_digest([history.get('id', ''), latest.get('id', ''), regressions])}",
|
||||
"valid": not any(item.get("severity") == "error" for item in diagnostics)
|
||||
and not threshold_failures
|
||||
and not regressions,
|
||||
"artifact_count": len(artifacts),
|
||||
"latest_artifact_id": latest.get("id", ""),
|
||||
"previous_artifact_id": previous.get("id", ""),
|
||||
"metric_regressions": regressions,
|
||||
"threshold_failures": threshold_failures,
|
||||
"operator_guidance": {
|
||||
"compare": "Diff the latest evaluation-trend-history.json artifact metrics against the previous run id.",
|
||||
"gate": "Block promotion when metric_regressions or threshold_failures are non-empty.",
|
||||
"history_path": "reports/evaluation-trend-history.json",
|
||||
},
|
||||
"diagnostics": diagnostics,
|
||||
}
|
||||
|
||||
|
||||
def write_evaluation_trend_history(path: str | Path, artifact: dict[str, Any]) -> dict[str, Any]:
|
||||
path = Path(path)
|
||||
existing = load_evaluation_trend_history(path)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue