Files
yao-meta-skill/scripts/render_world_class_claim_guard.py
T
2026-06-14 01:03:21 +08:00

237 lines
9.0 KiB
Python

#!/usr/bin/env python3
import argparse
import json
import re
from datetime import date
from pathlib import Path
from typing import Any
from render_world_class_evidence_ledger import build_ledger
ROOT = Path(__file__).resolve().parent.parent
SCRIPT_INTERFACE = "cli"
SCRIPT_INTERFACE_REASON = "Scans public claim surfaces so world-class completion is not claimed before accepted evidence exists."
FORBIDDEN_WHEN_PENDING = [
{
"key": "ready-to-claim-true",
"pattern": re.compile(r"ready[\s_-]*to[\s_-]*claim[\s_-]*world[\s_-]*class\s*[:=]\s*`?true`?", re.IGNORECASE),
"reason": "ready_to_claim_world_class cannot be true while ledger evidence is pending.",
},
{
"key": "world-class-ready-true",
"pattern": re.compile(r"(public\s+)?world[\s_-]*class[\s_-]*ready\s*[:=]\s*`?true`?", re.IGNORECASE),
"reason": "world-class readiness cannot be claimed before accepted external and human evidence exists.",
},
{
"key": "json-world-class-ready-true",
"pattern": re.compile(r'"(?:ready_to_claim_world_class|world_class_ready|public_world_class_ready)"\s*:\s*true', re.IGNORECASE),
"reason": "machine-readable claim fields must remain false until the ledger is ready.",
},
{
"key": "completion-phrase",
"pattern": re.compile(r"(public\s+)?world[\s_-]*class\s+(?:complete|completed|achieved|certified)", re.IGNORECASE),
"reason": "completion language is blocked until the world-class ledger is accepted.",
},
{
"key": "zh-completion-phrase",
"pattern": re.compile(r"世界级(?:已完成|完成|已达成|达成|准备就绪|可声明|认证通过)"),
"reason": "中文完成态表述必须等到 ledger ready 后才能出现。",
},
]
def load_json(path: Path) -> dict[str, Any]:
if not path.exists():
return {}
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return {}
return payload if isinstance(payload, dict) else {}
def rel_path(path: Path, root: Path) -> str:
try:
return str(path.resolve().relative_to(root.resolve()))
except ValueError:
return str(path.resolve())
def resolve_claim_surface(raw_path: str, skill_dir: Path) -> Path:
path = Path(raw_path)
if not path.is_absolute():
path = skill_dir / path
return path.resolve()
def default_claim_surfaces(skill_dir: Path) -> list[Path]:
paths: list[Path] = []
for rel in ["README.md", "SKILL.md"]:
path = skill_dir / rel
if path.exists():
paths.append(path)
for directory, patterns in [
(skill_dir / "docs", ["*.md"]),
(skill_dir / "reports", ["*.md", "*.html"]),
]:
if not directory.exists():
continue
for pattern in patterns:
paths.extend(
path
for path in directory.rglob(pattern)
if path.is_file()
and "release_snapshots" not in path.parts
and path.name not in {"world_class_claim_guard.md", "world_class_claim_guard.html"}
)
return sorted(set(paths), key=lambda item: rel_path(item, skill_dir))
def line_matches(path: Path, ledger_ready: bool) -> list[dict[str, Any]]:
if ledger_ready:
return []
violations: list[dict[str, Any]] = []
try:
lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
except OSError:
return violations
for lineno, line in enumerate(lines, start=1):
for rule in FORBIDDEN_WHEN_PENDING:
if rule["pattern"].search(line):
violations.append(
{
"line": lineno,
"rule": rule["key"],
"reason": rule["reason"],
"excerpt": line.strip()[:240],
}
)
return violations
def escape_markdown_table_cell(value: Any) -> str:
return str(value).replace("|", "\\|")
def build_guard(skill_dir: Path, generated_at: str, claim_surfaces: list[Path] | None = None) -> dict[str, Any]:
ledger = build_ledger(skill_dir, generated_at)
ledger_ready = ledger.get("summary", {}).get("ready_to_claim_world_class") is True
surfaces = claim_surfaces or default_claim_surfaces(skill_dir)
scanned = []
violations = []
for path in surfaces:
matches = line_matches(path, ledger_ready)
rel = rel_path(path, skill_dir)
scanned.append({"path": rel, "violation_count": len(matches)})
for match in matches:
violations.append({"path": rel, **match})
ok = len(violations) == 0
return {
"schema_version": "1.0",
"ok": ok,
"generated_at": generated_at,
"skill_dir": rel_path(skill_dir, ROOT),
"summary": {
"ledger_ready_to_claim_world_class": ledger_ready,
"ledger_pending_count": ledger.get("summary", {}).get("pending_count", 0),
"claim_surface_count": len(scanned),
"violation_count": len(violations),
"overclaim_guard_active": True,
"decision": (
"claim-ready"
if ledger_ready and ok
else ("claim-blocked-overclaim" if violations else "claim-guard-pass-evidence-pending")
),
},
"rules": [
{"key": item["key"], "reason": item["reason"], "pattern": item["pattern"].pattern}
for item in FORBIDDEN_WHEN_PENDING
],
"scanned_surfaces": scanned,
"violations": violations,
"source_ledger": {
"json": "reports/world_class_evidence_ledger.json",
"markdown": "reports/world_class_evidence_ledger.md",
},
"artifacts": {
"json": "reports/world_class_claim_guard.json",
"markdown": "reports/world_class_claim_guard.md",
},
}
def render_markdown(report: dict[str, Any]) -> str:
summary = report["summary"]
lines = [
"# World-Class Claim Guard",
"",
f"Generated at: `{report['generated_at']}`",
"",
"## Summary",
"",
f"- decision: `{summary['decision']}`",
f"- ledger ready to claim world-class: `{str(summary['ledger_ready_to_claim_world_class']).lower()}`",
f"- ledger pending evidence: `{summary['ledger_pending_count']}`",
f"- claim surfaces scanned: `{summary['claim_surface_count']}`",
f"- violations: `{summary['violation_count']}`",
f"- overclaim guard active: `{str(summary['overclaim_guard_active']).lower()}`",
"",
"This guard scans public claim surfaces for completion language that would contradict the world-class evidence ledger. It allows evidence planning and pending-state language, but blocks completion claims until the ledger is ready.",
"",
"## Violations",
"",
"| Path | Line | Rule | Excerpt |",
"| --- | ---: | --- | --- |",
]
if report["violations"]:
for item in report["violations"]:
excerpt = str(item["excerpt"]).replace("|", "\\|")
lines.append(f"| `{item['path']}` | {item['line']} | `{item['rule']}` | {excerpt} |")
else:
lines.append("| `none` | 0 | `none` | none |")
lines.extend(
[
"",
"## Rules",
"",
"| Rule | Reason |",
"| --- | --- |",
]
)
for rule in report["rules"]:
reason = escape_markdown_table_cell(rule["reason"])
lines.append(f"| `{rule['key']}` | {reason} |")
return "\n".join(lines).rstrip() + "\n"
def main() -> None:
parser = argparse.ArgumentParser(description="Guard public world-class completion claims against the evidence ledger.")
parser.add_argument("skill_dir", nargs="?", default=".")
parser.add_argument("--claim-surface", action="append", default=[])
parser.add_argument("--output-json", default="reports/world_class_claim_guard.json")
parser.add_argument("--output-md", default="reports/world_class_claim_guard.md")
parser.add_argument("--generated-at", default=date.today().isoformat())
args = parser.parse_args()
skill_dir = Path(args.skill_dir).resolve()
claim_surfaces = [resolve_claim_surface(item, skill_dir) for item in args.claim_surface] if args.claim_surface else None
report = build_guard(skill_dir, args.generated_at, claim_surfaces)
output_json = Path(args.output_json)
output_md = Path(args.output_md)
if not output_json.is_absolute():
output_json = skill_dir / output_json
if not output_md.is_absolute():
output_md = skill_dir / output_md
output_json.parent.mkdir(parents=True, exist_ok=True)
output_md.parent.mkdir(parents=True, exist_ok=True)
output_json.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
output_md.write_text(render_markdown(report), encoding="utf-8")
print(json.dumps(report, ensure_ascii=False, indent=2))
raise SystemExit(0 if report["ok"] else 2)
if __name__ == "__main__":
main()