#!/usr/bin/env python3 import argparse import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] ap = argparse.ArgumentParser() ap.add_argument('--job') ap.add_argument('--require-done', action='store_true') args = ap.parse_args() errors = [] if args.job: jp = ROOT / args.job if not jp.exists(): errors.append(f'missing_job: {args.job}') else: job = json.loads(jp.read_text(encoding='utf-8')) for art in job.get('expected_artifacts', []): p = ROOT / art if args.require_done and (not p.exists() or p.stat().st_size == 0): errors.append(f'missing_expected_artifact: {art}') else: checks = [ ROOT/'OWNER_DIGEST.md', ROOT/'triage'/'BACKLOG.md', ROOT/'triage'/'TOP_10_NEXT_ACTIONS.md', ROOT/'triage'/'MERGE_CANDIDATES.md', ROOT/'triage'/'ARCHIVE_CANDIDATES.md', ROOT/'triage'/'NEEDS_HUMAN.md', ] for p in checks: if not p.exists() or p.stat().st_size == 0: errors.append(f'missing_or_empty: {p.relative_to(ROOT)}') card_count = len(list((ROOT/'inventory'/'project_cards').glob('*.md'))) job_count = len(list((ROOT/'jobs'/'pending').glob('*.json'))) draft_count = len(list((ROOT/'github'/'issue_drafts').glob('*.md'))) project_count = 0 projects_path = ROOT/'inventory'/'projects.jsonl' if projects_path.exists(): project_count = sum(1 for line in projects_path.read_text(encoding='utf-8', errors='ignore').splitlines() if line.strip()) if card_count < 1: errors.append('no_project_cards') if project_count and card_count != project_count: errors.append(f'project_card_count_mismatch: projects={project_count} cards={card_count}') if job_count < 1: errors.append('no_pending_jobs') if draft_count < 1: errors.append('no_issue_drafts') expected_drafts = min(25, project_count) if project_count else 0 if expected_drafts and draft_count < expected_drafts: errors.append(f'issue_draft_count_too_low: expected_at_least={expected_drafts} actual={draft_count}') if errors: print('verify_artifacts: failed') for e in errors: print(f'- {e}') raise SystemExit(1) print('verify_artifacts: passed')