133 lines
4.5 KiB
Python
133 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify the sol-profile triage artifact against real disk state.
|
|
|
|
Recomputes the classification from the active profile directory
|
|
/root/.hermes/profiles/sol/ and diffs it against the recorded artifact.
|
|
Exit code 0 = artifact matches disk. Nonzero = mismatch.
|
|
|
|
Rules (must mirror the generator's EXACT map / ordering):
|
|
identity: .env, .env.bak-20261014T165715Z
|
|
soul: SOUL.md
|
|
config: .env.lock, config.yaml, config.yaml.bak-20261014T165715Z
|
|
state_db: state.db, state.db-shm, state.db-wal,
|
|
state.db.auto-maintenance.lock, state.db.fts_rebuild.lock,
|
|
state.db.quarantine.lock, auth.json, auth.lock,
|
|
.skills_prompt_snapshot.json, models_dev_cache.json,
|
|
models_dev_cache.etag
|
|
cache: cache, audio_cache, image_cache, context_length_cache.yaml
|
|
sessions: sessions
|
|
skills: skills
|
|
plugins: plugins, plugin-update-checks
|
|
logs: logs
|
|
backups: backups
|
|
vault: vault
|
|
extension_dir: any other directory
|
|
script: name ends with .py
|
|
config_data: name ends with .yaml or .json
|
|
other: none of the above
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
PROFILE = "/root/.hermes/profiles/sol"
|
|
ARTIFACT = "/root/.hermes/wizard-outputs/sol/sol-profile-triage-2026-10-28.json"
|
|
|
|
EXACT = {
|
|
"identity": {".env", ".env.bak-20261014T165715Z"},
|
|
"soul": {"SOUL.md"},
|
|
"config": {".env.lock", "config.yaml", "config.yaml.bak-20261014T165715Z"},
|
|
"state_db": {
|
|
"state.db", "state.db-shm", "state.db-wal",
|
|
"state.db.auto-maintenance.lock", "state.db.fts_rebuild.lock",
|
|
"state.db.quarantine.lock", "auth.json", "auth.lock",
|
|
".skills_prompt_snapshot.json", "models_dev_cache.json",
|
|
"models_dev_cache.etag",
|
|
},
|
|
"cache": {"cache", "audio_cache", "image_cache",
|
|
"context_length_cache.yaml"},
|
|
"sessions": {"sessions"},
|
|
"skills": {"skills"},
|
|
"plugins": {"plugins", "plugin-update-checks"},
|
|
"logs": {"logs"},
|
|
"backups": {"backups"},
|
|
"vault": {"vault"},
|
|
}
|
|
EXTS = {"bin", "cron", "forge", "home", "hooks", "keys", "lsp", "memories",
|
|
"pairings", "plans", "platforms", "runtime", "sandboxes", "skins",
|
|
"source-checks", "wizard-outputs", "workspace"}
|
|
|
|
|
|
def expected_category(name, is_dir):
|
|
if name in EXACT["identity"]:
|
|
return "identity"
|
|
if name in EXACT["soul"]:
|
|
return "soul"
|
|
if name in EXACT["config"]:
|
|
return "config"
|
|
if name in EXACT["state_db"]:
|
|
return "state_db"
|
|
if name in EXACT["cache"]:
|
|
return "cache"
|
|
if name in EXACT["sessions"]:
|
|
return "sessions"
|
|
if name in EXACT["skills"]:
|
|
return "skills"
|
|
if name in EXACT["plugins"]:
|
|
return "plugins"
|
|
if name in EXACT["logs"]:
|
|
return "logs"
|
|
if name in EXACT["backups"]:
|
|
return "backups"
|
|
if name in EXACT["vault"]:
|
|
return "vault"
|
|
if is_dir:
|
|
return "extension_dir"
|
|
if name.endswith(".py"):
|
|
return "script"
|
|
if name.endswith(".yaml") or name.endswith(".json"):
|
|
return "config_data"
|
|
return "other"
|
|
|
|
|
|
def main():
|
|
with open(ARTIFACT, encoding="utf-8") as fh:
|
|
art = json.load(fh)
|
|
|
|
disk = sorted(os.listdir(PROFILE))
|
|
expected = {}
|
|
for name in disk:
|
|
path = os.path.join(PROFILE, name)
|
|
expected[name] = expected_category(name, os.path.isdir(path))
|
|
|
|
recorded = {e["name"]: e.get("category") for e in art.get("entries", [])}
|
|
|
|
problems = []
|
|
if art.get("total_entries") != len(disk):
|
|
problems.append("total_entries %r != disk %d" % (art.get("total_entries"), len(disk)))
|
|
if set(recorded.keys()) != set(disk):
|
|
problems.append("entry names differ: missing=%s extra=%s" % (
|
|
sorted(set(disk) - set(recorded)), sorted(set(recorded) - set(disk))))
|
|
for n in sorted(set(disk) & set(recorded)):
|
|
if recorded[n] != expected[n]:
|
|
problems.append("category mismatch for %r: recorded=%r expected=%r" % (n, recorded[n], expected[n]))
|
|
expected_counts = {}
|
|
for n, c in expected.items():
|
|
expected_counts[c] = expected_counts.get(c, 0) + 1
|
|
if art.get("categories") != expected_counts:
|
|
problems.append("category counts %r != expected %r" % (art.get("categories"), expected_counts))
|
|
|
|
if problems:
|
|
print("FAIL")
|
|
for p in problems:
|
|
print(" -", p)
|
|
sys.exit(1)
|
|
|
|
print("PASS: artifact matches disk (%d entries, %d bytes)" % (len(disk), os.path.getsize(ARTIFACT)))
|
|
print("categories=%s" % json.dumps(art.get("categories")))
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|