Files
ConformalLabpp/scripts/quality/check-doc-freshness.sh
Tarik Moussa 569a03dc08
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
docs+tooling: doc-freshness gate, documentation-pass policy, token-hygiene
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>
2026-05-28 06:15:14 +02:00

101 lines
3.8 KiB
Bash
Executable File

#!/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