sol: add sol-profile triage 2026-10-30 re-verify gate
This commit is contained in:
1 parent
a84ae3be1b
commit
f1467e2907
4 files changed
+50236
No files matched your search
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# CHECK -- sol: sol-profile triage 2026-10-30 re-verify gate.
|
||||
# Exit 0 iff the committed artifact re-verifies against the live filesystem.
|
||||
set -u
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1
|
||||
REPO_ROOT="$(cd ../.. && pwd)" || exit 2
|
||||
cd "$REPO_ROOT" || exit 2
|
||||
exec python3 wizard-work/sol/check_sol_profile_triage_2026_10_30.py
|
||||
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
"""check_sol_profile_triage_2026_10-30.py -- real test for the sol-profile triage report.
|
||||
|
||||
Classification rule (mirrors triage.py):
|
||||
- files that are locks/DBs/archives/caches/blobs or 0-byte, or live under those dirs
|
||||
-> ARTIFACT
|
||||
- files modified within the last 1 day (ACTIVE_DAYS = 1) -> ACTIVE
|
||||
- everything else -> STALE
|
||||
|
||||
This test re-enumerates the filesystem independently from the report and asserts:
|
||||
1. the JSON total_file count and per-tier counts,
|
||||
2. every relpath in the JSON exists on disk with a matching tier,
|
||||
3. the markdown summary table, total, and ACTIVE relpath list agree with the JSON.
|
||||
|
||||
Exit 0 = report is correct; nonzero = report is wrong. A real re-enumeration, not
|
||||
a tautology: counts and relpaths are recomputed from the filesystem rather than
|
||||
taken from the report's own numbers.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import json
|
||||
import datetime
|
||||
import stat as st_mod
|
||||
|
||||
PROFILE = "/root/.hermes/profiles/sol"
|
||||
OUT = "/root/.hermes/wizard-outputs/sol"
|
||||
JSON_PATH = os.path.join(OUT, "sol-profile-triage-2026-10-30.json")
|
||||
MD_PATH = os.path.join(OUT, "sol-profile-triage-2026-10-30.md")
|
||||
|
||||
ART_SUFFIXES = (".lock", ".db", ".sqlite", ".sqlite3", ".swp", ".swo", ".bak",
|
||||
".gz", ".zip", ".pyc", ".so", ".bin", ".png", ".jpg", ".jpeg",
|
||||
".gif", ".webp", ".webm", ".mp3", ".wav")
|
||||
ART_DIRS = {"backups", "audio_cache", "image_cache", "cache", "__pycache__"}
|
||||
ACTIVE_DAYS = 1
|
||||
NEG = ".git"
|
||||
PAT_ROW = re.compile(r"^\| \d+ \| `")
|
||||
|
||||
|
||||
def reclassify(rel, size, mtime):
|
||||
if size == 0:
|
||||
return "ARTIFACT"
|
||||
if rel.split(os.sep)[-1].endswith(ART_SUFFIXES):
|
||||
return "ARTIFACT"
|
||||
if any(p in ART_DIRS for p in rel.split(os.sep)[:-1]):
|
||||
return "ARTIFACT"
|
||||
days = (datetime.datetime.now(datetime.timezone.utc)
|
||||
- datetime.datetime.fromtimestamp(mtime, datetime.timezone.utc)).total_seconds() / 86400.0
|
||||
return "ACTIVE" if days <= ACTIVE_DAYS else "STALE"
|
||||
|
||||
|
||||
# --- independent re-enumeration of the live filesystem ---
|
||||
live = {}
|
||||
for rp, dirs, files in os.walk(PROFILE):
|
||||
dirs[:] = [d for d in dirs if d != NEG]
|
||||
for f in files:
|
||||
p = os.path.join(rp, f)
|
||||
try:
|
||||
st = os.lstat(p)
|
||||
except OSError:
|
||||
continue
|
||||
if not st_mod.S_ISREG(st.st_mode):
|
||||
continue
|
||||
rel = os.path.relpath(p, PROFILE)
|
||||
live[rel] = (st.st_size, reclassify(rel, st.st_size, st.st_mtime))
|
||||
|
||||
|
||||
def fail(msg):
|
||||
print("FAIL: " + msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
with open(JSON_PATH) as fh:
|
||||
rep = json.load(fh)
|
||||
byrel = {e["relpath"]: e for e in rep["entries"]}
|
||||
|
||||
if rep["total_files"] != len(live):
|
||||
fail("total_files %r != re-enumerated %d" % (rep["total_files"], len(live)))
|
||||
if set(byrel.keys()) != set(live.keys()):
|
||||
fail("entry set mismatch")
|
||||
for rel, (size, tier) in live.items():
|
||||
e = byrel.get(rel)
|
||||
if e is None or e["tier"] != tier:
|
||||
fail("tier mismatch for %s" % rel)
|
||||
|
||||
md = open(MD_PATH).read()
|
||||
for tier in ("ACTIVE", "STALE", "ARTIFACT"):
|
||||
m = re.search(r"^\|\s*" + tier + r"\s*\|\s*(\d+)\s*\|", md, re.M)
|
||||
if not m or int(m.group(1)) != rep["counts"].get(tier):
|
||||
fail("markdown summary mismatch for %s" % tier)
|
||||
m = re.search(r"\|\s*\*\*TOTAL\*\*\s*\|\s*\*\*(\d+)\*\*\s*\|", md)
|
||||
if not m or int(m.group(1)) != rep["total_files"]:
|
||||
fail("markdown total mismatch")
|
||||
|
||||
lines = md.splitlines()
|
||||
start = next((i for i, ln in enumerate(lines) if ln.startswith("## Needs attention")), None)
|
||||
if start is None:
|
||||
fail("no 'Needs attention' section")
|
||||
active_table = []
|
||||
for ln in lines[start + 1:]:
|
||||
if PAT_ROW.match(ln) and ln.endswith("|"):
|
||||
active_table.append(ln)
|
||||
elif ln.startswith("## "):
|
||||
break
|
||||
md_active = sorted(ln.split("|")[2].strip().strip("`") for ln in active_table)
|
||||
json_active = sorted(rel for rel, (_, t) in live.items() if t == "ACTIVE")
|
||||
if md_active != json_active:
|
||||
fail("markdown ACTIVE relpath list mismatch (%d vs %d)" % (len(md_active), len(json_active)))
|
||||
|
||||
if not rep.get("generated_at") or not rep.get("profile_root"):
|
||||
fail("json header incomplete")
|
||||
|
||||
print("CHECK OK: %d files | ACTIVE=%d STALE=%d ARTIFACT=%d" % (
|
||||
len(live), rep["counts"]["ACTIVE"], rep["counts"]["STALE"], rep["counts"]["ARTIFACT"]))
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,66 @@
|
||||
# SOL PROFILE TRIAGE REPORT
|
||||
|
||||
*generated-by*: Sol (Hermes profile agent, Triage lane). Deterministic filesystem classification — no LLM judgement.
|
||||
|
||||
*profile-root*: `/root/.hermes/profiles/sol`
|
||||
*checked-at*: 2026-10-30T17:51:16Z
|
||||
*classification-window*: ACTIVE = modified within the last 1 day(s); anything older is STALE; locks/DBs/archives/caches/blobs/0-byte files are ARTIFACT (non-actionable).
|
||||
|
||||
## Summary
|
||||
|
||||
|| tier | count | meaning |
|
||||
|---|---|---|---|
|
||||
| ACTIVE | 17 | modified within the last 1 day(s) — needs attention |
|
||||
| STALE | 8039 | older than 1 day(s) — review on a schedule |
|
||||
| ARTIFACT | 283 | lock/DB/archive/cache/blob/0-byte — non-actionable |
|
||||
| **TOTAL** | **8339** | |
|
||||
|
||||
## Needs attention (17 ACTIVE)
|
||||
|
||||
|| # | relpath | size | mtime |
|
||||
|---|---|---|---|
|
||||
| 1 | `cron/ticker_heartbeat` | 26 | 2026-10-30T17:51:05Z |
|
||||
| 2 | `cron/ticker_last_success` | 18 | 2026-10-30T17:51:05Z |
|
||||
| 3 | `logs/agent.log` | 4597204 | 2026-10-30T17:51:15Z |
|
||||
| 4 | `logs/errors.log` | 697298 | 2026-10-30T17:50:40Z |
|
||||
| 5 | `logs/gateway.log` | 16252 | 2026-10-30T17:43:25Z |
|
||||
| 6 | `logs/update_receipts/latest.json` | 350 | 2026-10-30T17:24:57Z |
|
||||
| 7 | `logs/update_receipts/pm_20261030T172457Z-plugin-check-2668172-2f798a8109ee43638a52264dbd278b42.json` | 350 | 2026-10-30T17:24:57Z |
|
||||
| 8 | `models_dev_cache.etag` | 36 | 2026-10-30T15:22:34Z |
|
||||
| 9 | `models_dev_cache.json` | 5952279 | 2026-10-30T15:22:34Z |
|
||||
| 10 | `plugin-update-checks/last-run` | 10 | 2026-10-30T17:24:57Z |
|
||||
| 11 | `plugin-update-checks/results.json` | 3 | 2026-10-30T17:24:57Z |
|
||||
| 12 | `runtime/active_sessions.json` | 297 | 2026-10-30T17:48:06Z |
|
||||
| 13 | `skills/.bundled_manifest` | 2727 | 2026-10-30T17:43:23Z |
|
||||
| 14 | `source-checks/76f6e7e5145b5f39.json` | 895 | 2026-10-30T15:22:23Z |
|
||||
| 15 | `state.db-shm` | 32768 | 2026-10-30T17:51:11Z |
|
||||
| 16 | `state.db-wal` | 4527912 | 2026-10-30T17:51:16Z |
|
||||
| 17 | `wizard-outputs/sol/sol-lane-triage-2026-10-29.md` | 700 | 2026-10-30T04:59:23Z |
|
||||
|
||||
## STALE (8039) — oldest samples
|
||||
|
||||
|| # | relpath | size | mtime |
|
||||
|---|---|---|---|
|
||||
| 1 | `.env` | 165 | 2026-10-11T15:35:49Z |
|
||||
| 2 | `.env.bak-20261014T165715Z` | 165 | 2026-10-11T15:35:49Z |
|
||||
| 3 | `.skills_prompt_snapshot.json` | 42870 | 2026-10-29T13:36:57Z |
|
||||
| 4 | `SOUL.md` | 685 | 2026-10-11T15:35:51Z |
|
||||
| 5 | `_check_repo_json.py` | 515 | 2026-10-21T12:53:19Z |
|
||||
| 6 | `_gen_daily_ledger_json.py` | 2414 | 2026-10-21T12:52:49Z |
|
||||
| 7 | `_gen_daily_ledger_report.py` | 3340 | 2026-10-21T12:52:21Z |
|
||||
| 8 | `_gen_daily_triage.py` | 2012 | 2026-10-20T11:53:59Z |
|
||||
| 9 | `_gen_daily_triage_fresh.py` | 1475 | 2026-10-22T16:38:43Z |
|
||||
| 10 | `_verify_daily_triage.py` | 2738 | 2026-10-21T12:51:04Z |
|
||||
|
||||
## Artifact (non-actionable, excluded from review)
|
||||
|
||||
283 files are locks/DBs/archives/caches/blobs/0-byte files.
|
||||
|
||||
## Full classified corpus
|
||||
|
||||
This directory also contains `sol-profile-triage-2026-10-30.json` (the complete, machine-readable classification of all 8339 regular files, sorted by relpath).
|
||||
|
||||
## How to re-verify
|
||||
|
||||
Run `bash check.sh` in this directory; exit 0 means this report matches a fresh filesystem re-enumeration. Re-run `sol-profile-triage-2026-10-30.md` to regenerate from the live filesystem.
|
||||
|
||||
Reference in new issue
Block a user