Spaces:
Sleeping
Sleeping
Commit ·
d4776d0
1
Parent(s): 5c23a4e
Spec drift detection @0041177
Browse files- tools/hf_space/runner.py +82 -0
- tools/spec_sync/state.json +11 -0
tools/hf_space/runner.py
CHANGED
|
@@ -1056,6 +1056,71 @@ def _foundation_sha() -> str:
|
|
| 1056 |
return os.environ.get("SIMREADY_FOUNDATIONS_COMMIT", "unpinned")
|
| 1057 |
|
| 1058 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1059 |
def _validator_version() -> str:
|
| 1060 |
"""Version of the simready-validate package that ships in this Space."""
|
| 1061 |
try:
|
|
@@ -1316,6 +1381,23 @@ def run(
|
|
| 1316 |
summary="validator produced no result (unified streaming path returned None)",
|
| 1317 |
results_json={}, report_path=out_dir, pr_url=None,
|
| 1318 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1319 |
results_path.write_text(json.dumps(streamed), encoding="utf-8")
|
| 1320 |
results_json = streamed
|
| 1321 |
status, summary = _summarize(results_json)
|
|
|
|
| 1056 |
return os.environ.get("SIMREADY_FOUNDATIONS_COMMIT", "unpinned")
|
| 1057 |
|
| 1058 |
|
| 1059 |
+
# Path to the spec-sync state file. The state file declares which
|
| 1060 |
+
# foundation commit our hardcoded validator rules were last aligned
|
| 1061 |
+
# against. The Space's checkout includes the file at this relative
|
| 1062 |
+
# path (tools/spec_sync/state.json in the repo).
|
| 1063 |
+
_SPEC_SYNC_STATE_FILE = Path(__file__).resolve().parents[2] / "tools" / "spec_sync" / "state.json"
|
| 1064 |
+
|
| 1065 |
+
|
| 1066 |
+
def _check_foundation_spec_drift() -> dict:
|
| 1067 |
+
"""Check whether NVIDIA/simready-foundation has new commits to its
|
| 1068 |
+
spec dir since we last synced our hardcoded rules.
|
| 1069 |
+
|
| 1070 |
+
Cheap event-driven drift detection (one GitHub API call per run,
|
| 1071 |
+
soft-fails on errors). The validator surfaces drift in results.json
|
| 1072 |
+
so the dashboard can warn operators that hardcoded rules may be
|
| 1073 |
+
stale relative to the source of truth. Auto-update is the
|
| 1074 |
+
follow-up step (spec-sync workflow opens a PR to refresh rules).
|
| 1075 |
+
|
| 1076 |
+
Returns a dict the dashboard renders; never raises.
|
| 1077 |
+
"""
|
| 1078 |
+
out: dict = {"checked": False}
|
| 1079 |
+
try:
|
| 1080 |
+
if not _SPEC_SYNC_STATE_FILE.is_file():
|
| 1081 |
+
out["reason"] = "state file missing"
|
| 1082 |
+
return out
|
| 1083 |
+
state = json.loads(_SPEC_SYNC_STATE_FILE.read_text(encoding="utf-8"))
|
| 1084 |
+
last_sync_sha = state.get("foundation_commit_sha") or ""
|
| 1085 |
+
last_sync_at = state.get("synced_at") or ""
|
| 1086 |
+
watched_path = state.get("watched_path") or "nv_core/sr_specs/docs"
|
| 1087 |
+
repo = state.get("foundation_repo") or "NVIDIA/simready-foundation"
|
| 1088 |
+
except Exception as e:
|
| 1089 |
+
out["reason"] = f"could not read state: {type(e).__name__}: {e}"
|
| 1090 |
+
return out
|
| 1091 |
+
try:
|
| 1092 |
+
import urllib.request
|
| 1093 |
+
url = (f"https://api.github.com/repos/{repo}/commits"
|
| 1094 |
+
f"?path={watched_path}&per_page=1")
|
| 1095 |
+
req = urllib.request.Request(url)
|
| 1096 |
+
req.add_header("Accept", "application/vnd.github.v3+json")
|
| 1097 |
+
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_VALIDATOR_TOKEN")
|
| 1098 |
+
if token:
|
| 1099 |
+
req.add_header("Authorization", f"Bearer {token}")
|
| 1100 |
+
with urllib.request.urlopen(req, timeout=8) as resp:
|
| 1101 |
+
data = json.loads(resp.read())
|
| 1102 |
+
except Exception as e:
|
| 1103 |
+
out["reason"] = f"github api: {type(e).__name__}: {e}"
|
| 1104 |
+
return out
|
| 1105 |
+
if not isinstance(data, list) or not data:
|
| 1106 |
+
out["reason"] = "no commit data"
|
| 1107 |
+
return out
|
| 1108 |
+
current = data[0] or {}
|
| 1109 |
+
current_sha = current.get("sha") or ""
|
| 1110 |
+
current_at = (current.get("commit") or {}).get("committer", {}).get("date") or ""
|
| 1111 |
+
drifted = bool(current_sha) and current_sha != last_sync_sha
|
| 1112 |
+
return {
|
| 1113 |
+
"checked": True,
|
| 1114 |
+
"drifted": drifted,
|
| 1115 |
+
"current_sha": current_sha,
|
| 1116 |
+
"current_at": current_at,
|
| 1117 |
+
"last_sync_sha": last_sync_sha,
|
| 1118 |
+
"last_sync_at": last_sync_at,
|
| 1119 |
+
"repo": repo,
|
| 1120 |
+
"watched_path": watched_path,
|
| 1121 |
+
}
|
| 1122 |
+
|
| 1123 |
+
|
| 1124 |
def _validator_version() -> str:
|
| 1125 |
"""Version of the simready-validate package that ships in this Space."""
|
| 1126 |
try:
|
|
|
|
| 1381 |
summary="validator produced no result (unified streaming path returned None)",
|
| 1382 |
results_json={}, report_path=out_dir, pr_url=None,
|
| 1383 |
)
|
| 1384 |
+
# Event-driven foundation spec drift check. One GitHub API
|
| 1385 |
+
# call per run; soft-fails so network hiccups don't block
|
| 1386 |
+
# validation. The dashboard renders a notice if drifted=true.
|
| 1387 |
+
drift = _check_foundation_spec_drift()
|
| 1388 |
+
if drift.get("checked"):
|
| 1389 |
+
if drift.get("drifted"):
|
| 1390 |
+
out(f" ⚠ spec drift: foundation HEAD={drift.get('current_sha', '')[:8]} "
|
| 1391 |
+
f"@ {drift.get('current_at', '')}, last synced "
|
| 1392 |
+
f"{drift.get('last_sync_sha', '')[:8]} @ {drift.get('last_sync_at', '')} "
|
| 1393 |
+
f"— hardcoded rules may be stale; run spec-sync to refresh")
|
| 1394 |
+
else:
|
| 1395 |
+
out(f" spec sync: in sync with foundation HEAD "
|
| 1396 |
+
f"{drift.get('current_sha', '')[:8]}")
|
| 1397 |
+
else:
|
| 1398 |
+
out(f" spec sync: skipped ({drift.get('reason', 'unknown')})")
|
| 1399 |
+
streamed["spec_drift"] = drift
|
| 1400 |
+
|
| 1401 |
results_path.write_text(json.dumps(streamed), encoding="utf-8")
|
| 1402 |
results_json = streamed
|
| 1403 |
status, summary = _summarize(results_json)
|
tools/spec_sync/state.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_doc": "Drift state for NVIDIA/simready-foundation specs. The validator hits the GitHub API on every run; if the latest commit touching nv_core/sr_specs/docs differs from foundation_commit_sha below, the validator surfaces a 'spec drift' warning and (future) triggers the spec-sync workflow to auto-update hardcoded rules.",
|
| 3 |
+
"foundation_repo": "NVIDIA/simready-foundation",
|
| 4 |
+
"watched_path": "nv_core/sr_specs/docs",
|
| 5 |
+
"foundation_commit_sha": "805d2c50179a9878c89b0f41baaa0ecafe47c3d7",
|
| 6 |
+
"synced_at": "2026-06-02T00:00:00Z",
|
| 7 |
+
"synced_by": "initial-setup",
|
| 8 |
+
"rules_pinned_against": [
|
| 9 |
+
"AA.002 supported-file-types (validate.py:_AA_002_ALLOWED)"
|
| 10 |
+
]
|
| 11 |
+
}
|