Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ target/
.settings/
.DS_Store
*.log
__pycache__/
*.pyc
1 change: 1 addition & 0 deletions docs/engineering-log/000-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions docs/engineering-log/012-public-repository-readiness.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
65 changes: 65 additions & 0 deletions docs/engineering-log/017-public-documentation-audit.md
Original file line number Diff line number Diff line change
@@ -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.
98 changes: 98 additions & 0 deletions scripts/check-local-markdown-links.py
Original file line number Diff line number Diff line change
@@ -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"(?<!!)\[[^\]]+\]\(([^)]+)\)")
IMAGE_LINK = re.compile(r"!\[[^\]]*\]\(([^)]+)\)")
SKIPPED_PREFIXES = ("http://", "https://", "mailto:", "#")
PUBLIC_PATHS = (
"README.md",
"CONTRIBUTING.md",
"CODE_OF_CONDUCT.md",
"docs",
"reports",
".github",
)


def iter_markdown_files(root: Path):
for public_path in PUBLIC_PATHS:
path = root / public_path
if path.is_file():
yield path
elif path.exists():
yield from sorted(path.rglob("*.md"))


def iter_links(markdown_file: Path):
in_fence = False
for line_number, line in enumerate(
markdown_file.read_text(encoding="utf-8").splitlines(), start=1
):
if line.strip().startswith("```"):
in_fence = not in_fence
continue
if in_fence:
continue
for regex in (INLINE_LINK, IMAGE_LINK):
for match in regex.finditer(line):
yield line_number, match.group(1).strip()


def normalize_target(target: str) -> 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())