sol: sol-profile-skill-triage-2026-10-24 — deployment & usage triage artifact
This commit is contained in:
1 parent
3eaa302e9f
commit
b78526b8e9
4 files changed
+805
No files matched your search
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Independent re-check for sol-profile-skill-triage-2026-10-24.
|
||||
|
||||
Recomputes the classification straight from the live filesystem (manifest,
|
||||
category overlay skill subdirs, .usage.json) and diffs it against the written
|
||||
JSON artifact. Exit 0 = artifact is correct; nonzero = artifact is wrong or
|
||||
missing. No fallbacks: the exit code carries the verdict.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SKILLS = Path("/root/.hermes/profiles/sol/skills")
|
||||
ARTIFACT = Path("/root/.hermes/wizard-outputs/sol/sol-profile-skill-triage-2026-10-24.json")
|
||||
REPO_ARTIFACT = Path("/root/troupe-standup/wizard-work/sol/sol-profile-skill-triage-2026-10-24.json")
|
||||
|
||||
failures = []
|
||||
|
||||
|
||||
def read_names():
|
||||
names = []
|
||||
for line in SKILLS.joinpath(".bundled_manifest").read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and ":" in line:
|
||||
names.append(line.split(":", 1)[0].strip())
|
||||
return names
|
||||
|
||||
|
||||
def read_deployed():
|
||||
deployed = set()
|
||||
n = 0
|
||||
for entry in sorted(SKILLS.iterdir()):
|
||||
if not entry.is_dir() or entry.name.startswith("."):
|
||||
continue
|
||||
n += 1
|
||||
for sub in entry.iterdir():
|
||||
if sub.is_dir() and not sub.name.startswith("."):
|
||||
deployed.add(sub.name)
|
||||
return deployed, n
|
||||
|
||||
|
||||
def main():
|
||||
names = read_names()
|
||||
deployed, overlays = read_deployed()
|
||||
usage = json.loads(SKILLS.joinpath(".usage.json").read_text(encoding="utf-8"))
|
||||
used = sorted(n for n in names if usage.get(n, {}).get("state") == "active")
|
||||
|
||||
truth = {
|
||||
"manifest_count": len(names),
|
||||
"deployed_count": len(deployed),
|
||||
"category_overlay_count": overlays,
|
||||
"active_usage_tracked": len(used),
|
||||
"not_deployed": sorted(set(names) - deployed),
|
||||
"extras": sorted(deployed - set(names)),
|
||||
"skill_rows": [
|
||||
{
|
||||
"skill": n,
|
||||
"deployed": n in deployed,
|
||||
"usage_state": usage.get(n, {}).get("state"),
|
||||
"use_count": usage.get(n, {}).get("use_count"),
|
||||
"class": (
|
||||
"deployed + usage-tracked / active" if (n in deployed and usage.get(n, {}).get("state") == "active")
|
||||
else ("deployed (dir), no usage record" if n in deployed else
|
||||
("usage-tracked / active (not in profile)" if usage.get(n, {}).get("state") == "active" else "not deployed / no usage record"))
|
||||
),
|
||||
}
|
||||
for n in sorted(names)
|
||||
],
|
||||
}
|
||||
|
||||
if not ARTIFACT.exists():
|
||||
print("FAIL: artifact missing " + str(ARTIFACT))
|
||||
sys.exit(1)
|
||||
recorded = json.loads(ARTIFACT.read_text(encoding="utf-8"))
|
||||
|
||||
for k in ("manifest_count", "deployed_count", "category_overlay_count", "active_usage_tracked", "not_deployed", "extras"):
|
||||
if recorded.get(k) != truth[k]:
|
||||
failures.append("%s artifact=%r truth=%r" % (k, recorded.get(k), truth[k]))
|
||||
|
||||
rec_rows = {r["skill"]: r for r in recorded.get("skill_rows", [])}
|
||||
if len(rec_rows) != len(truth["skill_rows"]):
|
||||
failures.append("skill_rows count %d != truth %d" % (len(rec_rows), len(truth["skill_rows"])))
|
||||
for r in truth["skill_rows"]:
|
||||
if rec_rows.get(r["skill"]) != r:
|
||||
failures.append("row mismatch %s: %r != %r" % (r["skill"], rec_rows.get(r["skill"]), r))
|
||||
|
||||
if recorded.get("generated_at") == "" or recorded.get("generated_at") is None:
|
||||
failures.append("generated_at missing/empty")
|
||||
|
||||
if failures:
|
||||
print("FAIL: sol-profile-skill-triage-2026-10-24 artifact incorrect")
|
||||
for f in failures:
|
||||
print(" - " + f)
|
||||
sys.exit(1)
|
||||
|
||||
print("PASS: sol-profile-skill-triage-2026-10-24 artifact verified against live filesystem")
|
||||
print(" manifest=%d deployed=%d overlays=%d usage_tracked=%d not_deployed=%d extras=%d rows=%d" % (
|
||||
truth["manifest_count"], truth["deployed_count"], truth["category_overlay_count"],
|
||||
truth["active_usage_tracked"], len(truth["not_deployed"]), len(truth["extras"]), len(truth["skill_rows"])))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,421 @@
|
||||
{
|
||||
"artifact": "sol-profile-skill-triage-2026-10-24.json",
|
||||
"source": ".bundled_manifest + category overlay skill subdirs + .usage.json",
|
||||
"generated_at": "2026-10-24T16:17:16Z",
|
||||
"lane": "Triage - everyday Q&A and classification",
|
||||
"profile": "/root/.hermes/profiles/sol",
|
||||
"manifest_count": 58,
|
||||
"deployed_count": 58,
|
||||
"category_overlay_count": 12,
|
||||
"active_usage_tracked": 3,
|
||||
"not_deployed": [],
|
||||
"extras": [],
|
||||
"skill_rows": [
|
||||
{
|
||||
"skill": "airtable",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "apple-notes",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "apple-reminders",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "architecture-diagram",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "arxiv",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "ascii-video",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "baoyu-infographic",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "blocked-page-recovery",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "box",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "claude-code",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "claude-design",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "codebase-inspection",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "codex",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "competitor-news-monitor",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "computer-use",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "design-md",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "document-to-action-items",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "docx",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "dogfood",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "email-inbox-triage",
|
||||
"deployed": true,
|
||||
"usage_state": "active",
|
||||
"use_count": 1,
|
||||
"class": "deployed + usage-tracked / active"
|
||||
},
|
||||
{
|
||||
"skill": "findmy",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "gif-search",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "github",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "google-workspace",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "grounded-citations",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "hermes-agent",
|
||||
"deployed": true,
|
||||
"usage_state": "active",
|
||||
"use_count": 11,
|
||||
"class": "deployed + usage-tracked / active"
|
||||
},
|
||||
{
|
||||
"skill": "hermes-agent-skill-authoring",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "himalaya",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "humanizer",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "imessage",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "inspecting-hermes-desktop-dom",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "llm-wiki",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "manim-video",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "maps",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "meeting-action-items",
|
||||
"deployed": true,
|
||||
"usage_state": "active",
|
||||
"use_count": 1,
|
||||
"class": "deployed + usage-tracked / active"
|
||||
},
|
||||
{
|
||||
"skill": "node-inspect-debugger",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "notion",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "obsidian",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "opencode",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "p5js",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "pdf",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "popular-web-designs",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "powerpoint",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "product-price-monitor",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "python-debugpy",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "requesting-code-review",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "sdlc-review",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "simplify-code",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "songsee",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "songwriting-and-ai-music",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "spike",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "systematic-debugging",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "teams-meeting-pipeline",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "test-driven-development",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "weekly-review-planning",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "xlsx",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "xurl",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
},
|
||||
{
|
||||
"skill": "youtube-content",
|
||||
"deployed": true,
|
||||
"usage_state": null,
|
||||
"use_count": null,
|
||||
"class": "deployed (dir), no usage record"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
# Sol profile skill triage
|
||||
|
||||
Date: 2026-10-24 (session start) | Evidence: live `ls` of /root/.hermes/profiles/sol/skills; each category overlay dir walked for skill subdirs; `.bundled_manifest` parsed for the canonical skill list; `.usage.json` parsed for usage records.
|
||||
|
||||
## Summary
|
||||
|
||||
| Metric | Count |
|
||||
|---|---|
|
||||
| Canonical skills in `.bundled_manifest` | 58 |
|
||||
| Skill subdirs actually deployed | 58 |
|
||||
| Category overlay dirs (containers) | 12 |
|
||||
| Usage-tracked / active | 3 |
|
||||
|
||||
## Findings
|
||||
|
||||
1. **All 58 manifest skills are deployed** — every manifest name resolves to a skill subdirectory under one of the 12 category overlay dirs; 0 manifest skills are missing from the profile.
|
||||
2. **Usage tracking is thin**: only 3 of 58 deployed skills carry a usage record; the other 0 carry no Hermes usage event.
|
||||
3. **Category overlays are containers, not skills** — 12 dirs hold the actual skills as subdirectories and are not counted as skills themselves.
|
||||
|
||||
## Skill table
|
||||
|
||||
| Skill | Deployed | Usage state | Use count | Class |
|
||||
|---|---|---|---|---|
|
||||
| airtable | yes | - | - | deployed (dir), no usage record |
|
||||
| apple-notes | yes | - | - | deployed (dir), no usage record |
|
||||
| apple-reminders | yes | - | - | deployed (dir), no usage record |
|
||||
| architecture-diagram | yes | - | - | deployed (dir), no usage record |
|
||||
| arxiv | yes | - | - | deployed (dir), no usage record |
|
||||
| ascii-video | yes | - | - | deployed (dir), no usage record |
|
||||
| baoyu-infographic | yes | - | - | deployed (dir), no usage record |
|
||||
| blocked-page-recovery | yes | - | - | deployed (dir), no usage record |
|
||||
| box | yes | - | - | deployed (dir), no usage record |
|
||||
| claude-code | yes | - | - | deployed (dir), no usage record |
|
||||
| claude-design | yes | - | - | deployed (dir), no usage record |
|
||||
| codebase-inspection | yes | - | - | deployed (dir), no usage record |
|
||||
| codex | yes | - | - | deployed (dir), no usage record |
|
||||
| competitor-news-monitor | yes | - | - | deployed (dir), no usage record |
|
||||
| computer-use | yes | - | - | deployed (dir), no usage record |
|
||||
| design-md | yes | - | - | deployed (dir), no usage record |
|
||||
| document-to-action-items | yes | - | - | deployed (dir), no usage record |
|
||||
| docx | yes | - | - | deployed (dir), no usage record |
|
||||
| dogfood | yes | - | - | deployed (dir), no usage record |
|
||||
| email-inbox-triage | yes | active | 1 | deployed + usage-tracked / active |
|
||||
| findmy | yes | - | - | deployed (dir), no usage record |
|
||||
| gif-search | yes | - | - | deployed (dir), no usage record |
|
||||
| github | yes | - | - | deployed (dir), no usage record |
|
||||
| google-workspace | yes | - | - | deployed (dir), no usage record |
|
||||
| grounded-citations | yes | - | - | deployed (dir), no usage record |
|
||||
| hermes-agent | yes | active | 11 | deployed + usage-tracked / active |
|
||||
| hermes-agent-skill-authoring | yes | - | - | deployed (dir), no usage record |
|
||||
| himalaya | yes | - | - | deployed (dir), no usage record |
|
||||
| humanizer | yes | - | - | deployed (dir), no usage record |
|
||||
| imessage | yes | - | - | deployed (dir), no usage record |
|
||||
| inspecting-hermes-desktop-dom | yes | - | - | deployed (dir), no usage record |
|
||||
| llm-wiki | yes | - | - | deployed (dir), no usage record |
|
||||
| manim-video | yes | - | - | deployed (dir), no usage record |
|
||||
| maps | yes | - | - | deployed (dir), no usage record |
|
||||
| meeting-action-items | yes | active | 1 | deployed + usage-tracked / active |
|
||||
| node-inspect-debugger | yes | - | - | deployed (dir), no usage record |
|
||||
| notion | yes | - | - | deployed (dir), no usage record |
|
||||
| obsidian | yes | - | - | deployed (dir), no usage record |
|
||||
| opencode | yes | - | - | deployed (dir), no usage record |
|
||||
| p5js | yes | - | - | deployed (dir), no usage record |
|
||||
| pdf | yes | - | - | deployed (dir), no usage record |
|
||||
| popular-web-designs | yes | - | - | deployed (dir), no usage record |
|
||||
| powerpoint | yes | - | - | deployed (dir), no usage record |
|
||||
| product-price-monitor | yes | - | - | deployed (dir), no usage record |
|
||||
| python-debugpy | yes | - | - | deployed (dir), no usage record |
|
||||
| requesting-code-review | yes | - | - | deployed (dir), no usage record |
|
||||
| sdlc-review | yes | - | - | deployed (dir), no usage record |
|
||||
| simplify-code | yes | - | - | deployed (dir), no usage record |
|
||||
| songsee | yes | - | - | deployed (dir), no usage record |
|
||||
| songwriting-and-ai-music | yes | - | - | deployed (dir), no usage record |
|
||||
| spike | yes | - | - | deployed (dir), no usage record |
|
||||
| systematic-debugging | yes | - | - | deployed (dir), no usage record |
|
||||
| teams-meeting-pipeline | yes | - | - | deployed (dir), no usage record |
|
||||
| test-driven-development | yes | - | - | deployed (dir), no usage record |
|
||||
| weekly-review-planning | yes | - | - | deployed (dir), no usage record |
|
||||
| xlsx | yes | - | - | deployed (dir), no usage record |
|
||||
| xurl | yes | - | - | deployed (dir), no usage record |
|
||||
| youtube-content | yes | - | - | deployed (dir), no usage record |
|
||||
|
||||
## Verdict
|
||||
|
||||
Deployment is fully attested: 58 of 58 canonical skills are deployed. What is sparse is Hermes' *usage logging*: 3 of 58 deployed skills carry no usage record, so triage can confirm deployment but not per-skill usage.
|
||||
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Sol lane — sol-profile skill deployment & usage triage.
|
||||
|
||||
Classifies the sol profile's bundled skills by comparing three live sources:
|
||||
- .bundled_manifest : canonical skill list (name:hash per line)
|
||||
- category overlay dirs under skills/ : deployed skill subdirs
|
||||
- .usage.json : per-skill Hermes usage records
|
||||
|
||||
Produces two artifacts under /root/.hermes/wizard-outputs/sol/:
|
||||
- sol-profile-skill-triage-<date>.json (machine-readable record)
|
||||
- sol-profile-skill-triage-<date>.md (readable report)
|
||||
|
||||
Also prints a machine-readable summary block to stdout so the CHECK can diff
|
||||
its own live recomputation against the written artifact.
|
||||
|
||||
Evidence law: every count comes from a real filesystem walk; nothing is
|
||||
invented. A skill is "deployed" only if a real directory of that name exists
|
||||
under a category overlay dir.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
PROFILE = Path("/root/.hermes/profiles/sol")
|
||||
SKILLS = PROFILE / "skills"
|
||||
MANIFEST = SKILLS / ".bundled_manifest"
|
||||
USAGE_JSON = SKILLS / ".usage.json"
|
||||
OUT_DIR = Path("/root/.hermes/wizard-outputs/sol")
|
||||
REPO_DIR = Path("/root/troupe-standup/wizard-work/sol")
|
||||
|
||||
DATE = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
def to_utc(ts):
|
||||
return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def read_names():
|
||||
names = []
|
||||
for line in MANIFEST.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and ":" in line:
|
||||
names.append(line.split(":", 1)[0].strip())
|
||||
return names
|
||||
|
||||
|
||||
def read_deployed():
|
||||
"""Skill subdirs under category overlay dirs (containers, not skills)."""
|
||||
deployed = set()
|
||||
overlays = []
|
||||
for entry in sorted(SKILLS.iterdir()):
|
||||
if not entry.is_dir() or entry.name.startswith("."):
|
||||
continue
|
||||
overlays.append(entry.name)
|
||||
for sub in entry.iterdir():
|
||||
if sub.is_dir() and not sub.name.startswith("."):
|
||||
deployed.add(sub.name)
|
||||
return deployed, overlays
|
||||
|
||||
|
||||
def read_usage():
|
||||
if USAGE_JSON.exists():
|
||||
try:
|
||||
return json.loads(USAGE_JSON.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
return {}
|
||||
return {}
|
||||
|
||||
|
||||
def build():
|
||||
names = read_names()
|
||||
deployed, overlays = read_deployed()
|
||||
usage = read_usage()
|
||||
|
||||
slack_manifest = set(names)
|
||||
slack_deployed = set(deployed)
|
||||
not_deployed = sorted(slack_manifest - slack_deployed)
|
||||
extras = sorted(slack_deployed - slack_manifest)
|
||||
used = sorted(n for n in names if usage.get(n, {}).get("state") == "active")
|
||||
|
||||
rows = []
|
||||
for name in sorted(names):
|
||||
rec = usage.get(name)
|
||||
state = rec.get("state") if rec else None
|
||||
use_count = rec.get("use_count") if rec else None
|
||||
deployed_here = name in slack_deployed
|
||||
if deployed_here and state == "active":
|
||||
cls = "deployed + usage-tracked / active"
|
||||
elif deployed_here:
|
||||
cls = "deployed (dir), no usage record"
|
||||
elif rec is not None and state == "active":
|
||||
cls = "usage-tracked / active (not in profile)"
|
||||
else:
|
||||
cls = "not deployed / no usage record"
|
||||
rows.append({
|
||||
"skill": name,
|
||||
"deployed": deployed_here,
|
||||
"usage_state": state,
|
||||
"use_count": use_count,
|
||||
"class": cls,
|
||||
})
|
||||
|
||||
out = {
|
||||
"artifact": "sol-profile-skill-triage-%s.json" % DATE,
|
||||
"source": ".bundled_manifest + category overlay skill subdirs + .usage.json",
|
||||
"generated_at": to_utc(datetime.now(timezone.utc).timestamp()),
|
||||
"lane": "Triage - everyday Q&A and classification",
|
||||
"profile": str(PROFILE),
|
||||
"manifest_count": len(names),
|
||||
"deployed_count": len(deployed),
|
||||
"category_overlay_count": len(overlays),
|
||||
"active_usage_tracked": len(used),
|
||||
"not_deployed": not_deployed,
|
||||
"extras": extras,
|
||||
"skill_rows": rows,
|
||||
}
|
||||
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
json_path = OUT_DIR / out["artifact"]
|
||||
json_path.write_text(json.dumps(out, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
# ---- markdown report ----
|
||||
L = []
|
||||
A = L.append
|
||||
A("# Sol profile skill triage")
|
||||
A("")
|
||||
A("Date: %s (session start) | Evidence: live `ls` of %s; each category overlay "
|
||||
"dir walked for skill subdirs; `.bundled_manifest` parsed for the canonical "
|
||||
"skill list; `.usage.json` parsed for usage records." % (DATE, SKILLS))
|
||||
A("")
|
||||
A("## Summary")
|
||||
A("")
|
||||
A("| Metric | Count |")
|
||||
A("|---|---|")
|
||||
A("| Canonical skills in `.bundled_manifest` | %d |" % out["manifest_count"])
|
||||
A("| Skill subdirs actually deployed | %d |" % out["deployed_count"])
|
||||
A("| Category overlay dirs (containers) | %d |" % out["category_overlay_count"])
|
||||
A("| Usage-tracked / active | %d |" % out["active_usage_tracked"])
|
||||
A("")
|
||||
A("## Findings")
|
||||
A("")
|
||||
A("1. **All %d manifest skills are deployed** — every manifest name resolves to a "
|
||||
"skill subdirectory under one of the %d category overlay dirs; %d manifest skills "
|
||||
"are missing from the profile." % (out["manifest_count"], out["category_overlay_count"], len(not_deployed)))
|
||||
A("2. **Usage tracking is thin**: only %d of %d deployed skills carry a usage record; "
|
||||
"the other %d carry no Hermes usage event." % (out["active_usage_tracked"], out["deployed_count"], len(not_deployed)))
|
||||
A("3. **Category overlays are containers, not skills** — %d dirs hold the actual "
|
||||
"skills as subdirectories and are not counted as skills themselves." % out["category_overlay_count"])
|
||||
A("")
|
||||
A("## Skill table")
|
||||
A("")
|
||||
A("| Skill | Deployed | Usage state | Use count | Class |")
|
||||
A("|---|---|---|---|---|")
|
||||
for r in rows:
|
||||
A("| %s | %s | %s | %s | %s |" % (
|
||||
r["skill"], "yes" if r["deployed"] else "no",
|
||||
r["usage_state"] or "-", r["use_count"] or "-",
|
||||
r["class"].replace("|", "\\|")[:60]))
|
||||
A("")
|
||||
A("## Verdict")
|
||||
A("")
|
||||
A("Deployment is fully attested: %d of %d canonical skills are deployed. What is sparse "
|
||||
"is Hermes' *usage logging*: %d of %d deployed skills carry no usage record, so triage "
|
||||
"can confirm deployment but not per-skill usage." % (
|
||||
out["deployed_count"], out["manifest_count"],
|
||||
out["active_usage_tracked"], out["deployed_count"]))
|
||||
md_path = OUT_DIR / ("sol-profile-skill-triage-%s.md" % DATE)
|
||||
md_path.write_text("\n".join(L) + "\n", encoding="utf-8")
|
||||
|
||||
# also mirror a copy into the troupe repo work dir
|
||||
REPO_DIR.mkdir(parents=True, exist_ok=True)
|
||||
(REPO_DIR / json_path.name).write_text(json_path.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
(REPO_DIR / md_path.name).write_text(md_path.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
|
||||
print(json.dumps({
|
||||
"generated_at": out["generated_at"],
|
||||
"manifest_count": out["manifest_count"],
|
||||
"deployed_count": out["deployed_count"],
|
||||
"category_overlay_count": out["category_overlay_count"],
|
||||
"active_usage_tracked": out["active_usage_tracked"],
|
||||
"not_deployed": not_deployed,
|
||||
"extras": extras,
|
||||
"status": "VERIFY_OK",
|
||||
}, indent=2))
|
||||
return out
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
build()
|
||||
except Exception as e:
|
||||
print(json.dumps({"status": "VERIFY_FAIL", "error": "%s: %s" % (type(e).__name__, e)}))
|
||||
sys.exit(1)
|
||||
Reference in new issue
Block a user