#!/usr/bin/env python3 """Rust-independent documentation/Reader consistency checks for the 0.26.4 release.""" from pathlib import Path import re from rust_source import rust_source ROOT = Path(__file__).resolve().parents[1] DOCS = ROOT / "docs" required = [ ROOT / "README.md", ROOT / "ROADMAP.md", ROOT / "CHANGELOG.md", DOCS / "README.md", DOCS / "WEB_SERVER.md", DOCS / "TODO.md", DOCS / "V0.25.5_AUDIT.md", DOCS / "V0.25.4_AUDIT.md", DOCS / "V0.25.3_AUDIT.md", DOCS / "V0.25.2_AUDIT.md", DOCS / "V0.25.1_AUDIT.md", DOCS / "V0.25.0_AUDIT.md", DOCS / "TEST_REPORT.md", DOCS / "CHANGELOG_TECHNICAL_ARCHIVE.md", DOCS / "ROADMAP_HISTORY.md", ] for path in required: assert path.is_file(), f"missing required documentation: {path.relative_to(ROOT)}" index = (DOCS / "README.md").read_text(encoding="utf-8") for marker in ["Functional documentation", "Development and testing", "Technical documentation", "Historical or version-labelled context", "TODO.md", "V0.25.5_AUDIT.md", "V0.25.4_AUDIT.md", "V0.25.3_AUDIT.md", "V0.25.2_AUDIT.md", "V0.25.1_AUDIT.md", "V0.25.0_AUDIT.md", "CHANGELOG_TECHNICAL_ARCHIVE.md", "ROADMAP_HISTORY.md", "/docs"]: assert marker in index, marker for document in sorted(DOCS.glob("*.md")): if document.name == "README.md" or (document.name.startswith("V") and document.name.endswith("_AUDIT.md")): continue assert document.name in index, f"documentation index does not classify {document.name}" reader_html = (ROOT / "src/admin/web/docs.html").read_text(encoding="utf-8") reader_js = (ROOT / "src/admin/web/docs.js").read_text(encoding="utf-8") build = (ROOT / "build.rs").read_text(encoding="utf-8") admin = rust_source(ROOT, "src/admin/mod.rs") for marker in ["docs-tab-reader", "docs-reader-list", "docs-reader-content", "docs-tab-api"]: assert marker in reader_html, marker for marker in ["renderMarkdown", "selectDocument", 'get("/docs/content.json")', "docsByPath", "docsCategoryHistorical"]: assert marker in reader_js, marker documentation_rs = rust_source(ROOT, "src/admin/documentation.rs") + (ROOT / "src/admin/documentation/documents.rs").read_text(encoding="utf-8") assert "READER_DOCUMENTS" in documentation_rs and "reader_bundle" in documentation_rs assert 'include_str!(concat!(env!("CARGO_MANIFEST_DIR")' in documentation_rs assert 'docs-content.json' not in documentation_rs and 'documentation_bundle' not in build for document in sorted(DOCS.glob("*.md")): marker = f'/{document.relative_to(ROOT).as_posix()}"' assert marker in documentation_rs, f"Reader does not embed {document.relative_to(ROOT)}" assert '"/docs/content.json"' in admin readme = (ROOT / "README.md").read_text(encoding="utf-8") roadmap = (ROOT / "ROADMAP.md").read_text(encoding="utf-8") changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8") assert readme.startswith("# RustProxy 0.26.4") assert "docs/WEB_SERVER.md" in readme and "docs/README.md" in readme assert readme.count("## What changed in ") == 1, "README duplicates historical release notes; use CHANGELOG/archive" assert "## Release history" in readme and "docs/ROADMAP_HISTORY.md" in readme assert roadmap.startswith("# RustProxy roadmap") and "## 0.26.4" in roadmap and "## 0.26.0" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap assert "## 0.24." not in roadmap and "## Web Server follow-up" in roadmap and "docs/ROADMAP_HISTORY.md" in roadmap assert changelog.startswith("# Changelog\n") for release in ["0.26.4", "0.26.1", "0.26.0", "0.25.6", "0.25.5", "0.25.4", "0.25.3"]: assert f"## {release}" in changelog, release assert changelog.index("## 0.26.4") < changelog.index("## 0.26.1") < changelog.index("## 0.26.0") < changelog.index("## 0.25.6") < changelog.index("## 0.25.5") assert "CHANGELOG_TECHNICAL_ARCHIVE.md" in changelog for developer_only in ["Clean the remaining compiler warnings", "Update package/source/UI/OpenAPI/release identity", "source regressions and update release identity"]: assert developer_only not in changelog, f"developer-only CHANGELOG detail: {developer_only}" link_re = re.compile(r"\[[^\]]+\]\(([^)]+)\)") paths = [ROOT / "README.md", ROOT / "ROADMAP.md", ROOT / "CHANGELOG.md", *sorted(DOCS.glob("*.md"))] for source in paths: text = source.read_text(encoding="utf-8") for raw in link_re.findall(text): target = raw.strip().split()[0].strip("<>") if not target or target.startswith(("http://", "https://", "mailto:", "#", "/")): continue target = target.split("#", 1)[0].split("?", 1)[0] if not target: continue resolved = (source.parent / target).resolve() assert resolved.exists(), f"broken documentation link: {source.relative_to(ROOT)} -> {target}" print("PASS: documentation index, Reader/API split, release docs and local Markdown links are consistent.")