diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index d03564b..87c3798 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,12 +1,11 @@ -name: Deploy review demo +name: Deploy CounterProof Proof Lab on: push: branches: [main] paths: - - 'skill_factory/**' - - 'skills/**' - 'site/**' + - 'skill_factory/evolution/capabilities.py' - 'scripts/build_pages.py' - '.github/workflows/pages.yml' workflow_dispatch: @@ -42,7 +41,7 @@ jobs: echo "GitHub Pages is enabled." elif [[ "$status" == "404" ]]; then echo "enabled=false" >> "$GITHUB_OUTPUT" - echo "::notice title=GitHub Pages not enabled::Skipping deployment. Enable Pages for this repository with GitHub Actions as the source, then re-run this workflow." + echo "::notice title=GitHub Pages not enabled::Built the Proof Lab successfully, but deployment is skipped. Enable Pages with GitHub Actions as the source, then re-run this workflow." else echo "Unexpected GitHub Pages API status: $status" >&2 cat /tmp/counterproof-pages.json >&2 || true @@ -50,25 +49,25 @@ jobs: fi - uses: actions/checkout@v4 - if: steps.pages.outputs.enabled == 'true' - uses: actions/setup-python@v5 - if: steps.pages.outputs.enabled == 'true' with: python-version: '3.12' - cache: pip - - - name: Install, verify and test - if: steps.pages.outputs.enabled == 'true' - run: | - pip install -e '.[dev]' - ruff check skill_factory/ tests/ - pytest -q - - name: Build review surface from repository skills - if: steps.pages.outputs.enabled == 'true' + - name: Build CounterProof Proof Lab run: python scripts/build_pages.py + - name: Validate static artifact + shell: bash + run: | + set -euo pipefail + test -f dist/index.html + test -f dist/app.js + test -f dist/data/build.json + test -f dist/data/capabilities.json + grep -q '"commit"' dist/data/build.json + grep -q 'CounterProof' dist/index.html + - uses: actions/configure-pages@v5 if: steps.pages.outputs.enabled == 'true' @@ -77,7 +76,7 @@ jobs: with: path: dist - - name: Deploy to GitHub Pages + - name: Deploy CounterProof Proof Lab if: steps.pages.outputs.enabled == 'true' id: deployment uses: actions/deploy-pages@v4 diff --git a/scripts/build_pages.py b/scripts/build_pages.py index 968cfa0..e5ec15e 100644 --- a/scripts/build_pages.py +++ b/scripts/build_pages.py @@ -1,4 +1,4 @@ -"""Build a static review UI from the repository's real skills and validators.""" +"""Build the static CounterProof Proof Lab for GitHub Pages.""" from __future__ import annotations @@ -9,73 +9,39 @@ from pathlib import Path from skill_factory.evolution.capabilities import capability_report -from skill_factory.loader import load_skill -from skill_factory.verifier.static_check import verify_skill ROOT = Path(__file__).resolve().parents[1] -SKILLS = ROOT / "skills" DIST = ROOT / "dist" -def read_json(path: Path): - return json.loads(path.read_text(encoding="utf-8")) if path.exists() else None - - -def serialize_skill(skill_dir: Path) -> dict: - skill = load_skill(skill_dir) - result = verify_skill(skill_dir) - return { - "name": skill.name, - "description": skill.description, - "version": skill.meta.version, - "domain": skill.meta.domain, - "tags": skill.meta.tags, - "content": skill.content, - "validation": { - "passed": result.passed, - "errors": result.errors, - "warnings": result.warnings, - }, - "evals": read_json(skill_dir / "evals" / "evals.json"), - "trigger_queries": read_json(skill_dir / "evals" / "trigger_queries.json"), - "resources": { - "scripts": len(list((skill_dir / "scripts").glob("*.py"))) if (skill_dir / "scripts").exists() else 0, - "references": len(list((skill_dir / "references").glob("*"))) if (skill_dir / "references").exists() else 0, - "assets": len(list((skill_dir / "assets").glob("*"))) if (skill_dir / "assets").exists() else 0, - }, - } - - def main() -> None: if DIST.exists(): shutil.rmtree(DIST) shutil.copytree(ROOT / "site", DIST) - skills = [ - serialize_skill(path) - for path in sorted(SKILLS.iterdir()) - if path.is_dir() and (path / "SKILL.md").exists() - ] - payload = { + + data = DIST / "data" + data.mkdir(exist_ok=True) + + build = { "generated_at": datetime.now(timezone.utc).isoformat(), "commit": subprocess.run( - ["git", "rev-parse", "--short", "HEAD"], cwd=ROOT, check=True, - capture_output=True, text=True, + ["git", "rev-parse", "--short", "HEAD"], + cwd=ROOT, + check=True, + capture_output=True, + text=True, ).stdout.strip(), - "skills": skills, - "summary": { - "total": len(skills), - "valid": sum(item["validation"]["passed"] for item in skills), - "eval_cases": sum(len((item["evals"] or {}).get("cases", item["evals"] or [])) for item in skills), - }, } - data = DIST / "data" - data.mkdir(exist_ok=True) - (data / "skills.json").write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") + (data / "build.json").write_text( + json.dumps(build, ensure_ascii=False, indent=2), + encoding="utf-8", + ) (data / "capabilities.json").write_text( json.dumps(capability_report(), ensure_ascii=False, indent=2), encoding="utf-8", ) (DIST / ".nojekyll").touch() + if __name__ == "__main__": main() diff --git a/site/app.js b/site/app.js index 697670e..36db838 100644 --- a/site/app.js +++ b/site/app.js @@ -415,7 +415,7 @@ async function init() { fetch("data/evolution_cases.json").then(r => { if (!r.ok) throw new Error("case data " + r.status); return r.json(); }), fetch("data/capabilities.json").then(r => { if (!r.ok) throw new Error("capabilities " + r.status); return r.json(); }), fetch("data/reality_cases.json").then(r => r.ok ? r.json() : {cases: []}).catch(() => ({cases: []})), - fetch("data/skills.json").then(r => r.ok ? r.json() : null).catch(() => null) + fetch("data/build.json").then(r => r.ok ? r.json() : null).catch(() => null) ]); cases = casePayload.cases; capabilities = capabilityPayload.capabilities; diff --git a/site/standalone.html b/site/standalone.html index 1303d44..be0b16a 100644 --- a/site/standalone.html +++ b/site/standalone.html @@ -1195,7 +1195,7 @@

What is real today,
and what is still a research target.

if(u.endsWith("data/evolution_cases.json")) return new Response(JSON.stringify(__COUNTERPROOF_CASES__),{status:200,headers:{"Content-Type":"application/json"}}); if(u.endsWith("data/capabilities.json")) return new Response(JSON.stringify(__COUNTERPROOF_CAPS__),{status:200,headers:{"Content-Type":"application/json"}}); if(u.endsWith("data/reality_cases.json")) return new Response(JSON.stringify(__COUNTERPROOF_REALITY__),{status:200,headers:{"Content-Type":"application/json"}}); - if(u.endsWith("data/skills.json")) return new Response(JSON.stringify({commit:"counterproof-reality-intake"}),{status:200,headers:{"Content-Type":"application/json"}}); + if(u.endsWith("data/build.json")) return new Response(JSON.stringify({commit:"counterproof-proof-lab"}),{status:200,headers:{"Content-Type":"application/json"}}); if(__nativeFetch) return __nativeFetch(url,options); throw new Error("Network unavailable"); }; @@ -1616,7 +1616,7 @@

What is real today,
and what is still a research target.

fetch("data/evolution_cases.json").then(r => { if (!r.ok) throw new Error("case data " + r.status); return r.json(); }), fetch("data/capabilities.json").then(r => { if (!r.ok) throw new Error("capabilities " + r.status); return r.json(); }), fetch("data/reality_cases.json").then(r => r.ok ? r.json() : {cases: []}).catch(() => ({cases: []})), - fetch("data/skills.json").then(r => r.ok ? r.json() : null).catch(() => null) + fetch("data/build.json").then(r => r.ok ? r.json() : null).catch(() => null) ]); cases = casePayload.cases; capabilities = capabilityPayload.capabilities;