#!/usr/bin/env bash set -euo pipefail usage() { cat < Validate that a skill's sources provenance chain is complete and internally consistent. Arguments: skill-dir Path to the skill directory to validate. Exit codes: 0 All checks passed (or nothing to validate) 1 One or more checks failed Checks performed: 0 source_keys present but references/sources.md absent 1 FILL IN: placeholders in sources.md 2 source_keys in SKILL.md → slug exists in sources.md 3 source_keys in references/*.md → slug exists in sources.md (INFO if no source_keys) 4 Contributing files listed in sources.md exist on disk 5 Contributing files back-reference the parent slug in their source_keys 6 Research doc field present and not placeholder 7 Slug in sources.md present in upstream research doc (INFO only) 8 Extracted non-(none) slug in research doc present in sources.md EOF } if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then usage exit 0 fi if [[ $# -lt 1 ]]; then echo "Error: skill-dir is required." >&2 echo "" >&2 usage >&2 exit 1 fi python3 -u - "$1" <<'PYTHON' import sys import os import re skill_dir = os.path.abspath(sys.argv[1]) sources_md_path = os.path.join(skill_dir, "references", "sources.md") refs_dir = os.path.join(skill_dir, "references") # --- Helpers --- PLACEHOLDER_RE = re.compile(r'(?' to the '## {slug}' entry in references/sources.md." ) elif rd_value == "" or PLACEHOLDER_RE.search(rd_value): emit_fail( f"Research doc field is empty or placeholder", f"references/sources.md (## {slug})", f"The '## {slug}' entry has an unfilled Research doc value.", f"Set '- **Research doc:**' to a real path relative to repo root, or '(none)' if not applicable." ) else: # Check 7: Upstream forward — slug should appear in research doc if repo_root and not rd_value.startswith("(none"): rd_abs = os.path.join(repo_root, rd_value) if os.path.isfile(rd_abs): with open(rd_abs) as f: rd_content = f.read() rd_slugs = set(parse_h2_slugs(rd_content)) if slug not in rd_slugs: emit_info( f"Slug '{slug}' not found as H2 in research doc '{rd_value}'", f"references/sources.md (## {slug})", f"The research doc '{rd_value}' does not have a '## {slug}' heading. " f"The provenance link may be imprecise — the slug name in sources.md may differ from the research doc's heading." ) # Track for Check 8 if rd_abs not in research_docs_seen: research_docs_seen[rd_abs] = (rd_value, set()) research_docs_seen[rd_abs][1].add(slug) # --- Check 8: Upstream reverse --- for rd_abs, (rd_rel, known_slugs) in research_docs_seen.items(): with open(rd_abs) as f: rd_content = f.read() for rd_slug in parse_h2_slugs(rd_content): # Parse this slug's Contributing files and Status in the research doc rd_cf = parse_contributing_files(rd_content, rd_slug) rd_status = parse_status(rd_content, rd_slug) # Skip if contributing files start with (none if rd_cf and rd_cf.startswith("(none"): continue # Skip if status is not `extracted` if rd_status != "`extracted`": continue # This slug should be in sources.md if rd_slug not in sources_slugs: emit_fail( f"Research doc slug '{rd_slug}' missing from skill sources.md", f"references/sources.md", f"The research doc '{rd_rel}' has '## {rd_slug}' with status `extracted` and contributing files, " f"but this skill's sources.md has no '## {rd_slug}' entry.", f"Add '## {rd_slug}' to references/sources.md or mark it as '(none)' in the research doc's Contributing files." ) print_findings() sys.exit(1 if has_fail else 0) PYTHON