diff --git a/wizard-work/sol/build_lanes.py b/wizard-work/sol/build_lanes.py new file mode 100644 index 0000000..02cc66d --- /dev/null +++ b/wizard-work/sol/build_lanes.py @@ -0,0 +1,74 @@ +import json, os, glob, datetime + +BASE = "/root/.hermes/wizard-outputs" +LANES = ["forge", "ledger", "null", "quill", "sphinx", "sol", "spark"] +OUT = "/root/.hermes/wizard-outputs/sol" + +def classify(age_h): + if age_h <= 24.0: + return "ACTIVE" + if age_h <= 168.0: + return "WATCH" + return "STALE" + +now = datetime.datetime.now(datetime.timezone.utc) + +lanes = [] +counts = {} +for pid in LANES: + pat = os.path.join(BASE, pid + "-*.txt") + files = glob.glob(pat) + if not files: + raise SystemExit("NO LOGS for lane: " + pid) + latest = max(files, key=os.path.getmtime) + mt = os.path.getmtime(latest) + mtime_utc = datetime.datetime.fromtimestamp(mt, tz=datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + age_h = (now - datetime.datetime.fromtimestamp(mt, tz=datetime.timezone.utc)).total_seconds() / 3600.0 + status = classify(age_h) + lanes.append({ + "id": pid, + "latest_log": os.path.basename(latest), + "latest_mtime_utc": mtime_utc, + "age_h": round(age_h, 2), + "status": status, + }) + counts[status] = counts.get(status, 0) + 1 + +record = { + "artifact": "sol-lane-status-2026-10-27.json", + "source": "daily ledger logs under /root/.hermes/wizard-outputs/-*.txt (latest by mtime)", + "measured_at_utc": now.strftime("%Y-%m-%dT%H:%M:%SZ"), + "status_rule": "ACTIVE = latest log within 24h; WATCH = 24h-168h; STALE = >168h", + "lanes": lanes, + "status_counts": counts, +} + +with open(os.path.join(OUT, "sol-lane-status-2026-10-27.json"), "w") as f: + json.dump(record, f, indent=2) + f.write("\n") + +# Written result (plain-text triage verdict). +lines = ["# Sol Daily-Lane Status - 2026-10-27 (measured)", ""] +lines.append("Classification measured live from the on-disk mtimes of each primary lane's daily ledger logs under /root/.hermes/wizard-outputs/.") +lines.append("Rules: ACTIVE = latest log within 24h; WATCH = 24h-168h; STALE = >168h.") +lines.append("") +lines.append("## Verdict") +lines.append("") +lines.append("- status_counts: %s" % json.dumps(counts)) +lines.append("") +lines.append("## Per-lane table") +lines.append("") +lines.append("| Lane | Latest daily log | Last written (UTC) | Age (h) | Status |") +lines.append("|-------|------------------|--------------------|---------|--------|") +for ln in lanes: + lines.append("| %s | %s | %s | %.2f | %s |" % (ln["id"], ln["latest_log"], ln["latest_mtime_utc"], ln["age_h"], ln["status"])) +lines.append("") + +with open(os.path.join(OUT, "sol-lane-status-2026-10-27.md"), "w") as f: + f.write("\n".join(lines)) + +print("measured_at_utc:", record["measured_at_utc"]) +print("status_counts:", json.dumps(counts)) +print("lanes:") +for ln in lanes: + print(" ", ln["id"], ln["latest_log"], ln["latest_mtime_utc"], "age=%.2f" % ln["age_h"], "->", ln["status"]) diff --git a/wizard-work/sol/check_lanes.py b/wizard-work/sol/check_lanes.py new file mode 100755 index 0000000..5d28bba --- /dev/null +++ b/wizard-work/sol/check_lanes.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""CHECK (Sol daily-lane triage): independent recompute of ACTIVE/WATCH/STALE from the +raw daily ledger logs under /root/.hermes/wizard-outputs/-*.txt, compared against +the committed artifact sol-lane-status-2026-10-27.json. + +Independent recompute: derives status from raw mtimes only. The committed JSON's +statuses/latests are then compared against this recompute. A PASS = 0 proves the +committed artifact matches reality; any mismatch = nonzero. + +Exit code IS the verdict: 0 = correct, nonzero = wrong. +""" +import glob +import json +import os +import sys +from datetime import datetime, timezone + +BASE = "/root/.hermes/wizard-outputs" +JSON_PATH = "/root/.hermes/wizard-outputs/sol/sol-lane-status-2026-10-27.json" +LANES = ["forge", "ledger", "null", "quill", "sphinx", "sol", "spark"] + + +def recompute(): + now = datetime.now(timezone.utc) + out = {} + for pid in LANES: + files = glob.glob(os.path.join(BASE, pid + "-*.txt")) + if not files: + raise SystemExit("no daily logs for lane " + pid) + latest = max(files, key=os.path.getmtime) + mt = os.path.getmtime(latest) + mtime_utc = datetime.fromtimestamp(mt, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + age_h = (now - datetime.fromtimestamp(mt, tz=timezone.utc)).total_seconds() / 3600.0 + if age_h <= 24.0: + status = "ACTIVE" + elif age_h <= 168.0: + status = "WATCH" + else: + status = "STALE" + out[pid] = {"latest_log": os.path.basename(latest), "latest_mtime_utc": mtime_utc, + "age_h": round(age_h, 2), "status": status} + return out + + +def main(): + failures = [] + + # Load committed artifact. + if not os.path.exists(JSON_PATH): + print("FAIL: artifact missing: " + JSON_PATH) + sys.exit(1) + with open(JSON_PATH, encoding="utf-8") as fh: + art = json.load(fh) + + rec = recompute() + + # Compare lane by lane. + for pid in LANES: + r = rec[pid] + hit = art.get("lanes", []) + row = next((x for x in hit if x.get("id") == pid), None) + if row is None: + failures.append("lane " + pid + " missing from artifact lanes") + print("FAIL: " + pid + " missing") + continue + if row.get("latest_log") != r["latest_log"]: + failures.append("%s: latest_log %s != %s" % (pid, row.get("latest_log"), r["latest_log"])) + print("FAIL: " + pid + " latest_log") + if row.get("latest_mtime_utc") != r["latest_mtime_utc"]: + failures.append("%s: mtime %s != %s" % (pid, row.get("latest_mtime_utc"), r["latest_mtime_utc"])) + print("FAIL: " + pid + " mtime") + if row.get("status") != r["status"]: + failures.append("%s: status %s != %s" % (pid, row.get("status"), r["status"])) + print("FAIL: " + pid + " status") + else: + print("PASS: %s latest=%s age=%.2f status=%s" % (pid, r["latest_log"], r["age_h"], r["status"])) + + # Compare status_counts. + counts = {} + for x in art.get("lanes", []): + counts[x.get("status")] = counts.get(x.get("status"), 0) + 1 + if counts != rec_counts(rec): + failures.append("counts %s != recompute %s" % (counts, rec_counts(rec))) + + if failures: + print("FAIL: triage artifact does not match independent recompute") + for f in failures: + print(" - " + f) + sys.exit(1) + + print("PASS: 7/7 lanes match independent recompute from raw daily logs") + print(" status_counts=%s" % json.dumps(rec_counts(rec))) + + +def rec_counts(rec): + c = {} + for v in rec.values(): + c[v["status"]] = c.get(v["status"], 0) + 1 + return c + + +if __name__ == "__main__": + main() diff --git a/wizard-work/sol/sol-lane-status-2026-10-27.json b/wizard-work/sol/sol-lane-status-2026-10-27.json new file mode 100644 index 0000000..8cf9186 --- /dev/null +++ b/wizard-work/sol/sol-lane-status-2026-10-27.json @@ -0,0 +1,60 @@ +{ + "artifact": "sol-lane-status-2026-10-27.json", + "source": "daily ledger logs under /root/.hermes/wizard-outputs/-*.txt (latest by mtime)", + "measured_at_utc": "2026-10-27T19:42:03Z", + "status_rule": "ACTIVE = latest log within 24h; WATCH = 24h-168h; STALE = >168h", + "lanes": [ + { + "id": "forge", + "latest_log": "forge-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:56:18Z", + "age_h": 268.76, + "status": "STALE" + }, + { + "id": "ledger", + "latest_log": "ledger-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:47:33Z", + "age_h": 268.91, + "status": "STALE" + }, + { + "id": "null", + "latest_log": "null-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:47:52Z", + "age_h": 268.9, + "status": "STALE" + }, + { + "id": "quill", + "latest_log": "quill-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:47:07Z", + "age_h": 268.92, + "status": "STALE" + }, + { + "id": "sphinx", + "latest_log": "sphinx-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:50:35Z", + "age_h": 268.86, + "status": "STALE" + }, + { + "id": "sol", + "latest_log": "sol-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:49:04Z", + "age_h": 268.88, + "status": "STALE" + }, + { + "id": "spark", + "latest_log": "spark-2026-10-16-1446.txt", + "latest_mtime_utc": "2026-10-16T14:56:18Z", + "age_h": 268.76, + "status": "STALE" + } + ], + "status_counts": { + "STALE": 7 + } +} diff --git a/wizard-work/sol/sol-lane-status-2026-10-27.md b/wizard-work/sol/sol-lane-status-2026-10-27.md new file mode 100644 index 0000000..fcab0f3 --- /dev/null +++ b/wizard-work/sol/sol-lane-status-2026-10-27.md @@ -0,0 +1,20 @@ +# Sol Daily-Lane Status - 2026-10-27 (measured) + +Classification measured live from the on-disk mtimes of each primary lane's daily ledger logs under /root/.hermes/wizard-outputs/. +Rules: ACTIVE = latest log within 24h; WATCH = 24h-168h; STALE = >168h. + +## Verdict + +- status_counts: {"STALE": 7} + +## Per-lane table + +| Lane | Latest daily log | Last written (UTC) | Age (h) | Status | +|-------|------------------|--------------------|---------|--------| +| forge | forge-2026-10-16-1446.txt | 2026-10-16T14:56:18Z | 268.76 | STALE | +| ledger | ledger-2026-10-16-1446.txt | 2026-10-16T14:47:33Z | 268.91 | STALE | +| null | null-2026-10-16-1446.txt | 2026-10-16T14:47:52Z | 268.90 | STALE | +| quill | quill-2026-10-16-1446.txt | 2026-10-16T14:47:07Z | 268.92 | STALE | +| sphinx | sphinx-2026-10-16-1446.txt | 2026-10-16T14:50:35Z | 268.86 | STALE | +| sol | sol-2026-10-16-1446.txt | 2026-10-16T14:49:04Z | 268.88 | STALE | +| spark | spark-2026-10-16-1446.txt | 2026-10-16T14:56:18Z | 268.76 | STALE |