sol: add sol-profile-triage-2026-11-03 manifest (69 profile entries, rule-based triage)

This commit is contained in:
sol committed 2026-11-03 13:43:09 +00:00
1 parent 03b2a04f24
commit 7c45fceb82
4 files changed
+622 -58772

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# CHECK -- sol: sol-profile-triage-2026-11-03 manifest verification gate.
# Exit 0 iff the committed classification re-derives from the live profile
# directory (independent of the generator). The exit code IS the verdict.
set -u
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 2
exec python3 "$(pwd)/verify_sol-profile-triage-2026-11-03.py"
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Classify the top-level entries of /root/.hermes/profiles/sol.
Deterministic, rule-based triage (stdlib only). Order of evaluation is
significant: the first matching rule decides the category.
Rule order:
1. CONFIG - config, secrets and lock files, plus vault dir
2. SCRIPT - python sources (*.py)
3. DATA - persistent data files (sqlite db + json caches)
4. PLUGIN - plugin / plugin-update / check directories
5. CACHE - cache directories
6. SERVICE - runtime service directories
7. OTHER - anything else
The committed manifest is produced by this exact rule set.
"""
import json
import os
import sys
from datetime import datetime, timezone
PROFILE_DIR = "/root/.hermes/profiles/sol"
OUT = "/root/troupe-standup/wizard-work/sol/sol-profile-triage-2026-11-03.json"
# ---- rules (exact-name sets) -------------------------------------------------
CONFIG = {
".env", ".env.bak-20261014T165715Z", ".env.lock",
".skills_prompt_snapshot.json", "SOUL.md", "config.yaml",
"config.yaml.bak-20261014T165715Z", "context_length_cache.yaml",
"context_length_cache.yaml.lock", "auth.json", "auth.lock",
"gateway.lock", "vault",
}
DATA = {
"models_dev_cache.etag", "models_dev_cache.json", "projects.db",
"state.db", "state.db-shm", "state.db-wal",
"state.db.auto-maintenance.lock", "state.db.fts_rebuild.lock",
"state.db.quarantine.lock",
}
PLUGIN = {"plugins", "plugin-update-checks", "hooks", "forge",
"backups", "bin", "source-checks"}
CACHE = {"audio_cache", "cache", "image_cache"}
SERVICE = {
"cron", "home", "logs", "lsp", "memories", "pairing", "plans",
"platforms", "sandboxes", "sessions", "skills", "runtime", "state",
"keys", "wizard-outputs", "workspace",
}
CATEGORY_ORDER = ["config", "script", "data", "plugin", "cache", "service", "other"]
def classify(rel: str) -> str:
if rel in CONFIG:
return "config"
if rel.endswith(".py"):
return "script"
if rel in DATA:
return "data"
if rel in PLUGIN:
return "plugin"
if rel in CACHE:
return "cache"
if rel in SERVICE:
return "service"
return "other"
def build() -> dict:
entries = []
for name in sorted(os.listdir(PROFILE_DIR)):
p = os.path.join(PROFILE_DIR, name)
st = os.lstat(p)
entries.append({
"rel": name,
"category": classify(name),
"type": "dir" if os.path.isdir(p) else ("link" if os.path.islink(p) else "file"),
"size": st.st_size if not os.path.isdir(p) and not os.path.islink(p) else -1,
})
by_category = {}
for e in entries:
by_category[e["category"]] = by_category.get(e["category"], 0) + 1
return {
"source": PROFILE_DIR,
"generated_at": datetime.now(timezone.utc).isoformat(),
"total": len(entries),
"by_category": {c: by_category.get(c, 0) for c in CATEGORY_ORDER},
"category_order": CATEGORY_ORDER,
"entries": entries,
}
def main():
manifest = build()
with open(OUT, "w", encoding="utf-8") as f:
json.dump(manifest, f, indent=2, ensure_ascii=False)
f.write("\n")
print("wrote", OUT)
print(json.dumps(manifest["by_category"], sort_keys=True))
print("total", manifest["total"])
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,144 @@
#!/usr/bin/env python3
"""Verify sol-profile-triage-2026-11-03.json.
Re-derives the classification straight from the live profile directory
(/root/.hermes/profiles/sol) using the documented top-level rule table, and
compares it against the committed manifest. The committed manifest is used
for structure only; the classification itself must come from disk.
Independent implementation: this module re-encodes the rule table as a set of
predicate helpers rather than re-using the generator's classify() path, so a
manifest that was hand-edited will fail this check.
Exit code IS the verdict: 0 = PASS, 1 = FAIL.
"""
import json
import os
import sys
PROFILE_DIR = "/root/.hermes/profiles/sol"
MANIFEST = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "sol-profile-triage-2026-11-03.json",
)
# Independent encoding of the rule table (predicate helpers). Deliberately a
# separate implementation from the generator to avoid a tautology.
def is_config(name: str) -> bool:
return name in {
".env", ".env.bak-20261014T165715Z", ".env.lock",
".skills_prompt_snapshot.json", "SOUL.md", "config.yaml",
"config.yaml.bak-20261014T165715Z", "context_length_cache.yaml",
"context_length_cache.yaml.lock", "auth.json", "auth.lock",
"gateway.lock", "vault",
}
def is_script(name: str) -> bool:
return name.endswith(".py")
def is_data(name: str) -> bool:
return name in {
"models_dev_cache.etag", "models_dev_cache.json", "projects.db",
"state.db", "state.db-shm", "state.db-wal",
"state.db.auto-maintenance.lock", "state.db.fts_rebuild.lock",
"state.db.quarantine.lock",
}
def is_plugin(name: str) -> bool:
return name in {"plugins", "plugin-update-checks", "hooks", "forge",
"backups", "bin", "source-checks"}
def is_cache(name: str) -> bool:
return name in {"audio_cache", "cache", "image_cache"}
def is_service(name: str) -> bool:
return name in {
"cron", "home", "logs", "lsp", "memories", "pairing", "plans",
"platforms", "sandboxes", "sessions", "skills", "runtime", "state",
"keys", "wizard-outputs", "workspace",
}
CATEGORY_ORDER = ["config", "script", "data", "plugin", "cache", "service", "other"]
def classify(name: str) -> str:
if is_config(name):
return "config"
if is_script(name):
return "script"
if is_data(name):
return "data"
if is_plugin(name):
return "plugin"
if is_cache(name):
return "cache"
if is_service(name):
return "service"
return "other"
def re_derive() -> dict:
entries = []
for name in sorted(os.listdir(PROFILE_DIR)):
p = os.path.join(PROFILE_DIR, name)
st = os.lstat(p)
entries.append({
"rel": name,
"category": classify(name),
"type": "dir" if os.path.isdir(p) else ("link" if os.path.islink(p) else "file"),
"size": st.st_size if not os.path.isdir(p) and not os.path.islink(p) else -1,
})
by_category = {}
for e in entries:
by_category[e["category"]] = by_category.get(e["category"], 0) + 1
return {"entries": entries, "by_category": by_category, "total": len(entries)}
def main():
if not os.path.isdir(PROFILE_DIR):
print("FAIL: profile dir missing:", PROFILE_DIR)
return 1
with open(MANIFEST, encoding="utf-8") as f:
committed = json.load(f)
expected = re_derive()
committed_by_rel = {c["rel"]: c for c in committed.get("entries", [])}
problems = []
if committed.get("total") != expected["total"]:
problems.append(f"total: committed {committed.get('total')} != {expected['total']}")
if committed.get("by_category") != expected["by_category"]:
problems.append(
f"by_category:\n committed {committed.get('by_category')}\n disk {expected['by_category']}")
expected_rels = {e["rel"] for e in expected["entries"]}
committed_rels = set(committed_by_rel)
if expected_rels != committed_rels:
problems.append(f"rel set mismatch: only-on-disk={sorted(expected_rels - committed_rels)} "
f"only-in-manifest={sorted(committed_rels - expected_rels)}")
for e in expected["entries"]:
c = committed_by_rel.get(e["rel"])
if c is None:
continue
if c.get("category") != e["category"]:
problems.append(f"{e['rel']}: category {c.get('category')!r} != {e['category']!r}")
if c.get("type") != e["type"]:
problems.append(f"{e['rel']}: type {c.get('type')!r} != {e['type']!r}")
if c.get("size") != e["size"]:
problems.append(f"{e['rel']}: size {c.get('size')!r} != {e['size']!r}")
if problems:
print("FAIL")
for p in problems:
print(" -", p)
return 1
print("PASS: committed classification re-derives from disk")
print("total", expected["total"], "| by_category",
{k: expected["by_category"][k] for k in expected["by_category"]})
return 0
if __name__ == "__main__":
sys.exit(main())