diff --git a/.gitignore b/.gitignore index c8de884..8a7cb0c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ target/ .settings/ .DS_Store *.log +__pycache__/ +*.pyc diff --git a/docs/engineering-log/000-index.md b/docs/engineering-log/000-index.md index 5494834..d4aa8cb 100644 --- a/docs/engineering-log/000-index.md +++ b/docs/engineering-log/000-index.md @@ -22,6 +22,7 @@ The goal is not to maintain a generic changelog. Each entry captures technical d - [014 - Java 21 to 25 rule catalog](014-java-21-to-25-rule-catalog.md) - [015 - Java 21 to 25 baseline review rule](015-java-21-to-25-baseline-review-rule.md) - [016 - ThreadLocal scoped values review rule](016-threadlocal-scoped-values-review-rule.md) +- [017 - Public documentation audit](017-public-documentation-audit.md) ## Entry Format diff --git a/docs/engineering-log/012-public-repository-readiness.md b/docs/engineering-log/012-public-repository-readiness.md index f604a1e..05feb55 100644 --- a/docs/engineering-log/012-public-repository-readiness.md +++ b/docs/engineering-log/012-public-repository-readiness.md @@ -15,7 +15,7 @@ The repository was already public, but that is not the same as being ready for e - Rename `docs/bitacora/` to `docs/engineering-log/`. - Rename historical engineering log files to English filenames. - Rewrite historical engineering log entries in English with a technical tone for experienced Java engineers. -- Remove internal planning artifacts from `docs/superpowers/` because they were not edited for public readers. +- Remove internal planning artifacts because they were not edited for public readers. - Add a CI badge to the README. - Update GitHub Actions from `actions/checkout@v4` and `actions/setup-java@v4` to `v5` to avoid the Node.js 20 deprecation warning shown by GitHub Actions. - Create initial GitHub issues for contributors after the documentation cleanup is pushed. @@ -48,7 +48,7 @@ The public documentation surface is now cleaner: I verified this pass with: ```powershell -cmd /c "set JAVA_HOME=C:\Users\jstor\.codex\jdks\temurin-25\jdk-25.0.2+10&& set PATH=C:\Users\jstor\.codex\jdks\temurin-25\jdk-25.0.2+10\bin;%PATH%&& mvn test" +mvn test ``` Result: 30 tests passed. Maven still emits the known JDK 25 `sun.misc.Unsafe` warning from Maven/Guice, but the build succeeds. diff --git a/docs/engineering-log/017-public-documentation-audit.md b/docs/engineering-log/017-public-documentation-audit.md new file mode 100644 index 0000000..3fce951 --- /dev/null +++ b/docs/engineering-log/017-public-documentation-audit.md @@ -0,0 +1,65 @@ +# 017 - Public Documentation Audit + +## Date + +2026-04-23 + +## Goal + +Audit the public documentation surface before promoting the repository to external readers. + +The audit focused on README navigation, contribution guidance, issue templates, engineering log entries, sample reports, and local Markdown links. + +## Decisions + +- Keep the public documentation in English and aimed at experienced Java migration readers. +- Keep the renamed engineering log path as the only public documentation history. +- Normalize verification examples so they do not expose workstation-specific paths. +- Treat local Markdown links as a release-readiness gate. + +## Rejected Options + +- Do not rewrite historical decisions wholesale. The engineering log should preserve intent and trade-offs, but remove private or machine-specific details. +- Do not add marketing copy to the README. The current positioning is technical and evidence-first, which matches the repository audience. +- Do not introduce a separate documentation checker yet. A small repository can use explicit audit commands until link checking becomes a recurring CI concern. + +## Rationale + +Public documentation is part of the product surface. Senior engineers evaluating a migration tool will look for coherent navigation, reproducible examples, scoped contribution paths, and evidence that reports are generated from real analyzer behavior. + +The repository already had the right documentation structure after the engineering log rename. The remaining risk was small but important: public files should not leak local workstation paths or private planning context, and local links should resolve from a fresh checkout. + +## Concrete Result + +The audit confirmed that: + +- README sample report links resolve locally; +- contribution and documentation style guide links resolve locally; +- engineering log index links resolve locally; +- issue templates are concise and contribution-facing; +- sample reports do not contain local workstation paths; +- the remaining workstation-specific verification command was replaced with a portable Maven command. + +## Verification + +Local Markdown link audit: + +```powershell +python scripts/check-local-markdown-links.py +``` + +Result: all local Markdown links in README, contribution docs, code of conduct, docs, reports, and issue templates resolved. + +Public documentation scan: + +Manual ripgrep checks covered workstation-specific paths and private planning references. + +Result: no remaining workstation-specific paths or private planning references in public documentation. + +## Content Angle + +This is a useful public-release lesson: documentation readiness is not only translation or link hygiene. It also means removing private execution context and making the repository understandable from a clean checkout. + +## Next Step + +Use the remaining research issues to decide the next analyzer capability: Gradle version catalog inspection or an AST-backed source scanning design. diff --git a/scripts/check-local-markdown-links.py b/scripts/check-local-markdown-links.py new file mode 100644 index 0000000..1279693 --- /dev/null +++ b/scripts/check-local-markdown-links.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +"""Check local Markdown links in public repository documentation.""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path +from urllib.parse import unquote + + +INLINE_LINK = re.compile(r"(? str: + if target.startswith("<") and target.endswith(">"): + target = target[1:-1] + return unquote(target.split()[0].split("#", 1)[0]) + + +def main() -> int: + root = Path.cwd().resolve() + problems: list[str] = [] + checked = 0 + + for markdown_file in iter_markdown_files(root): + for line_number, raw_target in iter_links(markdown_file): + if not raw_target or raw_target.startswith(SKIPPED_PREFIXES): + continue + + target = normalize_target(raw_target) + if not target: + continue + + checked += 1 + resolved = (markdown_file.parent / target).resolve() + + try: + resolved.relative_to(root) + except ValueError: + problems.append( + f"{markdown_file.relative_to(root)}:{line_number}: " + f"{raw_target} escapes repository" + ) + continue + + if not resolved.exists(): + problems.append( + f"{markdown_file.relative_to(root)}:{line_number}: " + f"{raw_target} does not exist" + ) + + if problems: + print("Broken local Markdown links:") + for problem in problems: + print(f"- {problem}") + return 1 + + print(f"Checked {checked} local Markdown links.") + return 0 + + +if __name__ == "__main__": + sys.exit(main())