From 8f9f5edf1c96e575ca7082f64e6dba351f0b543f Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 22 Sep 2026 21:34:52 +0100 Subject: [PATCH] fix(linguist-check): exclude test corpora from the Python ban The gate asked "does this repo contain .py" when the doctrine it enforces means "is this repo written in Python". Those are different questions, and the difference fails exactly the repos that are doing their job properly: a static analyser, linter or parser needs Python source as test input, and that input is data, not implementation. pons-asinorum is the concrete case. Every one of its 18 .py files sits under fixtures/ as the positive/negative corpus for the Python analyser its own ADR-0002 mandates. The gate redded it for shipping the test data its design requires. Test-corpus directories are now excluded by name (fixtures, corpus, corpora, testdata, test-data, test-corpus, samples, vendor, node_modules). Anything outside them is still implementation and is still banned. The gate now also names the offending files instead of only asserting that some exist. Verified by mutant, not by inspection: - pons as-is -> rc=0, "18 Python file(s) ... allowed" - .py planted at repo root -> rc=1, names ./scratch_impl.py - .py planted in crates/ -> rc=1, names ./crates/.../helper.py Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WRvDivYwLSeVCJUrfjic3f --- actions/linguist-check/action.yml | 39 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/actions/linguist-check/action.yml b/actions/linguist-check/action.yml index 386783e..4c45306 100755 --- a/actions/linguist-check/action.yml +++ b/actions/linguist-check/action.yml @@ -7,19 +7,40 @@ runs: shell: bash run: | echo "Validating Linguist configuration and Banned Languages..." - - # Banned languages list based on user preference - BANNED_LANGS=("python" "ruby" "perl") - - # Detect extensions - if find . -name "*.py" -not -path "*/\.*" | grep -q .; then - echo "::error::Banned language detected: Python (.py files found). Use Rust, Julia, or bash/just instead." + + # The doctrine bans writing estate code in Python. It does not ban a + # repository from CONTAINING Python: a static analyser, a linter or a + # parser needs Python source as test input, and that input is data, not + # implementation. Asking "does this repo contain .py" instead of "is + # this repo written in Python" fails exactly those repos hardest for + # doing their job properly. + # + # So test corpora are excluded by directory. Anything OUTSIDE these + # directories is still implementation and is still banned. + EXCLUDED_DIRS=(fixtures corpus corpora testdata test-data test-corpus samples vendor node_modules) + + PRUNE=() + for d in "${EXCLUDED_DIRS[@]}"; do + PRUNE+=(-path "*/$d/*" -o -path "./$d/*" -o) + done + + OFFENDERS=$(find . \( "${PRUNE[@]}" -path "*/.*" \) -prune -o -name "*.py" -print 2>/dev/null) + + if [ -n "$OFFENDERS" ]; then + echo "::error::Banned language detected: Python implementation source found. Use Rust, Julia, or bash/just instead." + echo "Offending files (test corpora under ${EXCLUDED_DIRS[*]} are exempt):" + echo "$OFFENDERS" | sed 's/^/ /' exit 1 fi - + + EXEMPT_COUNT=$(find . -name "*.py" -not -path "*/.*" 2>/dev/null | wc -l) + if [ "$EXEMPT_COUNT" -gt 0 ]; then + echo "$EXEMPT_COUNT Python file(s) present, all inside excluded test-corpus directories — allowed." + fi + # Ensure .gitattributes defines linguist overrides if needed if [ ! -f ".gitattributes" ] || ! grep -q "linguist" ".gitattributes"; then echo "::warning::.gitattributes is missing or does not contain linguist configuration. The git linguist list should be up to date." fi - + echo "Linguist & Banned Languages validation complete."