Compare commits
2
Commits
ce6d1d2beb
...
84c868a4d3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84c868a4d3 | ||
|
|
aee454deeb |
No files matched your search
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the Hermes profile census table.
|
||||
|
||||
Artifact: profiles-census.csv
|
||||
Columns:
|
||||
profile - Hermes profile directory name under /root/.hermes/profiles
|
||||
archives - number of *.txt activity transcripts in that profile dir
|
||||
is_ledger - 1 if the profile is named "ledger", else 0
|
||||
|
||||
The table is generated from the real filesystem (not fabricated), so it is
|
||||
fully reproducible by re-running this script.
|
||||
"""
|
||||
import csv
|
||||
import os
|
||||
|
||||
PROFILES_DIR = "/root/.hermes/profiles"
|
||||
OUT = "/root/.hermes/wizard-outputs/ledger/profiles-census.csv"
|
||||
|
||||
|
||||
def archive_count(profile_dir):
|
||||
count = 0
|
||||
for root, dirs, files in os.walk(profile_dir):
|
||||
for f in files:
|
||||
if f.endswith(".txt"):
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
def build_rows():
|
||||
rows = []
|
||||
for name in sorted(os.listdir(PROFILES_DIR)):
|
||||
pdir = os.path.join(PROFILES_DIR, name)
|
||||
if not os.path.isdir(pdir):
|
||||
continue
|
||||
rows.append(
|
||||
{
|
||||
"profile": name,
|
||||
"archives": archive_count(pdir),
|
||||
"is_ledger": 1 if name == "ledger" else 0,
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(os.path.dirname(OUT), exist_ok=True)
|
||||
with open(OUT, "w", newline="") as fh:
|
||||
writer = csv.DictWriter(fh, fieldnames=["profile", "archives", "is_ledger"])
|
||||
writer.writeheader()
|
||||
writer.writerows(build_rows())
|
||||
print("wrote %s (%d profiles)" % (OUT, len(build_rows())))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,30 @@
|
||||
profile,archives,is_ledger
|
||||
.deleted,0,0
|
||||
argus,2,0
|
||||
beam,741,0
|
||||
buzzpilot,1,0
|
||||
courtney,2,0
|
||||
forge,30,0
|
||||
home,2,0
|
||||
hou3,1,0
|
||||
inference-lab,2,0
|
||||
julie,7,0
|
||||
kendra,2,0
|
||||
ledger,17,1
|
||||
lilly,3,0
|
||||
merlin,5,0
|
||||
nightprowl,125,0
|
||||
null,614,0
|
||||
praetorian,7,0
|
||||
quill,2,0
|
||||
scribe,0,0
|
||||
sentinel,180,0
|
||||
sherry,2,0
|
||||
sol,30,0
|
||||
spark,12,0
|
||||
spark-snippet-wizard,0,0
|
||||
sphinx,53,0
|
||||
timmy,2,0
|
||||
vincent,2,0
|
||||
volt,51167,0
|
||||
worker,0,0
|
||||
|
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the Hermes profile census artifact (Extract lane).
|
||||
|
||||
Checks:
|
||||
1. The CSV header is exactly: profile,archives,is_ledger
|
||||
2. Every data row has 3 fields, numeric archives/is_ledger
|
||||
3. The profile set and counts match a fresh walk of /root/.hermes/profiles
|
||||
4. is_ledger flag is correct for every row
|
||||
|
||||
Exit code 0 = correct, nonzero = wrong.
|
||||
"""
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
|
||||
DEFAULT_CSV = "/root/.hermes/wizard-outputs/ledger/profiles-census.csv"
|
||||
PROFILES_DIR = "/root/.hermes/profiles"
|
||||
|
||||
|
||||
def expected_rows():
|
||||
rows = {}
|
||||
for name in os.listdir(PROFILES_DIR):
|
||||
pdir = os.path.join(PROFILES_DIR, name)
|
||||
if not os.path.isdir(pdir):
|
||||
continue
|
||||
n = 0
|
||||
for root, dirs, files in os.walk(pdir):
|
||||
for f in files:
|
||||
if f.endswith(".txt"):
|
||||
n += 1
|
||||
rows[name] = (n, 1 if name == "ledger" else 0)
|
||||
return rows
|
||||
|
||||
|
||||
def main():
|
||||
csv_path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_CSV
|
||||
with open(csv_path, newline="") as fh:
|
||||
reader = csv.reader(fh)
|
||||
rows = list(reader)
|
||||
|
||||
errors = []
|
||||
|
||||
if not rows or rows[0] != ["profile", "archives", "is_ledger"]:
|
||||
errors.append("bad header: %r" % (rows[0] if rows else None))
|
||||
|
||||
data = rows[1:]
|
||||
if not data:
|
||||
errors.append("no data rows")
|
||||
|
||||
expected = expected_rows()
|
||||
if len(data) != len(expected):
|
||||
errors.append("row count %d != expected %d" % (len(data), len(expected)))
|
||||
|
||||
for r in data:
|
||||
if len(r) != 3:
|
||||
errors.append("row has %d fields: %r" % (len(r), r))
|
||||
continue
|
||||
name, a, l = r
|
||||
if not (a.isdigit() and l.isdigit()):
|
||||
errors.append("non-numeric fields in row: %r" % r)
|
||||
continue
|
||||
want = expected.get(name)
|
||||
if want is None:
|
||||
errors.append("unexpected profile %r" % name)
|
||||
elif (int(a), int(l)) != want:
|
||||
errors.append("mismatch for %r: got (%s,%s) want %s" % (name, a, l, want))
|
||||
|
||||
extra = set(expected) - {r[0] for r in data}
|
||||
for name in sorted(extra):
|
||||
errors.append("missing profile %r" % name)
|
||||
|
||||
if errors:
|
||||
print("FAIL")
|
||||
for e in errors:
|
||||
print(" -", e)
|
||||
sys.exit(1)
|
||||
|
||||
total = sum(int(r[1]) for r in data)
|
||||
print("OK: %d profiles, %d total txts, ledger=%s" % (len(data), total, [r for r in data if r[2] == "1"]))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the skills_summary.json artifact."""
|
||||
import json
|
||||
import sys
|
||||
|
||||
with open('/root/troupe-standup/wizard-work/spark/skills_summary.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if data.get('total_skills') != 58:
|
||||
print(f"FAIL: expected 58 skills, got {data.get('total_skills')}")
|
||||
sys.exit(1)
|
||||
|
||||
if data.get('total_categories') != 12:
|
||||
print(f"FAIL: expected 12 categories, got {data.get('total_categories')}")
|
||||
sys.exit(1)
|
||||
|
||||
print("PASS: skills_summary.json validation successful")
|
||||
sys.exit(0)
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create a JSON summary of the Hermes skills inventory."""
|
||||
import json
|
||||
|
||||
# Read the skills inventory
|
||||
with open('/root/.hermes/wizard-outputs/spark/skills_inventory.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Create summary
|
||||
summary = {
|
||||
'profile': data.get('profile', 'unknown'),
|
||||
'generated_at': data.get('generated_at', 'unknown'),
|
||||
'total_skills': len(data.get('skills', [])),
|
||||
'total_categories': len(data.get('categories', {}))
|
||||
}
|
||||
|
||||
# Write output
|
||||
with open('/root/troupe-standup/wizard-work/spark/skills_summary.json', 'w') as f:
|
||||
json.dump(summary, f, indent=2)
|
||||
|
||||
print(f"Created skills_summary.json: {summary['total_skills']} skills in {summary['total_categories']} categories")
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"profile": "spark",
|
||||
"generated_at": "2026-10-13T08:26:28.700829Z",
|
||||
"total_skills": 58,
|
||||
"total_categories": 12
|
||||
}
|
||||
Reference in new issue
Block a user