#!/usr/bin/env python3
import argparse
import html
import json
from datetime import date
from pathlib import Path
from typing import Any
from render_world_class_evidence_intake import build_intake
from render_world_class_evidence_ledger import build_ledger
from render_world_class_submission_review import build_submission_review
ROOT = Path(__file__).resolve().parent.parent
SCRIPT_INTERFACE = "cli"
SCRIPT_INTERFACE_REASON = "Renders an operator runbook for collecting pending world-class evidence without accepting evidence."
def rel_path(path: Path, root: Path) -> str:
try:
return str(path.resolve().relative_to(root.resolve()))
except ValueError:
return str(path.resolve())
def html_text(value: Any) -> str:
return html.escape(str(value or ""), quote=True)
def by_key(items: list[dict[str, Any]], key_name: str) -> dict[str, dict[str, Any]]:
return {str(item.get(key_name, "")): item for item in items if item.get(key_name)}
def output_path(path: str, skill_dir: Path) -> str:
candidate = Path(path)
if candidate.is_absolute():
return rel_path(candidate, skill_dir)
return path
def build_runbook_item(
entry: dict[str, Any],
checklist: dict[str, Any],
review_item: dict[str, Any],
) -> dict[str, Any]:
commands = checklist.get("commands", {}) if isinstance(checklist.get("commands", {}), dict) else {}
must_collect = checklist.get("must_collect", {}) if isinstance(checklist.get("must_collect", {}), dict) else {}
return {
"evidence_key": entry.get("key", ""),
"label": entry.get("label", entry.get("key", "")),
"category": entry.get("category", "external"),
"owner": entry.get("owner", "release reviewer"),
"ledger_status": entry.get("status", "pending"),
"intake_readiness": checklist.get("readiness", "missing"),
"review_state": review_item.get("review_state", "missing"),
"source_accepted": review_item.get("source_accepted") is True,
"objective": entry.get("objective", ""),
"current": entry.get("current", ""),
"blocking_reason": review_item.get("blocking_reason") or checklist.get("blocking_reason") or entry.get("next_action", ""),
"submission_path": checklist.get("submission_path") or entry.get("submission_state", {}).get("path", ""),
"template_path": checklist.get("template_path", ""),
"commands": {
"prepare_submission": commands.get("prepare_submission", ""),
"validate_intake": commands.get("validate_intake", ""),
"review_queue": commands.get("submission_review", ""),
"refresh_ledger": commands.get("refresh_ledger", "python3 scripts/yao.py world-class-ledger ."),
"guard_claim": commands.get("guard_claim", "python3 scripts/yao.py world-class-claim-guard ."),
},
"must_collect": {
"provenance_requirements": must_collect.get("provenance_requirements", entry.get("provenance_requirements", [])),
"success_checks": must_collect.get("success_checks", entry.get("success_checks", [])),
"privacy_contract": must_collect.get("privacy_contract", entry.get("privacy_contract", [])),
},
"evidence_artifacts": entry.get("evidence_artifacts", []),
"observed_state": entry.get("observed_state", {}),
"submission_state": entry.get("submission_state", {}),
"anti_overclaim": entry.get("anti_overclaim", {}),
}
def build_operator_runbook(skill_dir: Path, generated_at: str, submissions_dir: Path | None = None) -> dict[str, Any]:
submissions_dir = submissions_dir or (skill_dir / "evidence" / "world_class" / "submissions")
ledger = build_ledger(skill_dir, generated_at, submissions_dir=submissions_dir)
intake = build_intake(skill_dir, generated_at, submissions_dir=submissions_dir)
review = build_submission_review(skill_dir, generated_at, submissions_dir=submissions_dir)
checklist_by_key = by_key(intake.get("operator_checklist", []), "evidence_key")
review_by_key = by_key(review.get("items", []), "evidence_key")
items = [
build_runbook_item(entry, checklist_by_key.get(str(entry.get("key", "")), {}), review_by_key.get(str(entry.get("key", "")), {}))
for entry in ledger.get("entries", [])
]
summary = ledger.get("summary", {})
review_summary = review.get("summary", {})
return {
"schema_version": "1.0",
"ok": True,
"generated_at": generated_at,
"skill_dir": rel_path(skill_dir, ROOT),
"summary": {
"evidence_item_count": len(items),
"pending_count": summary.get("pending_count", 0),
"accepted_count": summary.get("accepted_count", 0),
"awaiting_submission_count": review_summary.get("awaiting_submission_count", 0),
"ready_for_ledger_review_count": review_summary.get("ready_for_ledger_review_count", 0),
"valid_packet_source_incomplete_count": review_summary.get("valid_packet_source_incomplete_count", 0),
"invalid_submission_count": review_summary.get("invalid_submission_count", 0),
"ready_to_claim_world_class": summary.get("ready_to_claim_world_class") is True,
"runbook_counts_as_completion": False,
"decision": "ready-for-completion-audit" if summary.get("ready_to_claim_world_class") is True else "collect-evidence",
},
"submissions": {
"directory": rel_path(submissions_dir, skill_dir),
"runbook_counts_submission_as_completion": False,
},
"items": items,
"source_reports": {
"ledger": "reports/world_class_evidence_ledger.json",
"intake": "reports/world_class_evidence_intake.json",
"submission_review": "reports/world_class_submission_review.json",
"claim_guard": "reports/world_class_claim_guard.json",
},
"artifacts": {
"json": "reports/world_class_operator_runbook.json",
"markdown": "reports/world_class_operator_runbook.md",
"html": "reports/world_class_operator_runbook.html",
},
}
def list_lines(values: list[Any], empty: str) -> list[str]:
if not values:
return [f"- {empty}"]
return [f"- {value}" for value in values]
def render_markdown(report: dict[str, Any]) -> str:
summary = report["summary"]
lines = [
"# World-Class Operator Runbook",
"",
f"Generated at: `{report['generated_at']}`",
"",
"## Summary",
"",
f"- decision: `{summary['decision']}`",
f"- ready to claim world-class: `{str(summary['ready_to_claim_world_class']).lower()}`",
f"- runbook counts as completion: `{str(summary['runbook_counts_as_completion']).lower()}`",
f"- evidence items: `{summary['evidence_item_count']}`",
f"- pending: `{summary['pending_count']}`",
f"- awaiting submission: `{summary['awaiting_submission_count']}`",
f"- ready for ledger review: `{summary['ready_for_ledger_review_count']}`",
"",
"This runbook coordinates evidence collection only. It does not accept submissions or make world-class completion true.",
"",
"## Fast Path",
"",
"1. Run the real external or human work for one evidence item.",
"2. Generate the matching submission draft.",
"3. Replace template-only fields with aggregate evidence and provenance.",
"4. Validate intake, review the queue, refresh the ledger, then run the claim guard.",
"",
"## Evidence Items",
"",
"| Evidence | Ledger | Intake | Review | Owner |",
"| --- | --- | --- | --- | --- |",
]
for item in report["items"]:
lines.append(
f"| `{item['evidence_key']}` | `{item['ledger_status']}` | `{item['intake_readiness']}` | "
f"`{item['review_state']}` | {item['owner']} |"
)
for item in report["items"]:
lines.extend(
[
"",
f"## {item['label']}",
"",
f"- objective: {item['objective']}",
f"- blocking reason: {item['blocking_reason']}",
f"- submission: `{item['submission_path'] or 'missing'}`",
f"- template: `{item['template_path'] or 'missing'}`",
"",
"### Commands",
"",
]
)
for label, command in item["commands"].items():
lines.append(f"- {label}: `{command}`")
lines.extend(["", "### Must Collect", ""])
lines.extend(list_lines(item["must_collect"].get("provenance_requirements", []), "No provenance requirements listed."))
lines.extend(["", "### Success Checks", ""])
lines.extend(list_lines(item["must_collect"].get("success_checks", []), "No success checks listed."))
lines.extend(["", "### Privacy Contract", ""])
lines.extend(list_lines(item["must_collect"].get("privacy_contract", []), "No privacy contract listed."))
lines.extend(["", "### Evidence Artifacts", ""])
lines.extend(list_lines(item.get("evidence_artifacts", []), "No evidence artifacts listed."))
lines.extend(
[
"",
"## Boundary",
"",
"- Planned work, draft packets, metadata fallback, pending human decisions, and local command runners do not count as completion.",
"- Valid intake means ready for submission review; ledger review still requires passing source evidence.",
"- The world-class ledger and claim guard remain the source of truth.",
]
)
return "\n".join(lines).rstrip() + "\n"
def html_list(values: list[Any], empty: str) -> str:
if not values:
return f"
{html_text(empty)} "
return "".join(f"{html_text(value)} " for value in values)
def render_html_item(item: dict[str, Any]) -> str:
commands = "".join(
f"{html_text(label.replace('_', ' '))} {html_text(command)} "
for label, command in item["commands"].items()
)
must_collect = item["must_collect"]
return f"""
{html_text(item['category'])} ยท {html_text(item['review_state'])} {html_text(item['label'])}
{html_text(item['blocking_reason'])}
Owner {html_text(item['owner'])}
Ledger {html_text(item['ledger_status'])}
Submission {html_text(item['submission_path'])}
Must Collect {html_list(must_collect.get('provenance_requirements', []), 'No provenance requirements listed.')}
Success Checks {html_list(must_collect.get('success_checks', []), 'No success checks listed.')}
Privacy {html_list(must_collect.get('privacy_contract', []), 'No privacy contract listed.')}
""".strip()
def render_html(report: dict[str, Any]) -> str:
summary = report["summary"]
stats = [
("Pending", summary["pending_count"]),
("Awaiting", summary["awaiting_submission_count"]),
("Ready", summary["ready_for_ledger_review_count"]),
("Invalid", summary["invalid_submission_count"]),
]
stat_html = "".join(f"{html_text(label)} {html_text(value)} " for label, value in stats)
item_html = "".join(render_html_item(item) for item in report["items"])
return f"""
World-Class Operator Runbook
Evidence Operations
World-Class Operator Runbook
A single operating page for collecting the remaining human and external evidence. It coordinates action, but does not accept evidence or change the ledger.
{stat_html}
Fast Path Run the real external or human work for one evidence item. Generate and fill the matching submission draft. Validate intake and inspect the submission review queue. Refresh the ledger and run the claim guard before making any completion claim.
Evidence Items {item_html}
Boundary Planned work, draft packets, metadata fallback, pending human decisions, and local command runners do not count as completion. Valid intake means ready for submission review; ledger review still requires passing source evidence. The world-class ledger and claim guard remain the source of truth.
"""
def main() -> None:
parser = argparse.ArgumentParser(description="Render an operator runbook for collecting pending world-class evidence.")
parser.add_argument("skill_dir", nargs="?", default=".")
parser.add_argument("--submissions-dir")
parser.add_argument("--output-json", default="reports/world_class_operator_runbook.json")
parser.add_argument("--output-md", default="reports/world_class_operator_runbook.md")
parser.add_argument("--output-html", default="reports/world_class_operator_runbook.html")
parser.add_argument("--generated-at", default=date.today().isoformat())
args = parser.parse_args()
skill_dir = Path(args.skill_dir).resolve()
submissions_dir = Path(args.submissions_dir).resolve() if args.submissions_dir else None
report = build_operator_runbook(skill_dir, args.generated_at, submissions_dir=submissions_dir)
outputs = {
"json": Path(args.output_json),
"markdown": Path(args.output_md),
"html": Path(args.output_html),
}
for key, path in outputs.items():
if not path.is_absolute():
path = skill_dir / path
path.parent.mkdir(parents=True, exist_ok=True)
report["artifacts"][key] = output_path(str(path), skill_dir)
if key == "json":
path.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
elif key == "markdown":
path.write_text(render_markdown(report), encoding="utf-8")
else:
path.write_text(render_html(report), encoding="utf-8")
print(json.dumps(report, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()