98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Sol lane — daily-ledger triage (fresh).
|
|
|
|
Recomputes the classification straight from the raw daily logs under
|
|
/root/.hermes/wizard-outputs (no cache), and writes a self-contained
|
|
artifact: triage-daily-2026-10-22.json + triage-daily-2026-10-22.md.
|
|
|
|
AGE_CLASSIFY rule: age <= 24h -> ACTIVE; age <= 168h -> WATCH; else STALE.
|
|
The 7 ids are the primary daily-ledger lanes the repository's own
|
|
triage_check.py already names (forge, ledger, null, quill, sphinx, sol, spark).
|
|
"""
|
|
import glob
|
|
import json
|
|
import os
|
|
from datetime import datetime, timezone
|
|
|
|
BASE = "/root/.hermes/wizard-outputs"
|
|
OUT_JSON = os.path.join(BASE, "sol", "triage-daily-2026-10-22.json")
|
|
OUT_MD = os.path.join(BASE, "sol", "triage-daily-2026-10-22.md")
|
|
|
|
PRIMARY = ["forge", "ledger", "null", "quill", "sphinx", "sol", "spark"]
|
|
|
|
|
|
def classify(age_sec):
|
|
age_h = age_sec / 3600.0
|
|
if age_h <= 24.0:
|
|
return "ACTIVE"
|
|
if age_h <= 168.0:
|
|
return "WATCH"
|
|
return "STALE"
|
|
|
|
|
|
def main():
|
|
now = datetime.now(timezone.utc)
|
|
lanes = []
|
|
for pid in PRIMARY:
|
|
pattern = os.path.join(BASE, pid + "*-*.txt")
|
|
files = sorted(glob.glob(pattern))
|
|
if not files:
|
|
raise SystemExit("no raw logs for lane %s" % pid)
|
|
latest = max(files, key=os.path.getmtime)
|
|
mtime = os.path.getmtime(latest)
|
|
age_sec = (now - datetime.fromtimestamp(mtime, tz=timezone.utc)).total_seconds()
|
|
lanes.append({
|
|
"id": pid,
|
|
"latest_log": os.path.basename(latest),
|
|
"latest_mtime_utc": datetime.fromtimestamp(mtime, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
"daily_log_count": len(files),
|
|
"age_hours": round(age_sec / 3600.0, 1),
|
|
"status": classify(age_sec),
|
|
})
|
|
|
|
artifact = {
|
|
"generated_utc": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
"classify_rule": "AGE_CLASSIFY: ACTIVE <=24h, WATCH <=168h, else STALE",
|
|
"source": "raw daily logs under %s" % BASE,
|
|
"lanes": lanes,
|
|
}
|
|
with open(OUT_JSON, "w", encoding="utf-8") as fh:
|
|
json.dump(artifact, fh, indent=2)
|
|
|
|
lines = []
|
|
lines.append("# Daily-ledger triage — sol — 2026-10-22")
|
|
lines.append("")
|
|
lines.append("Recomputed from raw logs at %s." % now.strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
lines.append("")
|
|
lines.append("| lane | latest log | latest mtime (UTC) | logs | age (h) | status |")
|
|
lines.append("|---|---|---|---|---|---|")
|
|
for e in sorted(lanes, key=lambda x: x["id"]):
|
|
lines.append("| %s | %s | %s | %d | %.1f | %s |" % (
|
|
e["id"], e["latest_log"], e["latest_mtime_utc"], e["daily_log_count"],
|
|
e["age_hours"], e["status"]))
|
|
lines.append("")
|
|
lines.append("## Summary")
|
|
lines.append("")
|
|
counts = {}
|
|
for e in lanes:
|
|
counts[e["status"]] = counts.get(e["status"], 0) + 1
|
|
lines.append("- **%d** lanes total" % len(lanes))
|
|
for s in ("ACTIVE", "WATCH", "STALE"):
|
|
lines.append("- **%d** %s" % (counts.get(s, 0), s))
|
|
lines.append("")
|
|
with open(OUT_MD, "w", encoding="utf-8") as fh:
|
|
fh.write("\n".join(lines))
|
|
|
|
print("WROTE", OUT_JSON)
|
|
print("WROTE", OUT_MD)
|
|
for e in sorted(lanes, key=lambda x: x["id"]):
|
|
print(" %-6s %-24s %s age=%-6.1fh %s" % (
|
|
e["id"], e["latest_log"], e["latest_mtime_utc"], e["age_hours"], e["status"]))
|
|
print(" counts:", {"ACTIVE": counts.get("ACTIVE", 0),
|
|
"WATCH": counts.get("WATCH", 0),
|
|
"STALE": counts.get("STALE", 0)})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|