105 lines
4.1 KiB
Python
105 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Independent re-check for sol-profile-skill-triage-2026-10-24.
|
|
|
|
Recomputes the classification straight from the live filesystem (manifest,
|
|
category overlay skill subdirs, .usage.json) and diffs it against the written
|
|
JSON artifact. Exit 0 = artifact is correct; nonzero = artifact is wrong or
|
|
missing. No fallbacks: the exit code carries the verdict.
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
SKILLS = Path("/root/.hermes/profiles/sol/skills")
|
|
ARTIFACT = Path("/root/.hermes/wizard-outputs/sol/sol-profile-skill-triage-2026-10-24.json")
|
|
REPO_ARTIFACT = Path("/root/troupe-standup/wizard-work/sol/sol-profile-skill-triage-2026-10-24.json")
|
|
|
|
failures = []
|
|
|
|
|
|
def read_names():
|
|
names = []
|
|
for line in SKILLS.joinpath(".bundled_manifest").read_text(encoding="utf-8").splitlines():
|
|
line = line.strip()
|
|
if line and not line.startswith("#") and ":" in line:
|
|
names.append(line.split(":", 1)[0].strip())
|
|
return names
|
|
|
|
|
|
def read_deployed():
|
|
deployed = set()
|
|
n = 0
|
|
for entry in sorted(SKILLS.iterdir()):
|
|
if not entry.is_dir() or entry.name.startswith("."):
|
|
continue
|
|
n += 1
|
|
for sub in entry.iterdir():
|
|
if sub.is_dir() and not sub.name.startswith("."):
|
|
deployed.add(sub.name)
|
|
return deployed, n
|
|
|
|
|
|
def main():
|
|
names = read_names()
|
|
deployed, overlays = read_deployed()
|
|
usage = json.loads(SKILLS.joinpath(".usage.json").read_text(encoding="utf-8"))
|
|
used = sorted(n for n in names if usage.get(n, {}).get("state") == "active")
|
|
|
|
truth = {
|
|
"manifest_count": len(names),
|
|
"deployed_count": len(deployed),
|
|
"category_overlay_count": overlays,
|
|
"active_usage_tracked": len(used),
|
|
"not_deployed": sorted(set(names) - deployed),
|
|
"extras": sorted(deployed - set(names)),
|
|
"skill_rows": [
|
|
{
|
|
"skill": n,
|
|
"deployed": n in deployed,
|
|
"usage_state": usage.get(n, {}).get("state"),
|
|
"use_count": usage.get(n, {}).get("use_count"),
|
|
"class": (
|
|
"deployed + usage-tracked / active" if (n in deployed and usage.get(n, {}).get("state") == "active")
|
|
else ("deployed (dir), no usage record" if n in deployed else
|
|
("usage-tracked / active (not in profile)" if usage.get(n, {}).get("state") == "active" else "not deployed / no usage record"))
|
|
),
|
|
}
|
|
for n in sorted(names)
|
|
],
|
|
}
|
|
|
|
if not ARTIFACT.exists():
|
|
print("FAIL: artifact missing " + str(ARTIFACT))
|
|
sys.exit(1)
|
|
recorded = json.loads(ARTIFACT.read_text(encoding="utf-8"))
|
|
|
|
for k in ("manifest_count", "deployed_count", "category_overlay_count", "active_usage_tracked", "not_deployed", "extras"):
|
|
if recorded.get(k) != truth[k]:
|
|
failures.append("%s artifact=%r truth=%r" % (k, recorded.get(k), truth[k]))
|
|
|
|
rec_rows = {r["skill"]: r for r in recorded.get("skill_rows", [])}
|
|
if len(rec_rows) != len(truth["skill_rows"]):
|
|
failures.append("skill_rows count %d != truth %d" % (len(rec_rows), len(truth["skill_rows"])))
|
|
for r in truth["skill_rows"]:
|
|
if rec_rows.get(r["skill"]) != r:
|
|
failures.append("row mismatch %s: %r != %r" % (r["skill"], rec_rows.get(r["skill"]), r))
|
|
|
|
if recorded.get("generated_at") == "" or recorded.get("generated_at") is None:
|
|
failures.append("generated_at missing/empty")
|
|
|
|
if failures:
|
|
print("FAIL: sol-profile-skill-triage-2026-10-24 artifact incorrect")
|
|
for f in failures:
|
|
print(" - " + f)
|
|
sys.exit(1)
|
|
|
|
print("PASS: sol-profile-skill-triage-2026-10-24 artifact verified against live filesystem")
|
|
print(" manifest=%d deployed=%d overlays=%d usage_tracked=%d not_deployed=%d extras=%d rows=%d" % (
|
|
truth["manifest_count"], truth["deployed_count"], truth["category_overlay_count"],
|
|
truth["active_usage_tracked"], len(truth["not_deployed"]), len(truth["extras"]), len(truth["skill_rows"])))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|