docs+tooling: doc-freshness gate, documentation-pass policy, token-hygiene
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m2s
API Docs / doc-build (pull_request) Successful in 1m8s
Markdown link check / check (pull_request) Successful in 52s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 1m59s
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m2s
API Docs / doc-build (pull_request) Successful in 1m8s
Markdown link check / check (pull_request) Successful in 52s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 1m59s
Refresh CLAUDE.md for v0.10.0 (3 CI jobs incl. disabled test-cgal,
compile-time option matrix, reviewer/pages docs, agentic + token-hygiene
workflow patterns) and condense the historical Phase-8/audit logs to
pointers.
Add the documentation-pass process so the single-source-of-truth rules
stay enforced:
* scripts/quality/check-doc-freshness.sh — string-only drift gate
(version/date across CITATION/CHANGELOG/CLAUDE, doc-map count), <1 s,
registered in run-all.sh + quality README.
* doc/release-policy.md — "Documentation passes" subsection (triggers +
docs:sync rule); fix stale Phase-milestone mapping (v0.10.0 was
reviewer-ready, 9c→v0.11.0) and the test-cgal CI mention.
Add shared Claude config (un-ignore the two files only):
* .claude/settings.json — permission allowlist for safe repo commands.
* .claude/token-hygiene.md — Tier-3 cache-discipline user guide that
CLAUDE.md instructs Claude to remind the user about.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ consistency + markdown links + end-to-end smoke via `try_it.sh`).
|
||||
| Script | What it checks | Wall time | Prereqs |
|
||||
|---|---|---|---|
|
||||
| `license-headers.sh` | every C++ source carries `SPDX-License-Identifier: MIT` | ~1 s | `bash` |
|
||||
| `check-doc-freshness.sh` | string-only doc drift: version/date agree across CITATION/CHANGELOG/CLAUDE; doc-map count matches `doc/**/*.md` | <1 s | `bash` |
|
||||
| `cgal-conventions.py` | CGAL-1…6: include-guard format, `\file` brief, namespace nesting, tag-naming, no `using namespace`, no stray `#define` | ~1 s | `python3` |
|
||||
| `clang-format.sh` | every C++ source matches `.clang-format` (dry-run by default; `--fix` to apply) | ~2 s | `clang-format` ≥ 15 |
|
||||
| `cmake-format.sh` | every `CMakeLists.txt` matches `.cmake-format.yaml` + passes `cmake-lint` | ~2 s | `cmake-format` (pip: cmakelang) |
|
||||
|
||||
100
scripts/quality/check-doc-freshness.sh
Executable file
100
scripts/quality/check-doc-freshness.sh
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/quality/check-doc-freshness.sh
|
||||
#
|
||||
# Cheap, string-only documentation-freshness gate. Catches the cross-file
|
||||
# drift that a "documentation pass" (see doc/release-policy.md) is meant to
|
||||
# prevent — without building anything, so it runs in well under a second.
|
||||
#
|
||||
# Invariants checked:
|
||||
# 1. Release version agrees across CITATION.cff, CHANGELOG.md (newest
|
||||
# section) and CLAUDE.md ("Current release:" line).
|
||||
# 2. Release date agrees across CITATION.cff and CHANGELOG.md.
|
||||
# 3. The "N documents across ..." count in CLAUDE.md's Documentation map
|
||||
# equals the actual number of doc/**/*.md files.
|
||||
#
|
||||
# NOT checked here (they need a build — run them as part of the release
|
||||
# documentation pass, see doc/release-policy.md):
|
||||
# * doc/api/tests.md counts → scripts/check-test-counts.sh (needs BUILD_DIR)
|
||||
# * doc/api/headers.md regeneration → scripts/gen-headers-md.py (needs Doxygen XML)
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/quality/check-doc-freshness.sh
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 all string invariants hold
|
||||
# 1 at least one drift found
|
||||
# 2 prerequisite missing (a required file is absent)
|
||||
|
||||
set -uo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT" || exit 2
|
||||
|
||||
for f in CITATION.cff CHANGELOG.md CLAUDE.md; do
|
||||
if [ ! -f "$f" ]; then
|
||||
echo "FAIL: required file not found: $f" >&2
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
|
||||
fail=0
|
||||
note() { printf ' %-4s %s\n' "$1" "$2"; }
|
||||
|
||||
# Strip an optional leading "v" so "v0.10.0" and "0.10.0" compare equal.
|
||||
strip_v() { printf '%s' "${1#v}"; }
|
||||
|
||||
# ── Invariant 1 + 2: version & date triple ──────────────────────────────────
|
||||
cit_ver=$(strip_v "$(grep -E '^version:' CITATION.cff | head -1 | awk '{print $2}')")
|
||||
cit_date=$(grep -E '^date-released:' CITATION.cff | head -1 | awk '{print $2}')
|
||||
|
||||
chg_header=$(grep -m1 -E '^## \[' CHANGELOG.md)
|
||||
chg_ver=$(strip_v "$(printf '%s' "$chg_header" | sed -E 's/^## \[([^]]+)\].*/\1/')")
|
||||
chg_date=$(printf '%s' "$chg_header" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1)
|
||||
|
||||
claude_ver=$(strip_v "$(grep -m1 'Current release:' CLAUDE.md | sed -E 's/.*\*\*(v?[0-9][0-9.]*)\*\*.*/\1/')")
|
||||
|
||||
echo "── version / date consistency ──"
|
||||
note "CIT" "CITATION.cff version=$cit_ver date=$cit_date"
|
||||
note "CHG" "CHANGELOG.md version=$chg_ver date=$chg_date"
|
||||
note "CLD" "CLAUDE.md version=$claude_ver"
|
||||
|
||||
if [ "$cit_ver" = "$chg_ver" ] && [ "$cit_ver" = "$claude_ver" ]; then
|
||||
note "OK" "version agrees ($cit_ver)"
|
||||
else
|
||||
note "DRIFT" "version mismatch: CITATION=$cit_ver CHANGELOG=$chg_ver CLAUDE=$claude_ver"
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$cit_date" = "$chg_date" ]; then
|
||||
note "OK" "date agrees ($cit_date)"
|
||||
else
|
||||
note "DRIFT" "date mismatch: CITATION=$cit_date CHANGELOG=$chg_date"
|
||||
fail=1
|
||||
fi
|
||||
|
||||
# ── Invariant 3: documentation-map count ────────────────────────────────────
|
||||
stated=$(grep -m1 -E '^[0-9]+ documents across' CLAUDE.md | awk '{print $1}')
|
||||
actual=$(find doc -name '*.md' -type f | wc -l | tr -d ' ')
|
||||
|
||||
echo
|
||||
echo "── documentation-map count ──"
|
||||
note "CLD" "CLAUDE.md states: $stated documents"
|
||||
note "DISK" "doc/**/*.md on disk: $actual"
|
||||
if [ "$stated" = "$actual" ]; then
|
||||
note "OK" "doc count agrees ($actual)"
|
||||
else
|
||||
note "DRIFT" "CLAUDE.md says $stated, disk has $actual — update the 'N documents across' line"
|
||||
fail=1
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "FAIL: documentation drift detected."
|
||||
echo "Recovery: run a documentation pass (see doc/release-policy.md →"
|
||||
echo " 'Documentation passes'); fix the lines above, then re-run."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "OK: documentation strings are consistent."
|
||||
echo "Reminder: at release also run scripts/check-test-counts.sh and"
|
||||
echo " scripts/gen-headers-md.py (both need a build)."
|
||||
exit 0
|
||||
@@ -35,6 +35,7 @@ FAST=0
|
||||
|
||||
GATES_FAST=(
|
||||
"License headers | bash scripts/quality/license-headers.sh"
|
||||
"Doc freshness | bash scripts/quality/check-doc-freshness.sh"
|
||||
"CGAL conventions | python3 scripts/quality/cgal-conventions.py"
|
||||
"clang-format drift | bash scripts/quality/clang-format.sh"
|
||||
"cmake-format/-lint | bash scripts/quality/cmake-format.sh"
|
||||
|
||||
Reference in New Issue
Block a user