59 lines
1.6 KiB
Python
Executable File
59 lines
1.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Check S91 CTO SOT dotpath migration state."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
REQUIRED_FILES = [
|
|
".sot/00-START/CTO-WORKSPACE-INTENT.md",
|
|
".sot/03-PROTOCOLS/CTO-CASE-BACKEND-BRIEF.md",
|
|
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-RECORD.md",
|
|
]
|
|
SCAN_FILES = [
|
|
"AGENTS.md",
|
|
"README.md",
|
|
"WORKBOARD.yaml",
|
|
"tools/validate_cto_child.py",
|
|
]
|
|
|
|
|
|
def fail(message: str) -> None:
|
|
raise SystemExit(f"S91 cto dotpath check failed: {message}")
|
|
|
|
|
|
def main() -> int:
|
|
if not (ROOT / ".sot").is_dir():
|
|
fail("missing canonical .sot directory")
|
|
legacy = ROOT / "sot"
|
|
if not legacy.is_symlink():
|
|
fail("legacy sot path must be a temporary symlink")
|
|
if os.readlink(legacy) != ".sot":
|
|
fail("legacy sot symlink must target .sot")
|
|
|
|
for relative in REQUIRED_FILES:
|
|
if not (ROOT / relative).is_file():
|
|
fail(f"missing required canonical file: {relative}")
|
|
|
|
for relative in SCAN_FILES:
|
|
text = (ROOT / relative).read_text(encoding="utf-8")
|
|
if re.search(r"(?<!\.)sot/", text):
|
|
fail(f"legacy sot reference remains in {relative}")
|
|
if ".sot/" not in text:
|
|
fail(f"missing canonical .sot reference in {relative}")
|
|
|
|
for path in (ROOT / ".sot").rglob("*.md"):
|
|
text = path.read_text(encoding="utf-8")
|
|
if re.search(r"source:\s+sot/", text):
|
|
fail(f"legacy source frontmatter remains in {path.relative_to(ROOT)}")
|
|
|
|
print("S91 cto dotpath check passed")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|