#!/usr/bin/env python3 """Verify that R2 workflow sources are connected to deterministic gateways.""" from __future__ import annotations import argparse import json from pathlib import Path import sys from typing import Any, Iterable DEFAULT_ROOT = Path(__file__).resolve().parents[2] RESULT_SCHEMA = "workflow-connection-result/v1" WRITER_SOURCES = ( Path("harness/source/agents/bodies/wiki-doc-author.md"), Path("harness/source/agents/bodies/wiki-source-summarizer.md"), ) GLOBAL_REPORT_SOURCE = Path(".agents/plugins/wiki-superpowers/skills/wiki-workflow/SKILL.md") WRITER_REQUIRED = ( "harness/runtime/document_commit.py", "document-commit/v1", "document-commit-result/v1", "--dry-run", "plan_sha256", "--expected-plan-sha256", "--apply", ) WRITER_FORBIDDEN = ( "자동 rollback 미구현", "**C4. Parent hub Cluster 갱신**", "**M5. Parent hub Cluster 점검**", "### Step 6: Parent hub Cluster 갱신", ) REPORT_REQUIRED = ( "proof-request/v1", "harness/runtime/proof_runner.py", "proof-runner-result/v1", "proof-manifest/v1", "manifest_sha256", "proof_count", "pass_count", "fail_count", "1~3", "실패", ) SEMANTIC_WORKFLOW_SOURCES = ( Path("harness/source/skills/project-spec.md"), Path("harness/source/skills/branch-spec.md"), Path("harness/source/skills/sync.md"), ) SEMANTIC_REQUIRED = ( "semantic_surface_extractor.py", "semantic_candidate_builder.py", "wiki-semantic-coherence-auditor", "semantic_audit.py", "semantic certificate", ) PARENT_CERTIFICATE_SOURCE = Path("harness/source/skills/branch-from-project.md") PARENT_CERTIFICATE_REQUIRED = ( "semantic_certificate.py", "--mode hub", "--path raw/project-notes/.md", ) class ConnectionCheckError(RuntimeError): pass def _finding(code: str, path: Path, token: str) -> dict[str, str]: return {"code": code, "path": path.as_posix(), "token": token} def _require_tokens(path: Path, text: str, tokens: Iterable[str]) -> list[dict[str, str]]: return [_finding("MISSING_REQUIRED_CONNECTION", path, token) for token in tokens if token not in text] def _report_sources(root: Path) -> list[Path]: body_root = root / "harness/source/agents/bodies" sources = [ path.relative_to(root) for path in body_root.glob("*.md") if "§7.1" in path.read_text(encoding="utf-8") or "Self-Grep" in path.read_text(encoding="utf-8") ] sources.append(GLOBAL_REPORT_SOURCE) return sorted(set(sources), key=lambda item: item.as_posix()) def check(root: Path) -> dict[str, Any]: root = root.resolve(strict=True) findings: list[dict[str, str]] = [] for relative in WRITER_SOURCES: path = root / relative if not path.is_file(): findings.append(_finding("MISSING_CONNECTION_SOURCE", relative, "")) continue text = path.read_text(encoding="utf-8") findings.extend(_require_tokens(relative, text, WRITER_REQUIRED)) findings.extend( _finding("FORBIDDEN_DIRECT_WRITE_CONTRACT", relative, token) for token in WRITER_FORBIDDEN if token in text ) for relative in SEMANTIC_WORKFLOW_SOURCES: path = root / relative if not path.is_file(): findings.append(_finding("MISSING_CONNECTION_SOURCE", relative, "")) continue findings.extend(_require_tokens(relative, path.read_text(encoding="utf-8"), SEMANTIC_REQUIRED)) parent_path = root / PARENT_CERTIFICATE_SOURCE if not parent_path.is_file(): findings.append(_finding("MISSING_CONNECTION_SOURCE", PARENT_CERTIFICATE_SOURCE, "")) else: findings.extend(_require_tokens(PARENT_CERTIFICATE_SOURCE, parent_path.read_text(encoding="utf-8"), PARENT_CERTIFICATE_REQUIRED)) reporters = _report_sources(root) for relative in reporters: path = root / relative if not path.is_file(): findings.append(_finding("MISSING_CONNECTION_SOURCE", relative, "")) continue findings.extend(_require_tokens(relative, path.read_text(encoding="utf-8"), REPORT_REQUIRED)) findings.sort(key=lambda item: (item["path"], item["code"], item["token"])) return { "schema_version": RESULT_SCHEMA, "status": "PASS" if not findings else "FAIL", "writer_sources": len(WRITER_SOURCES), "semantic_workflow_sources": len(SEMANTIC_WORKFLOW_SOURCES) + 1, "report_sources": len(reporters), "findings": findings, } def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--root", type=Path, default=DEFAULT_ROOT) args = parser.parse_args(argv) try: result = check(args.root) exit_code = 0 if result["status"] == "PASS" else 1 except (ConnectionCheckError, OSError, UnicodeError, ValueError) as exc: result = { "schema_version": RESULT_SCHEMA, "status": "ERROR", "errors": [{"code": "WORKFLOW_CONNECTION_ERROR", "message": str(exc)}], } exit_code = 2 json.dump(result, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True) sys.stdout.write("\n") return exit_code if __name__ == "__main__": raise SystemExit(main())