Skip to content

fix(ci): the invisible-character gate never matched anything - #25

Merged
hyperpolymath merged 5 commits into
mainfrom
fix/empty-linter-pattern-never-matched
Sep 12, 2026
Merged

hyperpolymath merged 5 commits into
mainfrom
fix/empty-linter-pattern-never-matched

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Measured 2026-08-27: this gate 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, U+00C2 then U+00A0 — never present.

grep -P '\xc2\xa0'  ->  miss
grep -P '\x{a0}'    ->  MATCH

Only \x00 worked, being single-byte in both readings. The gate ran, passed, and could not see what it exists to see.

Fixed

  • codepoint escapes in place of byte sequences
  • C0 controls \x01-\x08,\x0B,\x0C,\x0E-\x1F added (TAB/LF/CR excluded)
  • grep -a — without it 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.

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.
@coderabbitai

coderabbitai Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Free

Run ID: 9f343c87-4d3b-4aba-af89-50bf2af0ab8d

📥 Commits

Reviewing files that changed from the base of the PR and between a2510f5 and 9491035.

📒 Files selected for processing (1)
  • .github/workflows/dogfood-gate.yml

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of empty or invisible characters across a wider range of Unicode characters.
    • Scans all files, including those identified as binary, for more consistent results.

Walkthrough

The dogfood gate workflow now detects targeted control and invisible Unicode characters with a PCRE pattern. It also scans binary-marked files as text.

Changes

Invisible character scan

Layer / File(s) Summary
Scan pattern and file handling
.github/workflows/dogfood-gate.yml
The scan uses a PCRE character class for control and invisible Unicode ranges. grep treats binary-marked files as text while retaining recursive matching and result reporting.

Estimated code review effort: 2 (Simple) | ~5 minutes

Poem

A rabbit checks the hidden signs,
Through bytes and files in neat designs.
Control marks hop into the light,
Unicode shadows lose their flight.
Text and binaries now align,
The gate reports each warning sign.


Note

🎁 Summarized by CodeRabbit Free

The PR author is not assigned a seat. If you are a newly provisioned user and your organization has automatic seat assignment enabled, open a new pull request to trigger seat assignment. Otherwise, ask an organization administrator to assign a seat through the team management page at https://app.coderabbit.ai/settings/team-management.

A rabbit reads each line,
The patch grows clear beneath the moon,
Small changes hop in place,
Tests guard the garden path,
Reviews bloom before the dawn.

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

This comment has been minimized.

@hyperpolymath
hyperpolymath enabled auto-merge (squash) August 28, 2026 07:14
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codacy-production codacy-production Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves the invisible character detection gate by utilizing PCRE codepoint escapes and ensuring files with NUL bytes are scanned. While the regex improvements align with the intent, the implementation contains a logic error in how the process exit status is captured, which may result in the CI passing even when violations are found. Additionally, the file traversal logic is inefficient and uses redundant flags. There is currently no evidence of automated tests verifying that the new patterns correctly catch non-breaking spaces, control characters, or byte-order marks.

About this PR

  • The gate's reliability is currently compromised by the way exit codes are handled. If the intention is to fail the build when invisible characters are detected, the logic needs to evaluate the grep results directly or use a find execution mode that propagates grep failures.

Test suggestions

  • Verify detection of a Non-Breaking Space (U+00A0) in a supported source file
  • Verify detection of C0 control characters (e.g., Backspace \x08) in a source file
  • Verify that files containing NUL bytes (\x00) are scanned and reported rather than skipped as binary
  • Verify detection of Byte Order Marks (U+FEFF) and Soft Hyphens (U+00AD)
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify detection of a Non-Breaking Space (U+00A0) in a supported source file
2. Verify detection of C0 control characters (e.g., Backspace \x08) in a source file
3. Verify that files containing NUL bytes (\x00) are scanned and reported rather than skipped as binary
4. Verify detection of Byte Order Marks (U+FEFF) and Soft Hyphens (U+00AD)

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

-o -name '*.gleam' -o -name '*.hs' -o -name '*.ml' -o -name '*.sh' \) \
-exec grep -Prl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null
-exec grep -aPrl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null
EL_EXIT=$?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

The exit code captured here reflects the status of the find command, not the success or failure of the grep scans. Since find ignores the exit status of -exec ... \; unless it refers to a filesystem error, EL_EXIT will likely always be 0. To accurately signal a failure, you should derive the status from the count of findings or use find ... -exec ... + which returns non-zero if any invocation fails.

-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" {} \; > /tmp/empty-lint-results.txt 2>/dev/null
-exec grep -aPrl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ LOW RISK

Suggestion: Using + instead of \; allows find to pass multiple file paths to a single grep process, which is significantly faster. Additionally, the -r (recursive) flag is redundant because find is already traversing the directory structure.

auto-merge was automatically disabled September 12, 2026 14:45

Head branch was modified

@hyperpolymath
hyperpolymath enabled auto-merge (squash) September 12, 2026 19:42
@hyperpolymath
hyperpolymath merged commit 12449ec into main Sep 12, 2026
1 of 3 checks passed
@hyperpolymath
hyperpolymath deleted the fix/empty-linter-pattern-never-matched branch September 12, 2026 19:43
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant