#!/usr/bin/env python3 """Build the public release-check summary. This is a public release map over the existing validators. It does not replace the validators; it makes the release state readable in one file and one machine-readable JSON bundle. """ from __future__ import annotations import json from datetime import datetime, timezone from pathlib import Path ROOT = Path(__file__).resolve().parents[1] OUTPUT_JSON = ROOT / "docs/data/quality_gates.json" OUTPUT_MD = ROOT / "QUALITY_GATES.md" GATES = [ { "id": "scale_up_status", "title": "Multi-episode pilot status", "command": "python scripts/validate_scope_claims.py", "report": "docs/data/scope_claims_audit.json", "blocks_if": "Setup identifiers are presented as completed held-out metrics.", "shows": "Qwen3-Omni setup artifacts stay distinct from the planned held-out pilot.", }, { "id": "source_alignment", "title": "Source alignment", "command": "python scripts/validate_source_alignment.py", "report": "docs/data/source_alignment_audit.json", "blocks_if": "Official full-dataset facts, sample-card facts, API-listing notes, or project coverage are missing or inconsistent.", "shows": "The repo, website, and Hugging Face cards preserve the Xperience-10M source facts and current project scope.", }, { "id": "website_integrity", "title": "Website integrity", "command": "python scripts/validate_website_integrity.py", "report": "docs/data/website_integrity.json", "blocks_if": "Local links, anchors, JSON bundles, or referenced image assets are missing or invalid.", "shows": "The GitHub Pages / HF static surface is self-consistent before upload.", }, { "id": "rendered_site_check", "title": "Rendered website check", "command": "python scripts/build_rendered_site_check.py --input /tmp/xperience_rendered_site_observations.json", "report": "docs/data/rendered_site_check.json", "blocks_if": "The local rendered site cannot load, switch tabs, deep-link to the walkthrough, update player controls, or stay console-clean.", "shows": "The published static page has a recent browser-level interaction record in addition to static link checks.", }, { "id": "task_surface_integrity", "title": "Task surface integrity", "command": "python scripts/validate_task_surface.py", "report": "docs/data/task_surface_integrity.json", "blocks_if": "Task cards expose raw artifact ids, human-readable task names drift, modality thumbnails are missing, or the interactive task player is not wired to the generated JSON.", "shows": "The public task cards and walkthrough/player stay aligned with generated task-suite metadata.", }, { "id": "evaluation_protocol", "title": "Evaluation protocol", "command": "python scripts/build_evaluation_protocol.py", "report": "docs/data/evaluation_protocol.json", "blocks_if": "Windowing, split policy, leakage controls, task metrics, or current limitations are not explicit.", "shows": "The task evaluation protocol is generated from committed metric artifacts.", }, { "id": "task_method_source_audit", "title": "Task-method source audit", "command": "python scripts/validate_task_method_matrix_sources.py", "report": "docs/data/task_method_20_source_audit.json", "blocks_if": "A scored 20-task matrix cell points to a JSON metric source that does not contain the same metric value.", "shows": "Public 20-task scores remain traceable to their task-specific metric artifacts.", }, { "id": "figure_index", "title": "Figure index", "command": "python scripts/build_figure_index.py", "report": "docs/data/figure_index.json", "blocks_if": "Public figures, charts, or modality thumbnails are missing, unreadable, or lack source-script provenance.", "shows": "Public visual assets have dimensions, SHA-256 hashes, source scripts, and presentation roles.", }, { "id": "brand_assets", "title": "Brand assets", "command": "python scripts/build_brand_assets.py", "report": "docs/data/brand_assets.json", "blocks_if": "The generated logo system, favicon, social card, or app icons are missing or not reproducibly packaged.", "shows": "The same project logo is available for website header, favicon, README, Hugging Face cards, and social previews.", }, { "id": "quality_gate_manifest", "title": "Release-check manifest", "command": "python scripts/build_quality_gates.py", "report": "docs/data/quality_gates.json", "blocks_if": "A public reader cannot see the current release state in one place.", "shows": "The release checklist is explicit, versioned, and mirrored with the repo.", }, { "id": "artifact_index", "title": "Artifact index", "command": "python scripts/build_artifact_index.py", "report": "docs/data/artifact_index.json", "blocks_if": "Project-critical evidence files are missing from the indexed artifact layer.", "shows": "Core project artifacts exist and stable files have SHA-256 hashes.", }, { "id": "publication_package", "title": "Public bundle contents", "command": "python scripts/validate_publication_package.py", "report": "docs/data/publication_audit.json", "blocks_if": "Raw data, caches, heavy archives, credential text, missing required assets, or outdated public-card assets enter public bundles.", "shows": "The repo and prepared HF bundles contain the intended public files for release.", }, { "id": "public_surface_qa", "title": "Public project surface", "command": "python scripts/build_public_surface_qa.py", "report": "docs/data/public_surface_qa.json", "blocks_if": "Repo, website, or Hugging Face presentation loses SEO/social metadata, accessible tab semantics, source links, project-check links, or clear project language.", "shows": "The public repo, website, and Hugging Face cards read as one cohesive research project surface.", }, { "id": "mirror_parity", "title": "Prepared mirror parity", "command": "python scripts/validate_mirror_parity.py", "report": "docs/data/mirror_parity.json", "blocks_if": "Prepared HF Space, artifact dataset, or model bundle diverges from the repo for critical files.", "shows": "The files staged for GitHub and Hugging Face are synchronized before upload.", }, ] POST_PUBLISH_CHECKS = [ { "id": "live_publication_verifier", "title": "Live publication verifier", "evidence": "python scripts/verify_live_publication.py", "required_result": "live GitHub Pages, GitHub raw, HF Space, artifact dataset, and model mirrors match the current release assets", }, { "id": "github_pages_deploy", "title": "GitHub Pages deployment", "evidence": "gh run list --repo ChaoYue0307/ropedia-xperience-10m-task-suite --limit 5", "required_result": "latest pages-build-deployment run succeeds", }, { "id": "rendered_browser_check", "title": "Rendered browser check", "evidence": "Browser/Playwright page identity, nonblank render, console health, and one local interaction", "required_result": "no relevant console warnings/errors and target links work", }, ] def read_status(path: Path) -> dict: if not path.exists(): return {"exists": False, "status": "missing"} try: payload = json.loads(path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: return {"exists": True, "status": "invalid_json", "error": str(exc)} return { "exists": True, "status": str(payload.get("status", "unknown")), } def build_payload() -> dict: gate_records = [] generated_at = datetime.now(timezone.utc).isoformat(timespec="seconds") for gate in GATES: if gate["id"] == "quality_gate_manifest": status = {"exists": True, "status": "pass"} else: status = read_status(ROOT / gate["report"]) gate_records.append({**gate, "current_report": status}) overall_status = "pass" if all(item["current_report"]["status"] == "pass" for item in gate_records) else "fail" return { "title": "Ropedia Xperience-10M Release Checks", "status": overall_status, "generated_at_utc": generated_at, "rule": "A release is current when the automated reports pass and the live GitHub/Hugging Face mirrors are verified after publishing.", "automated_gates": gate_records, "post_publish_checks": POST_PUBLISH_CHECKS, "scope_note": "These checks cover public packaging, project status wording, mirror parity, and website integrity. Cross-episode model quality is measured by later held-out evaluation reports.", } def markdown(payload: dict) -> str: lines = [ "# Release Checks", "", "This file is the release map for the Ropedia Xperience-10M Task Suite.", "", f"Current gate status: **{payload['status']}**", "", payload["rule"], "", payload["scope_note"], "", "## Automated Checks", "", "| Check | Command | Report | Current status | Needs attention when |", "| --- | --- | --- | --- | --- |", ] for gate in payload["automated_gates"]: report_status = gate["current_report"]["status"] lines.append( f"| {gate['title']} | `{gate['command']}` | `{gate['report']}` | `{report_status}` | {gate['blocks_if']} |" ) lines.extend([ "", "## Post-Publish Checks", "", "| Check | Evidence | Required result |", "| --- | --- | --- |", ]) for check in payload["post_publish_checks"]: lines.append(f"| {check['title']} | `{check['evidence']}` | {check['required_result']} |") lines.extend([ "", "## Rerun Order", "", "```bash", "python scripts/validate_scope_claims.py", "python scripts/validate_source_alignment.py", "python scripts/build_evaluation_protocol.py", "python scripts/validate_task_method_matrix_sources.py", "python scripts/build_brand_assets.py", "python scripts/build_figure_index.py", "python scripts/validate_website_integrity.py", "python scripts/build_rendered_site_check.py --input /tmp/xperience_rendered_site_observations.json", "python scripts/validate_task_surface.py", "python scripts/build_quality_gates.py", "python scripts/build_artifact_index.py", "python scripts/validate_publication_package.py", "python scripts/build_public_surface_qa.py", "python scripts/validate_mirror_parity.py", "```", "", "After Hugging Face bundle sync, rerun `validate_publication_package.py` and `validate_mirror_parity.py` once more before upload.", "", ]) return "\n".join(lines) def main() -> int: payload = build_payload() OUTPUT_JSON.parent.mkdir(parents=True, exist_ok=True) OUTPUT_JSON.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") OUTPUT_MD.write_text(markdown(payload), encoding="utf-8") print(f"{payload['status'].upper()}: wrote {OUTPUT_JSON}") print(f"{payload['status'].upper()}: wrote {OUTPUT_MD}") return 0 if payload["status"] == "pass" else 1 if __name__ == "__main__": raise SystemExit(main())