Skip to content

Commit 0c20c92

Browse files
hyperpolymathclaude
andcommitted
feat(readme): pin toolchain + normalise freshness for reproducible derivation
Make derivation reproducible so the freshness check is trustworthy: - Install step pins pandoc 3.10 + asciidoctor 2.0.26 + asciidoctor-reducer 1.1.1 (was: floating apt/gem latest). The committed README.md must be generated by the same versions CI runs, or cosmetic toolchain drift would be misreported as staleness. Bump deliberately + regenerate; never float. - Freshness check normalises (strip banner, trim trailing WS, squeeze blank runs) before diffing — belt-and-braces so a harmless whitespace nudge is not flagged, while real prose/structure/anchor changes still show. Verified against boj-server's real README end-to-end: normalised body byte-identical on re-derive, vocab 98.7%, anchor guard satisfied. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5231501 commit 0c20c92

1 file changed

Lines changed: 26 additions & 7 deletions

File tree

.github/workflows/readme-derive-reusable.yml

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,22 @@ jobs:
110110
111111
- name: Install toolchain
112112
if: steps.decl.outputs.derive == 'true'
113+
env:
114+
# Pinned so derivation is REPRODUCIBLE: the same versions used to
115+
# generate the committed README.md must run in CI, or the freshness
116+
# check would flag cosmetic toolchain-drift diffs as staleness. Bump
117+
# deliberately (and regenerate every derived README) — never float.
118+
PANDOC_VERSION: "3.10"
119+
ASCIIDOCTOR_VERSION: "2.0.26"
120+
ASCIIDOCTOR_REDUCER_VERSION: "1.1.1"
113121
run: |
114-
sudo apt-get update -qq
115-
sudo apt-get install -y -qq pandoc
116-
# asciidoctor + include-reducer from rubygems (ubuntu ships ruby)
117-
sudo gem install --no-document asciidoctor asciidoctor-reducer
122+
set -euo pipefail
123+
curl -fsSL -o /tmp/pandoc.deb \
124+
"https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-1-amd64.deb"
125+
sudo dpkg -i /tmp/pandoc.deb
126+
sudo gem install --no-document \
127+
asciidoctor -v "$ASCIIDOCTOR_VERSION" \
128+
asciidoctor-reducer -v "$ASCIIDOCTOR_REDUCER_VERSION"
118129
pandoc --version | head -1
119130
asciidoctor --version | head -1
120131
@@ -190,13 +201,21 @@ jobs:
190201
CANONICAL: ${{ steps.decl.outputs.canonical }}
191202
run: |
192203
set -euo pipefail
204+
# Normalise before comparing: drop the banner comment lines, trim
205+
# trailing whitespace, and squeeze blank-line runs. The toolchain is
206+
# version-pinned so output is reproducible; this normalisation is a
207+
# belt-and-braces layer that keeps a harmless whitespace nudge from
208+
# being reported as staleness, while any real prose/structure/anchor
209+
# change still shows.
210+
norm() { grep -vE '^<!-- (SPDX-License-Identifier|GENERATED)' "$1" \
211+
| sed 's/[[:space:]]*$//' | cat -s; }
193212
if [ ! -f "$DERIVED_PATH" ]; then
194213
echo "::error::Declared derived README '$DERIVED_PATH' is missing. Regenerate and commit it."
195214
SHOW_CMD=1
196-
elif ! diff -q "$RUNNER_TEMP/derived.md" "$DERIVED_PATH" >/dev/null; then
215+
elif ! diff -q <(norm "$RUNNER_TEMP/derived.md") <(norm "$DERIVED_PATH") >/dev/null; then
197216
echo "::error::'$DERIVED_PATH' is STALE relative to '$CANONICAL'. Regenerate and commit it."
198-
echo "----- diff (committed vs regenerated) -----"
199-
diff "$DERIVED_PATH" "$RUNNER_TEMP/derived.md" || true
217+
echo "----- diff (committed vs regenerated, normalised) -----"
218+
diff <(norm "$DERIVED_PATH") <(norm "$RUNNER_TEMP/derived.md") || true
200219
SHOW_CMD=1
201220
else
202221
echo "✓ $DERIVED_PATH is up to date with $CANONICAL"

0 commit comments

Comments
 (0)