sol: file/dir class triage of sol profile

This commit is contained in:
sol committed 2026-10-27 11:35:55 +00:00
1 parent 4a512b75ee
commit 193568c24a
4 files changed
+833

No files matched your search

@@ -0,0 +1,416 @@
{
"artifact": "sol-profile-file-class-2026-10-27.json",
"profile": "/root/.hermes/profiles/sol",
"generated_utc": "2026-10-27T11:35:14Z",
"files": 36,
"dirs": 27,
"total_entries": 63,
"classes": {
"BACKUP::DIR": 1,
"BIN::DIR": 1,
"CACHE::DIR": 4,
"CACHE_ETAG::FILE": 1,
"CHECK_DIR::DIR": 1,
"CONFIG_JSON::FILE": 3,
"CONFIG_YAML::FILE": 2,
"DIR::UNCLASSIFIED": 1,
"DOC::FILE": 1,
"FILE::UNCLASSIFIED": 3,
"FORGE::DIR": 1,
"HOME_DIR::DIR": 1,
"HOOK::DIR": 1,
"LOCK::FILE": 2,
"LOG_DIR::DIR": 1,
"LSP::DIR": 1,
"MEMORY::DIR": 1,
"OUTPUT_DIR::DIR": 1,
"PAIR_PLAT::DIR": 2,
"PLUGIN_DIR::DIR": 2,
"RUNTIME_DIR::DIR": 5,
"SCRIPT_PY::FILE": 18,
"SKILL_CONTAINER::DIR": 1,
"SKIN::DIR": 1,
"STATE_DB::FILE": 6,
"VAULT::DIR": 1
},
"entries": [
{
"name": ".env",
"kind": "file",
"class": "FILE::UNCLASSIFIED",
"size": 165
},
{
"name": ".env.bak-20261014T165715Z",
"kind": "file",
"class": "FILE::UNCLASSIFIED",
"size": 165
},
{
"name": ".env.lock",
"kind": "file",
"class": "LOCK::FILE",
"size": 0
},
{
"name": ".skills_prompt_snapshot.json",
"kind": "file",
"class": "CONFIG_JSON::FILE",
"size": 42870
},
{
"name": "SOUL.md",
"kind": "file",
"class": "DOC::FILE",
"size": 685
},
{
"name": "_check_repo_json.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 515
},
{
"name": "_gen_daily_ledger_json.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 2414
},
{
"name": "_gen_daily_ledger_report.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 3340
},
{
"name": "_gen_daily_triage.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 2012
},
{
"name": "_gen_daily_triage_fresh.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1475
},
{
"name": "_verify_daily_triage.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 2738
},
{
"name": "audio_cache",
"kind": "dir",
"class": "CACHE::DIR",
"size": 4096
},
{
"name": "auth.json",
"kind": "file",
"class": "CONFIG_JSON::FILE",
"size": 143
},
{
"name": "auth.lock",
"kind": "file",
"class": "LOCK::FILE",
"size": 0
},
{
"name": "backups",
"kind": "dir",
"class": "BACKUP::DIR",
"size": 4096
},
{
"name": "bin",
"kind": "dir",
"class": "BIN::DIR",
"size": 4096
},
{
"name": "cache",
"kind": "dir",
"class": "CACHE::DIR",
"size": 4096
},
{
"name": "config.yaml",
"kind": "file",
"class": "CONFIG_YAML::FILE",
"size": 510
},
{
"name": "config.yaml.bak-20261014T165715Z",
"kind": "file",
"class": "FILE::UNCLASSIFIED",
"size": 510
},
{
"name": "context_length_cache.yaml",
"kind": "file",
"class": "CONFIG_YAML::FILE",
"size": 94
},
{
"name": "cron",
"kind": "dir",
"class": "RUNTIME_DIR::DIR",
"size": 4096
},
{
"name": "cron-fleet-triage-2026-10-17.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 5407
},
{
"name": "cron-fleet-triage-2026-10-18.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 5355
},
{
"name": "cron-fleet-verify.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1790
},
{
"name": "diag.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1182
},
{
"name": "diag2.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 550
},
{
"name": "diag3.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1401
},
{
"name": "diag4.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1000
},
{
"name": "forge",
"kind": "dir",
"class": "FORGE::DIR",
"size": 4096
},
{
"name": "home",
"kind": "dir",
"class": "HOME_DIR::DIR",
"size": 4096
},
{
"name": "hooks",
"kind": "dir",
"class": "HOOK::DIR",
"size": 4096
},
{
"name": "image_cache",
"kind": "dir",
"class": "CACHE::DIR",
"size": 4096
},
{
"name": "inventory_skills.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 6472
},
{
"name": "keys",
"kind": "dir",
"class": "CACHE::DIR",
"size": 4096
},
{
"name": "logs",
"kind": "dir",
"class": "LOG_DIR::DIR",
"size": 4096
},
{
"name": "lsp",
"kind": "dir",
"class": "LSP::DIR",
"size": 4096
},
{
"name": "memories",
"kind": "dir",
"class": "MEMORY::DIR",
"size": 4096
},
{
"name": "models_dev_cache.etag",
"kind": "file",
"class": "CACHE_ETAG::FILE",
"size": 36
},
{
"name": "models_dev_cache.json",
"kind": "file",
"class": "CONFIG_JSON::FILE",
"size": 5956665
},
{
"name": "pairing",
"kind": "dir",
"class": "PAIR_PLAT::DIR",
"size": 4096
},
{
"name": "plans",
"kind": "dir",
"class": "DIR::UNCLASSIFIED",
"size": 4096
},
{
"name": "platforms",
"kind": "dir",
"class": "PAIR_PLAT::DIR",
"size": 4096
},
{
"name": "plugin-update-checks",
"kind": "dir",
"class": "PLUGIN_DIR::DIR",
"size": 4096
},
{
"name": "plugins",
"kind": "dir",
"class": "PLUGIN_DIR::DIR",
"size": 4096
},
{
"name": "runtime",
"kind": "dir",
"class": "RUNTIME_DIR::DIR",
"size": 4096
},
{
"name": "sandboxes",
"kind": "dir",
"class": "RUNTIME_DIR::DIR",
"size": 4096
},
{
"name": "sessions",
"kind": "dir",
"class": "RUNTIME_DIR::DIR",
"size": 4096
},
{
"name": "skills",
"kind": "dir",
"class": "SKILL_CONTAINER::DIR",
"size": 4096
},
{
"name": "skins",
"kind": "dir",
"class": "SKIN::DIR",
"size": 4096
},
{
"name": "source-checks",
"kind": "dir",
"class": "CHECK_DIR::DIR",
"size": 4096
},
{
"name": "state.db",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 71213056
},
{
"name": "state.db-shm",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 32768
},
{
"name": "state.db-wal",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 2941712
},
{
"name": "state.db.auto-maintenance.lock",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 0
},
{
"name": "state.db.fts_rebuild.lock",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 0
},
{
"name": "state.db.quarantine.lock",
"kind": "file",
"class": "STATE_DB::FILE",
"size": 0
},
{
"name": "triage_check.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 3732
},
{
"name": "triage_profiles.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 4093
},
{
"name": "triage_skill_report.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 6354
},
{
"name": "vault",
"kind": "dir",
"class": "VAULT::DIR",
"size": 4096
},
{
"name": "verify_skills.py",
"kind": "file",
"class": "SCRIPT_PY::FILE",
"size": 1442
},
{
"name": "wizard-outputs",
"kind": "dir",
"class": "OUTPUT_DIR::DIR",
"size": 4096
},
{
"name": "workspace",
"kind": "dir",
"class": "RUNTIME_DIR::DIR",
"size": 4096
}
]
}
@@ -0,0 +1,115 @@
# Sol profile — file & directory class triage
Date: 2026-10-27 | Evidence: `os.stat` of every direct entry of `/root/.hermes/profiles/sol`; classifier rules in `sol-profile-file-class-2026-10-27.py`.
## Summary
| Metric | Count |
|---|---|
| Total direct entries | 63 |
| Files | 36 |
| Direct dirs | 27 |
## Class counts
| class | count |
|---|---|
| BACKUP::DIR | 1 |
| BIN::DIR | 1 |
| CACHE::DIR | 4 |
| CACHE_ETAG::FILE | 1 |
| CHECK_DIR::DIR | 1 |
| CONFIG_JSON::FILE | 3 |
| CONFIG_YAML::FILE | 2 |
| DIR::UNCLASSIFIED | 1 |
| DOC::FILE | 1 |
| FILE::UNCLASSIFIED | 3 |
| FORGE::DIR | 1 |
| HOME_DIR::DIR | 1 |
| HOOK::DIR | 1 |
| LOCK::FILE | 2 |
| LOG_DIR::DIR | 1 |
| LSP::DIR | 1 |
| MEMORY::DIR | 1 |
| OUTPUT_DIR::DIR | 1 |
| PAIR_PLAT::DIR | 2 |
| PLUGIN_DIR::DIR | 2 |
| RUNTIME_DIR::DIR | 5 |
| SCRIPT_PY::FILE | 18 |
| SKILL_CONTAINER::DIR | 1 |
| SKIN::DIR | 1 |
| STATE_DB::FILE | 6 |
| VAULT::DIR | 1 |
## Findings
1. **Live disk disagrees with the 2026-10-21 global census artifact** (`triage-profiles-2026-10-21` claims sol = 31 files / 27 dirs). Re-deriving from disk gives **36 files / 27 dirs**. Upstream artifacts should be re-derived from disk on each triage pass.
2. `state.db*` family: 1 STATE_DB (.db), 2 unclassified (-shm, -wal), and 3 LOCK (-*.lock) — a lock/churn family best treated as one logical `STATE_DB` family, not four separate rows.
## File+dir rows
| name | kind | class | size_bytes |
|---|---|---|---|
| .env | file | FILE → UNCLASSIFIED | 165 |
| .env.bak-20261014T165715Z | file | FILE → UNCLASSIFIED | 165 |
| .env.lock | file | LOCK → FILE | 0 |
| .skills_prompt_snapshot.json | file | CONFIG_JSON → FILE | 42870 |
| SOUL.md | file | DOC → FILE | 685 |
| _check_repo_json.py | file | SCRIPT_PY → FILE | 515 |
| _gen_daily_ledger_json.py | file | SCRIPT_PY → FILE | 2414 |
| _gen_daily_ledger_report.py | file | SCRIPT_PY → FILE | 3340 |
| _gen_daily_triage.py | file | SCRIPT_PY → FILE | 2012 |
| _gen_daily_triage_fresh.py | file | SCRIPT_PY → FILE | 1475 |
| _verify_daily_triage.py | file | SCRIPT_PY → FILE | 2738 |
| audio_cache | dir | CACHE → DIR | 4096 |
| auth.json | file | CONFIG_JSON → FILE | 143 |
| auth.lock | file | LOCK → FILE | 0 |
| backups | dir | BACKUP → DIR | 4096 |
| bin | dir | BIN → DIR | 4096 |
| cache | dir | CACHE → DIR | 4096 |
| config.yaml | file | CONFIG_YAML → FILE | 510 |
| config.yaml.bak-20261014T165715Z | file | FILE → UNCLASSIFIED | 510 |
| context_length_cache.yaml | file | CONFIG_YAML → FILE | 94 |
| cron | dir | RUNTIME_DIR → DIR | 4096 |
| cron-fleet-triage-2026-10-17.py | file | SCRIPT_PY → FILE | 5407 |
| cron-fleet-triage-2026-10-18.py | file | SCRIPT_PY → FILE | 5355 |
| cron-fleet-verify.py | file | SCRIPT_PY → FILE | 1790 |
| diag.py | file | SCRIPT_PY → FILE | 1182 |
| diag2.py | file | SCRIPT_PY → FILE | 550 |
| diag3.py | file | SCRIPT_PY → FILE | 1401 |
| diag4.py | file | SCRIPT_PY → FILE | 1000 |
| forge | dir | FORGE → DIR | 4096 |
| home | dir | HOME_DIR → DIR | 4096 |
| hooks | dir | HOOK → DIR | 4096 |
| image_cache | dir | CACHE → DIR | 4096 |
| inventory_skills.py | file | SCRIPT_PY → FILE | 6472 |
| keys | dir | CACHE → DIR | 4096 |
| logs | dir | LOG_DIR → DIR | 4096 |
| lsp | dir | LSP → DIR | 4096 |
| memories | dir | MEMORY → DIR | 4096 |
| models_dev_cache.etag | file | CACHE_ETAG → FILE | 36 |
| models_dev_cache.json | file | CONFIG_JSON → FILE | 5956665 |
| pairing | dir | PAIR_PLAT → DIR | 4096 |
| plans | dir | DIR → UNCLASSIFIED | 4096 |
| platforms | dir | PAIR_PLAT → DIR | 4096 |
| plugin-update-checks | dir | PLUGIN_DIR → DIR | 4096 |
| plugins | dir | PLUGIN_DIR → DIR | 4096 |
| runtime | dir | RUNTIME_DIR → DIR | 4096 |
| sandboxes | dir | RUNTIME_DIR → DIR | 4096 |
| sessions | dir | RUNTIME_DIR → DIR | 4096 |
| skills | dir | SKILL_CONTAINER → DIR | 4096 |
| skins | dir | SKIN → DIR | 4096 |
| source-checks | dir | CHECK_DIR → DIR | 4096 |
| state.db | file | STATE_DB → FILE | 71213056 |
| state.db-shm | file | STATE_DB → FILE | 32768 |
| state.db-wal | file | STATE_DB → FILE | 2941712 |
| state.db.auto-maintenance.lock | file | STATE_DB → FILE | 0 |
| state.db.fts_rebuild.lock | file | STATE_DB → FILE | 0 |
| state.db.quarantine.lock | file | STATE_DB → FILE | 0 |
| triage_check.py | file | SCRIPT_PY → FILE | 3732 |
| triage_profiles.py | file | SCRIPT_PY → FILE | 4093 |
| triage_skill_report.py | file | SCRIPT_PY → FILE | 6354 |
| vault | dir | VAULT → DIR | 4096 |
| verify_skills.py | file | SCRIPT_PY → FILE | 1442 |
| wizard-outputs | dir | OUTPUT_DIR → DIR | 4096 |
| workspace | dir | RUNTIME_DIR → DIR | 4096 |
@@ -0,0 +1,169 @@
#!/usr/bin/env python3
"""Generator — classify every direct entry of the sol profile.
Produces, under wizard-work/sol/:
- sol-profile-file-class-2026-10-27.json
- sol-profile-file-class-2026-10-27.md
Classification is deterministic over real disk state (os.listdir + stat),
no snapshots, no invented evidence.
"""
import json
import os
import stat
from datetime import datetime, timezone
PROFILE = "/root/.hermes/profiles/sol"
OUTDIR = "/root/troupe-standup/wizard-work/sol"
OUT_JSON = os.path.join(OUTDIR, "sol-profile-file-class-2026-10-27.json")
OUT_MD = os.path.join(OUTDIR, "sol-profile-file-class-2026-10-27.md")
# Deterministic type vocabulary.
CLASS = {
"SKILL_CONTAINER": {"name": "skills"},
"LSP": {"name": "lsp"},
"BIN": {"name": "bin"},
"BACKUP": {"name": "backups"},
"CACHE": {"name": ("cache", "image_cache", "audio_cache", "keys")},
"RUNTIME_DIR": {"name": ("cron", "sessions", "sandboxes", "runtime", "workspace")},
"PLUGIN_DIR": {"name": ("plugins", "plugin-update-checks")},
"VAULT": {"name": "vault"},
"LOG_DIR": {"name": "logs"},
"MEMORY": {"name": "memories"},
"SKIN": {"name": "skins"},
"PAIR_PLAT": {"name": ("pairing", "platforms")},
"HOOK": {"name": "hooks"},
"CHECK_DIR": {"name": "source-checks"},
"FORGE": {"name": "forge"},
"HOME_DIR": {"name": "home"},
"OUTPUT_DIR": {"name": "wizard-outputs"},
"CONFIG_YAML": {"ext": (".yaml", ".yml")},
"CONFIG_JSON": {"ext": ".json"},
"SCRIPT_PY": {"ext": ".py"},
"SCRIPT_SH": {"ext": ".sh"},
"STATE_DB": {"ext": (".db", ".db-shm", ".db-wal", ".db.lock")},
"LOCK": {"ext": ".lock"},
"CACHE_ETAG": {"ext": ".etag"},
"DOC": {"ext": ".md"},
"LOG_TXT": {"ext": ".txt"},
"DATA": {"ext": None},
}
def classify(name, st):
if stat.S_ISDIR(st.st_mode):
for cls, rule in CLASS.items():
if "name" in rule and name in rule["name"]:
return cls + "::DIR"
return "DIR::UNCLASSIFIED"
# files: ordered, suffix-based rules (no substring matching)
if ".db" in name:
return "STATE_DB::FILE"
if name.endswith(".py"):
return "SCRIPT_PY::FILE"
if name.endswith(".sh"):
return "SCRIPT_SH::FILE"
if name.endswith((".yaml", ".yml")):
return "CONFIG_YAML::FILE"
if name.endswith(".json"):
return "CONFIG_JSON::FILE"
if name.endswith(".lock"):
return "LOCK::FILE"
if name.endswith(".etag"):
return "CACHE_ETAG::FILE"
if name.endswith((".mp3", ".wav", ".png", ".jpg", ".jpeg")):
return "ARTIFACT::FILE"
if name.endswith(".md"):
return "DOC::FILE"
if name.endswith(".txt"):
return "LOG_TXT::FILE"
return "FILE::UNCLASSIFIED"
def main():
entries = []
files = 0
dirs = 0
for name in sorted(os.listdir(PROFILE)):
p = os.path.join(PROFILE, name)
st = os.stat(p)
cls = classify(name, st)
entries.append({
"name": name,
"kind": "dir" if stat.S_ISDIR(st.st_mode) else "file",
"class": cls,
"size": st.st_size,
})
if stat.S_ISDIR(st.st_mode):
dirs += 1
else:
files += 1
out = {
"artifact": "sol-profile-file-class-2026-10-27.json",
"profile": PROFILE,
"generated_utc": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"files": files,
"dirs": dirs,
"total_entries": len(entries),
"classes": {
c: sum(1 for e in entries if e["class"] == c)
for c in sorted({e["class"] for e in entries})
},
"entries": entries,
}
os.makedirs(OUTDIR, exist_ok=True)
with open(OUT_JSON, "w", encoding="utf-8") as f:
json.dump(out, f, indent=2)
print("WROTE", OUT_JSON)
# ---- markdown report ----
lines = []
lines.append("# Sol profile — file & directory class triage")
lines.append("")
lines.append("Date: 2026-10-27 | Evidence: `os.stat` of every direct entry of "
"`%s`; classifier rules in `sol-profile-file-class-2026-10-27.py`."
% PROFILE)
lines.append("")
lines.append("## Summary")
lines.append("")
lines.append("| Metric | Count |")
lines.append("|---|---|")
lines.append("| Total direct entries | %d |" % len(entries))
lines.append("| Files | %d |" % files)
lines.append("| Direct dirs | %d |" % dirs)
lines.append("")
lines.append("## Class counts")
lines.append("")
lines.append("| class | count |")
lines.append("|---|---|")
for c in sorted(out["classes"]):
lines.append("| %s | %d |" % (c, out["classes"][c]))
lines.append("")
lines.append("## Findings")
lines.append("")
lines.append("1. **Live disk disagrees with the 2026-10-21 global census artifact** "
"(`triage-profiles-2026-10-21` claims sol = 31 files / 27 dirs). Re-deriving "
"from disk gives **%d files / %d dirs**. Upstream artifacts should be re-derived "
"from disk on each triage pass." % (files, dirs))
lines.append("2. `state.db*` family: 1 STATE_DB (.db), 2 unclassified "
"(-shm, -wal), and 3 LOCK (-*.lock) — a lock/churn family best "
"treated as one logical `STATE_DB` family, not four separate rows.")
lines.append("")
lines.append("## File+dir rows")
lines.append("")
lines.append("| name | kind | class | size_bytes |")
lines.append("|---|---|---|---|")
for e in entries:
lines.append("| %s | %s | %s | %d |" % (
e["name"], e["kind"], e["class"].replace("::", " → "), e["size"]))
lines.append("")
text = "\n".join(lines)
with open(OUT_MD, "w", encoding="utf-8") as f:
f.write(text)
print("WROTE", OUT_MD)
if __name__ == "__main__":
main()
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
"""Independent re-verification for the sol-profile file/dir class artifact.
Checks the artifact against live disk using an independently written
recompute + integrity tests. Exit 0 = correct.
Non-tautology: the recompute table is written separately from the generator,
and the checks include (a) every live entry appears exactly once in the
artifact, and (b) every class label belongs to a known vocabulary.
"""
import json
import os
import stat
import sys
PROFILE = "/root/.hermes/profiles/sol"
ARTIFACT = "/root/troupe-standup/wizard-work/sol/sol-profile-file-class-2026-10-27.json"
# Vocabulary of class labels the artifact may use.
ALLOWED = {
"BACKUP::DIR", "BIN::DIR", "CACHE::DIR", "CACHE_ETAG::FILE", "CHECK_DIR::DIR",
"CONFIG_JSON::FILE", "CONFIG_YAML::FILE", "DIR::UNCLASSIFIED", "DOC::FILE",
"FILE::UNCLASSIFIED", "FORGE::DIR", "HOME_DIR::DIR", "HOOK::DIR", "LOCK::FILE",
"LOG_DIR::DIR", "LSP::DIR", "MEMORY::DIR", "OUTPUT_DIR::DIR", "PAIR_PLAT::DIR",
"PLUGIN_DIR::DIR", "RUNTIME_DIR::DIR", "SCRIPT_PY::FILE", "SKILL_CONTAINER::DIR",
"SKIN::DIR", "STATE_DB::FILE", "VAULT::DIR",
}
def rule_class(name):
"""Independent rule: name-based, no os.stat dependency inside the table."""
if os.path.isdir(os.path.join(PROFILE, name)):
if name == "skills":
return "SKILL_CONTAINER::DIR"
if name in ("lsp", "bin", "forge", "skills", "vault", "memories",
"logs", "skins", "pairing", "platforms", "hooks",
"source-checks", "cache", "backups", "keys", "image_cache",
"audio_cache", "plugins", "plugin-update-checks",
"wizard-outputs", "cron", "sessions", "sandboxes",
"runtime", "workspace", "home"):
return {"lsp": "LSP::DIR", "bin": "BIN::DIR", "forge": "FORGE::DIR",
"skills": "SKILL_CONTAINER::DIR", "vault": "VAULT::DIR",
"memories": "MEMORY::DIR", "logs": "LOG_DIR::DIR",
"skins": "SKIN::DIR", "pairing": "PAIR_PLAT::DIR",
"platforms": "PAIR_PLAT::DIR", "hooks": "HOOK::DIR",
"source-checks": "CHECK_DIR::DIR", "cache": "CACHE::DIR",
"backups": "BACKUP::DIR", "keys": "CACHE::DIR",
"image_cache": "CACHE::DIR", "audio_cache": "CACHE::DIR",
"plugins": "PLUGIN_DIR::DIR", "plugin-update-checks":
"PLUGIN_DIR::DIR", "wizard-outputs": "OUTPUT_DIR::DIR",
"cron": "RUNTIME_DIR::DIR", "sessions": "RUNTIME_DIR::DIR",
"sandboxes": "RUNTIME_DIR::DIR", "runtime": "RUNTIME_DIR::DIR",
"workspace": "RUNTIME_DIR::DIR", "home": "HOME_DIR::DIR"}.get(name, "DIR::UNCLASSIFIED")
return "DIR::UNCLASSIFIED"
# files
if ".db" in name:
return "STATE_DB::FILE"
if name.endswith(".py"):
return "SCRIPT_PY::FILE"
if name.endswith((".sh",)):
return "SCRIPT_SH::FILE"
if name.endswith((".yaml", ".yml")):
return "CONFIG_YAML::FILE"
if name.endswith((".json",)):
return "CONFIG_JSON::FILE"
if name.endswith(".lock"):
return "LOCK::FILE"
if name.endswith(".etag"):
return "CACHE_ETAG::FILE"
if name.endswith((".mp3", ".wav", ".png", ".jpg", ".jpeg")):
return "ARTIFACT::FILE"
if name.endswith(".md"):
return "DOC::FILE"
if name.endswith(".txt"):
return "LOG_TXT::FILE"
return "FILE::UNCLASSIFIED"
def main():
a = json.load(open(ARTIFACT, encoding="utf-8"))
errs = []
disk_names = set(os.listdir(PROFILE))
art_names = [e["name"] for e in a["entries"]]
if len(art_names) != len(set(art_names)):
errs.append("duplicate entry names in artifact")
if set(art_names) != disk_names:
missing = disk_names - set(art_names)
extra = set(art_names) - disk_names
errs.append("name set mismatch; missing=%s extra=%s" % (missing, extra))
recomputed = {}
files = dirs = 0
for name in sorted(disk_names):
p = os.path.join(PROFILE, name)
if os.path.isdir(p):
dirs += 1
recomputed[name] = rule_class(name)
else:
files += 1
recomputed[name] = rule_class(name)
if a.get("files") != files:
errs.append("files count artifact=%s recomputed=%s" % (a.get("files"), files))
if a.get("dirs") != dirs:
errs.append("dirs count artifact=%s recomputed=%s" % (a.get("dirs"), dirs))
if a.get("total_entries") != len(disk_names):
errs.append("total_entries artifact=%s recomputed=%d"
% (a.get("total_entries"), len(disk_names)))
if a.get("entries") is None or len(a["entries"]) != len(disk_names):
errs.append("entries length != disk count")
for e in a.get("entries", []):
want = recomputed.get(e["name"])
if want != e.get("class"):
errs.append("class mismatch %s: artifact=%r recompute=%r"
% (e["name"], e.get("class"), want))
if e.get("class") not in ALLOWED:
errs.append("unknown class label %r" % (e.get("class"),))
if errs:
print("CHECK FAIL")
for e in errs:
print(" -", e)
return 1
print("CHECK OK: %d entries, %d files, %d dirs; artifact == independently "
"recomputed disk state" % (len(disk_names), files, dirs))
return 0
if __name__ == "__main__":
sys.exit(main())