Skip to content

Commit 33e6801

Browse files
committed
Enforce reference authority in CI with snapshot and conic failure clustering
1 parent 677431e commit 33e6801

14 files changed

Lines changed: 302 additions & 57 deletions

.github/workflows/governance-audit.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@ jobs:
2222
python -m pip install --upgrade pip
2323
python -m pip install -r requirements-dev.txt
2424
python -m pip install -e ".[dev]"
25-
- name: Audit registry, manifests, and release metadata
25+
- name: Reference authority (index, snapshot, audit, flagship)
26+
run: python scripts/reference_authority_check.py
27+
- name: Governance evidence tests
2628
run: |
27-
python scripts/refresh_published_run_index.py --check
28-
python -m pytest tests/governance/test_host_realistic_publish_evidence.py tests/governance/test_run_host_realistic_publish.py -q
29-
python -m conicshield.governance.audit_cli
29+
python -m pytest \
30+
tests/governance/test_host_realistic_publish_evidence.py \
31+
tests/governance/test_reference_authority_invariants.py \
32+
tests/governance/test_reference_evidence_tiers.py \
33+
tests/governance/test_native_arm_publish_evidence.py \
34+
tests/governance/test_run_host_realistic_publish.py \
35+
tests/governance/test_conic_suite_report_clusters.py \
36+
-q --tb=short
3037
- name: Export rehearsal matches committed upstream JSON
3138
run: |
3239
python scripts/export_inter_sim_offline_graph.py \
@@ -68,5 +75,3 @@ jobs:
6875
--family-id conicshield-transition-bank-v1 \
6976
--reason "CI governance rehearsal (governance-audit workflow)" \
7077
--dry-run
71-
- name: Strict governance audit
72-
run: python -m conicshield.governance.audit_cli --strict

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ else
2323
PYTHON ?= python
2424
endif
2525

26-
.PHONY: test test-reference test-slow test-solver test-vendor-moreau smoke-solver smoke-check env-check reference-correctness perf-benchmark diff-check trust-dashboard parity-native-licensed artifact-validation-report parity-report audit dashboard validate-fixture lint typecheck format format-check cov cov-gates compile-deps verify-extended bootstrap-moreau upgrade-host-realistic-vendor host-realistic-rehearsal export-upstream-rehearsal batch-solve-report verify-reference-system reference-authority-check refresh-live-upstream-export
26+
.PHONY: test test-reference test-slow test-solver test-vendor-moreau smoke-solver smoke-check env-check reference-correctness perf-benchmark diff-check trust-dashboard parity-native-licensed artifact-validation-report parity-report audit dashboard validate-fixture lint typecheck format format-check cov cov-gates compile-deps verify-extended bootstrap-moreau upgrade-host-realistic-vendor host-realistic-rehearsal export-upstream-rehearsal batch-solve-report verify-reference-system reference-authority-check reference-authority-snapshot refresh-live-upstream-export
2727

2828
test:
2929
$(PYTHON) -m pytest -q
@@ -76,6 +76,9 @@ upgrade-host-realistic-vendor:
7676
reference-authority-check:
7777
$(PYTHON) scripts/reference_authority_check.py
7878

79+
reference-authority-snapshot:
80+
$(PYTHON) scripts/generate_reference_authority_snapshot.py
81+
7982
refresh-live-upstream-export:
8083
@echo "Usage: $(PYTHON) scripts/refresh_live_upstream_export.py --graph-json <path/to/offline_transition_graph.json>"
8184

@@ -85,6 +88,7 @@ verify-reference-system: reference-authority-check
8588
tests/governance/test_host_realistic_publish_evidence.py \
8689
tests/governance/test_reference_evidence_tiers.py \
8790
tests/governance/test_reference_authority_invariants.py \
91+
tests/governance/test_conic_suite_report_clusters.py \
8892
tests/governance/test_native_arm_publish_evidence.py \
8993
tests/governance/test_run_host_realistic_publish.py \
9094
tests/governance/test_batch_solve_report.py \

benchmarks/reports/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@ Optional JSON reports that illustrate public benchmark evidence shapes. They are
44

55
| File | Purpose |
66
|------|---------|
7+
| [`reference_authority_snapshot.json`](reference_authority_snapshot.json) | Committed flagship release alignment (`current_run_id`, gates, provenance); CI `--check` via `reference_authority_check` |
78
| [`batch_solve_report.example.json`](batch_solve_report.example.json) | Schema example for `scripts/batch_solve_report.py` output (`native_microbatch` vs `native_compiled_real_batch`) |
89

10+
Regenerate snapshot after release or flagship bundle changes:
11+
12+
```bash
13+
make reference-authority-snapshot
14+
```
15+
916
## Regenerate real batch evidence (licensed host)
1017

1118
```bash
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"schema_version": "conicshield_reference_authority_snapshot/v1",
3+
"generated_at_utc": "2026-05-26T04:42:53Z",
4+
"family_id": "conicshield-transition-bank-v1",
5+
"flagship_run_id": "host-realistic-20260525",
6+
"aligned": true,
7+
"current_release": {
8+
"current_run_id": "host-realistic-20260525",
9+
"state": "published",
10+
"publishable_arms": [
11+
"baseline-unshielded",
12+
"shielded-rules-only",
13+
"shielded-rules-plus-geometry",
14+
"shielded-native-moreau"
15+
],
16+
"artifact_gate": "green",
17+
"parity_gate": "green",
18+
"promotion_gate": "green",
19+
"benchmark_bundle_paths": [
20+
"benchmarks/published_runs/wsl-native-20260409-091141",
21+
"benchmarks/published_runs/wsl-real-20260409-132450",
22+
"benchmarks/published_runs/host-realistic-20260525"
23+
]
24+
},
25+
"flagship_provenance": {
26+
"evidence_tier": "vendor_native",
27+
"projector_mode": "real_projector",
28+
"source_export_json": "benchmarks/external_evidence/offline_graph_export_upstream.json"
29+
},
30+
"flagship_governance": {
31+
"state": "published",
32+
"parity_gate": "green",
33+
"promotion_gate": "green"
34+
},
35+
"export_provenance": {
36+
"export_kind": "structural_committed",
37+
"export_json": "benchmarks/external_evidence/offline_graph_export_upstream.json"
38+
}
39+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""Reference-authority snapshot: flagship release alignment for dashboards and CI."""
2+
3+
from __future__ import annotations
4+
5+
import json
6+
from datetime import UTC, datetime
7+
from pathlib import Path
8+
from typing import Any
9+
10+
_FLAGSHIP_RUN_ID = "host-realistic-20260525"
11+
_FAMILY_ID = "conicshield-transition-bank-v1"
12+
13+
14+
def _load_json(path: Path) -> dict[str, Any]:
15+
return json.loads(path.read_text(encoding="utf-8"))
16+
17+
18+
def build_reference_authority_snapshot(*, repo_root: Path | None = None) -> dict[str, Any]:
19+
"""Machine-readable flagship + family release state from committed artifacts."""
20+
root = repo_root if repo_root is not None else Path.cwd()
21+
current_path = root / "benchmarks" / "releases" / _FAMILY_ID / "CURRENT.json"
22+
current = _load_json(current_path)
23+
registry = _load_json(root / "benchmarks" / "registry.json")
24+
fam = next(f for f in registry["benchmark_families"] if f["family_id"] == _FAMILY_ID)
25+
26+
flagship_dir = root / "benchmarks" / "published_runs" / _FLAGSHIP_RUN_ID
27+
prov = _load_json(flagship_dir / "RUN_PROVENANCE.json") if (flagship_dir / "RUN_PROVENANCE.json").is_file() else {}
28+
gov = (
29+
_load_json(flagship_dir / "governance_status.json")
30+
if (flagship_dir / "governance_status.json").is_file()
31+
else {}
32+
)
33+
export_prov_path = root / "benchmarks" / "external_evidence" / "EXPORT_PROVENANCE.json"
34+
export_prov = _load_json(export_prov_path) if export_prov_path.is_file() else {}
35+
36+
gates_ok = all(current.get(g) == "green" for g in ("artifact_gate", "parity_gate", "promotion_gate"))
37+
native_ok = "shielded-native-moreau" in (current.get("publishable_arms") or [])
38+
bundle_ok = f"benchmarks/published_runs/{_FLAGSHIP_RUN_ID}" in (current.get("benchmark_bundle_paths") or [])
39+
gov_gates_ok = gov and all(gov.get(g) == "green" for g in ("parity_gate", "promotion_gate"))
40+
aligned = (
41+
current.get("current_run_id") == _FLAGSHIP_RUN_ID
42+
and fam.get("current_run_id") == _FLAGSHIP_RUN_ID
43+
and current.get("state") == "published"
44+
and prov.get("evidence_tier") == "vendor_native"
45+
and prov.get("projector_mode") == "real_projector"
46+
and gates_ok
47+
and native_ok
48+
and bundle_ok
49+
and gov_gates_ok
50+
)
51+
52+
return {
53+
"schema_version": "conicshield_reference_authority_snapshot/v1",
54+
"generated_at_utc": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
55+
"family_id": _FAMILY_ID,
56+
"flagship_run_id": _FLAGSHIP_RUN_ID,
57+
"aligned": aligned,
58+
"current_release": {
59+
"current_run_id": current.get("current_run_id"),
60+
"state": current.get("state"),
61+
"publishable_arms": current.get("publishable_arms"),
62+
"artifact_gate": current.get("artifact_gate"),
63+
"parity_gate": current.get("parity_gate"),
64+
"promotion_gate": current.get("promotion_gate"),
65+
"benchmark_bundle_paths": current.get("benchmark_bundle_paths"),
66+
},
67+
"flagship_provenance": {
68+
"evidence_tier": prov.get("evidence_tier"),
69+
"projector_mode": prov.get("projector_mode"),
70+
"source_export_json": prov.get("source_export_json"),
71+
},
72+
"flagship_governance": {
73+
"state": gov.get("state"),
74+
"parity_gate": gov.get("parity_gate"),
75+
"promotion_gate": gov.get("promotion_gate"),
76+
},
77+
"export_provenance": {
78+
"export_kind": export_prov.get("export_kind"),
79+
"export_json": export_prov.get("export_json"),
80+
},
81+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Helpers for trusted conic suite reporting (no cvxpy import)."""
2+
3+
from __future__ import annotations
4+
5+
from typing import Any
6+
7+
8+
def cluster_cases_by_family(case_rows: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
9+
"""Aggregate suite rows by ``family`` for failure dashboards."""
10+
clusters: dict[str, dict[str, Any]] = {}
11+
for row in case_rows:
12+
family = str(row.get("family", "unknown"))
13+
bucket = clusters.setdefault(family, {"total": 0, "ok": 0, "failed_case_ids": []})
14+
bucket["total"] += 1
15+
if row.get("status") == "ok":
16+
bucket["ok"] += 1
17+
else:
18+
bucket["failed_case_ids"].append(row.get("case_id"))
19+
return clusters

docs/REFERENCE_AUTHORITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Orchestration: [`scripts/run_host_realistic_publish.py`](../scripts/run_host_rea
2727
| Gate | Command |
2828
|------|---------|
2929
| Reference authority (index + audit + flagship) | `make reference-authority-check` or `python scripts/reference_authority_check.py` |
30+
| Refresh committed snapshot | `make reference-authority-snapshot``benchmarks/reports/reference_authority_snapshot.json` |
3031
| Public verification bundle | `make verify-reference-system` |
3132
| Strict governance audit | `python -m conicshield.governance.audit_cli --strict` |
3233

docs/ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ What is **not** closed or only partially addressed:
4343

4444
1. **Live inter-sim re-export**`python scripts/refresh_live_upstream_export.py --graph-json <dump.json>` then `make upgrade-host-realistic-vendor` when a patched-host dump is available.
4545
2. **Shield autograd vs finite differences****Decision: defer autograd product claim.** Inter-sim shield **FD** (`tests/vendor/diff/`) and `python scripts/differentiation_check.py --shield-inter-sim` support internal validation only; **autograd / `enable_grad` vs FD** on the production shield QP remains out of scope for external narrative until explicitly promoted.
46-
3. **Conic suite: failure clustering**Optional richer **CI artifacts** or dashboards aggregating `conic_suite_report.py` by regime (suite rows already carry case metadata).
46+
3. **Conic suite: failure clustering**`conic_suite_report.py` emits `clusters.by_family` and `families_with_failures`; optional committed CI artifacts under `benchmarks/reports/`.
4747
4. **Physical test tree** — Continue incremental moves per [`tests/STRUCTURE.md`](../tests/STRUCTURE.md); no mass rename required for correctness.
4848
5. **Second benchmark family**[`conicshield-shield-qp-micro-v1`](../benchmarks/releases/conicshield-shield-qp-micro-v1/FAMILY_README.md) is scaffold-only (`current_run_id: null`) until you publish a real run and bundles.
4949
6. **Follow-on product** — Retraining comparisons, richer proof metadata, second benchmark host — each needs a family manifest and governance review.

scripts/conic_suite_report.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
raise SystemExit("cvxpy is required: pip install cvxpy") from exc
1919

2020
from conicshield.reference_correctness.conic_suite import run_conic_suite_trusted_only
21+
from conicshield.reference_correctness.report_clusters import cluster_cases_by_family
2122

2223

2324
def _main() -> int:
@@ -37,6 +38,8 @@ def _main() -> int:
3738
args = p.parse_args()
3839

3940
rows = run_conic_suite_trusted_only(cp, profile=args.profile)
41+
42+
by_family = cluster_cases_by_family(rows)
4043
payload: dict[str, Any] = {
4144
"generated_at_utc": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
4245
"profile": args.profile,
@@ -47,6 +50,12 @@ def _main() -> int:
4750
"ok": sum(1 for r in rows if r.get("status") == "ok"),
4851
"failed": [r.get("case_id") for r in rows if r.get("status") != "ok"],
4952
},
53+
"clusters": {
54+
"by_family": by_family,
55+
"families_with_failures": sorted(
56+
fam for fam, data in by_family.items() if data.get("failed_case_ids")
57+
),
58+
},
5059
}
5160
text = json.dumps(payload, indent=2)
5261
if args.out is not None:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python3
2+
"""Write benchmarks/reports/reference_authority_snapshot.json from committed release state."""
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
import json
8+
from pathlib import Path
9+
10+
from conicshield.governance.reference_authority import build_reference_authority_snapshot
11+
12+
13+
def _repo_root() -> Path:
14+
return Path(__file__).resolve().parents[1]
15+
16+
17+
def main() -> int:
18+
p = argparse.ArgumentParser(description=__doc__)
19+
p.add_argument(
20+
"--out",
21+
type=Path,
22+
default=None,
23+
help="Output path (default: benchmarks/reports/reference_authority_snapshot.json).",
24+
)
25+
p.add_argument("--check", action="store_true", help="Fail if on-disk file differs from fresh snapshot.")
26+
args = p.parse_args()
27+
28+
root = _repo_root()
29+
out = args.out or (root / "benchmarks" / "reports" / "reference_authority_snapshot.json")
30+
payload = build_reference_authority_snapshot(repo_root=root)
31+
fresh = json.dumps(payload, indent=2) + "\n"
32+
33+
def _semantic_key(text: str) -> str:
34+
data = json.loads(text)
35+
data.pop("generated_at_utc", None)
36+
return json.dumps(data, indent=2, sort_keys=True)
37+
38+
if args.check:
39+
if not out.is_file():
40+
print(f"Missing {out}; run: python {Path(__file__).name}", flush=True)
41+
return 2
42+
if _semantic_key(out.read_text(encoding="utf-8")) != _semantic_key(fresh):
43+
print(f"Stale {out}; run: python {Path(__file__).name}", flush=True)
44+
return 2
45+
print(f"OK {out}")
46+
return 0
47+
48+
out.parent.mkdir(parents=True, exist_ok=True)
49+
out.write_text(fresh, encoding="utf-8")
50+
print(out)
51+
if not payload.get("aligned"):
52+
print("warning: flagship alignment check failed in snapshot", flush=True)
53+
return 1
54+
return 0
55+
56+
57+
if __name__ == "__main__":
58+
raise SystemExit(main())

0 commit comments

Comments
 (0)