Files
llm-wiki/harness/runtime/workflow_connection_check.py
T

158 lines
5.2 KiB
Python

#!/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/<project>.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())