#!/usr/bin/env python3 """Validate the lightweight DCL7 document status baseline. DCL7 removed the old full feature matrix from the current docs tree. Historical details remain recoverable from git history and issue CSVs. This check now guards the current lightweight status docs and the latest issue CSV contract shape instead of requiring a large duplicated feature table. """ from __future__ import annotations import csv import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent MATRIX_PATH = ROOT / "docs" / "历史功能状态矩阵.md" STATE_MATRIX_PATH = ROOT / "docs" / "文档事实源状态矩阵.md" INDEX_PATH = ROOT / "docs" / "文档索引.md" ISSUES_DIR = ROOT / "issues" REQUIRED_COLUMNS = { "ID", "Title", "Description", "Acceptance", "Test_Method", "Tools", "Dev_Status", "Review1_Status", "Regression_Status", "Files", "Dependencies", "Notes", } def read_text(path: Path) -> str: return path.read_text(encoding="utf-8") def validate_latest_issue_csv() -> list[str]: errors: list[str] = [] csv_files = sorted(ISSUES_DIR.glob("*.csv")) if not csv_files: return ["No issue CSV files found"] latest = csv_files[-1] with latest.open(encoding="utf-8", newline="") as fp: reader = csv.DictReader(fp) columns = set(reader.fieldnames or []) missing = sorted(REQUIRED_COLUMNS - columns) if missing: errors.append(f"{latest.name} missing columns: {missing}") rows = list(reader) if not rows: errors.append(f"{latest.name} has no issue rows") for row in rows: for key in ("Dev_Status", "Review1_Status", "Regression_Status"): value = (row.get(key) or "").strip() if value not in {"TODO", "DOING", "DONE"}: errors.append(f"{latest.name}:{row.get('ID')} invalid {key}={value!r}") return errors def main() -> int: errors: list[str] = [] for path in (MATRIX_PATH, STATE_MATRIX_PATH, INDEX_PATH): if not path.exists(): errors.append(f"Missing required doc: {path.relative_to(ROOT)}") if not errors: matrix = read_text(MATRIX_PATH) state = read_text(STATE_MATRIX_PATH) index = read_text(INDEX_PATH) required_matrix_markers = [ "历史功能状态矩阵", "git show 5da05eb:docs/feature-matrix.md", "MIF7", "ME6-3", ] for marker in required_matrix_markers: if marker not in matrix: errors.append(f"{MATRIX_PATH.relative_to(ROOT)} missing marker: {marker}") for marker in ("中文优先", "已从当前树移除", "MIF7", "ME6-3"): if marker not in state and marker not in index: errors.append(f"status/index docs missing marker: {marker}") errors.extend(validate_latest_issue_csv()) if errors: print("[ERR] lightweight document status validation failed") for err in errors: print(f" - {err}") return 1 print("[OK] lightweight document status baseline is valid") return 0 if __name__ == "__main__": sys.exit(main())