From 6b5b0fa485d4f1e1fa301239cc663accb424856d Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:23:55 +0100 Subject: [PATCH 1/3] fix(ci): the invisible-character gate never matched anything MEASURED 2026-08-27: this gate's pattern caught 0 OF 6 invisible-character test cases. It has never detected an NBSP, zero-width space, BOM, soft hyphen, bidi override or word joiner. ROOT CAUSE: the pattern used UTF-8 BYTE sequences (\xc2\xa0) while grep -P matches CHARACTERS. Bytes c2 a0 are ONE character U+00A0; \xc2\xa0 asks for TWO characters, U+00C2 then U+00A0, which is never present. grep -P '\xc2\xa0' -> miss grep -P '\x{a0}' -> MATCH Only \x00 worked, being single-byte in both readings. FIXED: codepoint escapes; C0 control characters \x01-\x08,\x0B,\x0C,\x0E-\x1F added (TAB/LF/CR excluded); and grep -a, without which grep skips any NUL-bearing file as binary. The C0 range matters: a stray BACKSPACE byte made a workflow unparseable in developer-ecosystem, so it never ran, and this linter called it clean. Canonical fix: hyperpolymath/empty-linter#70. 1 file(s) here. VERIFIED: YAML re-parsed, and the corrected pattern was confirmed to catch a real NBSP before the change was kept. --- .github/workflows/dogfood-gate.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 3eb7a2b..de97464 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -115,7 +115,7 @@ jobs: shell: bash run: | set -euo pipefail - patterns='\xc2\xa0|\xe2\x80\x8b|\xe2\x80\x8c|\xe2\x80\x8d|\xef\xbb\xbf|\xc2\xad|\xe2\x80\x8e|\xe2\x80\x8f|\xe2\x80\xaa|\xe2\x80\xab|\xe2\x80\xac|\xe2\x80\xad|\xe2\x80\xae|\x00' + patterns='\x00|[\x01-\x08\x0B\x0C\x0E-\x1F]|\x{a0}|\x{ad}|\x{200b}|\x{200c}|\x{200d}|\x{200e}|\x{200f}|\x{202a}|\x{202b}|\x{202c}|\x{202d}|\x{202e}|\x{2060}|\x{feff}' results_file="${RUNNER_TEMP}/empty-lint-results.txt" find "$GITHUB_WORKSPACE" \ -not -path '*/.git/*' -not -path '*/node_modules/*' \ @@ -127,7 +127,7 @@ jobs: -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' -o -name '*.adoc' \ -o -name '*.idr' -o -name '*.zig' -o -name '*.v' -o -name '*.jl' \ -o -name '*.gleam' -o -name '*.hs' -o -name '*.ml' -o -name '*.sh' \) \ - -exec grep -Prl "$patterns" {} \; > "$results_file" 2>/dev/null || true + -exec grep -aPrl "$patterns" {} \; > "$results_file" 2>/dev/null || true findings=$(wc -l < "$results_file") echo "findings=$findings" >> "$GITHUB_OUTPUT" while IFS= read -r filepath; do From ae7cd391720afe81da507df57eef20e30a2aaf1a Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 28 Aug 2026 01:26:47 +0100 Subject: [PATCH 2/3] fix(ci): enforce C0/NUL corruption; warn on invisible Unicode Third layer of the empty-linter fix, scoped by an owner ruling after a census. DETECTION (layers 1-2, earlier commits) sees everything the pattern covers. ENFORCEMENT (this commit) distinguishes two classes: BLOCKING C0 control characters and NUL. Never legitimate; proven damage - a backspace byte made a workflow unloadable (it never ran once), and LaTeX maths in wiki files was silently mangled where a generation step turned backslash-b commands into backspaces. ADVISORY NBSP, BOM, zero-width marks. A gate-lens census found ~2,100 first-party files carry these as legitimate typography in prose; blocking would fail 2,333 files estate-wide for no safety gain. Also checks the lint STEP OUTCOME: if the step crashes, its counts arrive empty, and a count-only check would silently pass (review finding). The blocking count re-greps only the files the full pattern already flagged, so the find expression is not duplicated and cannot drift. 1 file(s). YAML re-parsed per edit; reverted on any mis-apply. --- .github/workflows/dogfood-gate.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index de97464..00d4196 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -130,6 +130,15 @@ jobs: -exec grep -aPrl "$patterns" {} \; > "$results_file" 2>/dev/null || true findings=$(wc -l < "$results_file") echo "findings=$findings" >> "$GITHUB_OUTPUT" + # Blocking subset: C0 controls and NUL only (owner ruling 2026-08-28). + # Invisible Unicode (NBSP/BOM/zero-width) stays ADVISORY - about 2,100 + # estate files carry it as legitimate typography in prose. + blocking=0 + while IFS= read -r bf; do + [ -z "$bf" ] && continue + grep -qaP '\x00|[\x01-\x08\x0B\x0C\x0E-\x1F]' "$bf" && blocking=$((blocking+1)) + done < "$results_file" + echo "blocking=$blocking" >> "$GITHUB_OUTPUT" while IFS= read -r filepath; do [ -z "$filepath" ] && continue relative_path="${filepath#"$GITHUB_WORKSPACE"/}" @@ -245,6 +254,9 @@ jobs: if: always() shell: bash env: + EMPTY_LINT_FINDINGS: ${{ steps.empty_lint.outputs.findings }} + EMPTY_LINT_BLOCKING: ${{ steps.empty_lint.outputs.blocking }} + EMPTY_LINT_OUTCOME: ${{ steps.empty_lint.outcome }} A2ML_OUTCOME: ${{ steps.a2ml.outcome }} K9_OUTCOME: ${{ steps.k9.outcome }} ECLEX_OUTCOME: ${{ steps.eclexiaiser.outcome }} @@ -256,6 +268,21 @@ jobs: if [ "$result" = failure ]; then failed=1; fi done if [ "$GROOVE_VALID" = false ]; then failed=1; fi + # empty-linter: C0/NUL corruption FAILS the build; invisible Unicode + # (NBSP/BOM/zero-width) only WARNS - owner ruling 2026-08-28 after a + # census showed ~2,100 estate files carry the latter as typography. + # The outcome check matters as much as the counts: if the lint step + # crashes, both counts arrive empty and a count-only check passes. + if [ "${EMPTY_LINT_OUTCOME:-}" = "failure" ]; then + echo "::error::empty-linter step itself failed - treating as gate failure" + failed=1 + fi + if [ "${EMPTY_LINT_BLOCKING:-0}" -gt 0 ]; then + echo "::error::empty-linter: ${EMPTY_LINT_BLOCKING} file(s) contain C0 control characters or NUL - genuine corruption" + failed=1 + elif [ "${EMPTY_LINT_FINDINGS:-0}" -gt 0 ]; then + echo "::warning::empty-linter: ${EMPTY_LINT_FINDINGS} file(s) contain invisible Unicode (advisory, non-blocking)" + fi if [ "$failed" -ne 0 ]; then echo '::error::One or more dogfood validators failed; see the consolidated scorecard' exit 1 From 40d3e73be051ae4b4efa51b074516bda29076a37 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:35:52 +0100 Subject: [PATCH 3/3] fix(ci): make invisible-character PCRE locale-independent --- .github/workflows/dogfood-gate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 00d4196..41ca94f 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -115,7 +115,7 @@ jobs: shell: bash run: | set -euo pipefail - patterns='\x00|[\x01-\x08\x0B\x0C\x0E-\x1F]|\x{a0}|\x{ad}|\x{200b}|\x{200c}|\x{200d}|\x{200e}|\x{200f}|\x{202a}|\x{202b}|\x{202c}|\x{202d}|\x{202e}|\x{2060}|\x{feff}' + patterns='(*UTF)[\x00-\x08\x0B\x0C\x0E-\x1F\x{a0}\x{ad}\x{200b}-\x{200f}\x{202a}-\x{202f}\x{2060}\x{2066}-\x{2069}\x{feff}]' results_file="${RUNNER_TEMP}/empty-lint-results.txt" find "$GITHUB_WORKSPACE" \ -not -path '*/.git/*' -not -path '*/node_modules/*' \