Skip to content

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

Open
hyperpolymath wants to merge 1 commit into
mainfrom
fix/empty-linter-pattern-never-matched
Open

fix(ci): the invisible-character gate never matched anything#142
hyperpolymath wants to merge 1 commit 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.
@sonarqubecloud

Copy link
Copy Markdown

@gitar-bot

gitar-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8a37ce7d-370b-4288-baf0-6c54590bb40a

📥 Commits

Reviewing files that changed from the base of the PR and between 5534f24 and aceaa0d.

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

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (27)
  • GitHub Check: scan / gitleaks
  • GitHub Check: scan / Hypatia Neurosymbolic Analysis
  • GitHub Check: scan / rust-secrets
  • GitHub Check: governance / Trusted-base reduction policy
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: governance / Licence consistency
  • GitHub Check: governance / Exemption ratchet
  • GitHub Check: governance / Workflow security linter
  • GitHub Check: governance / Allowlist Preflight
  • GitHub Check: governance / Well-Known (RFC 9116 + RSR)
  • GitHub Check: governance / Code quality + docs
  • GitHub Check: governance / Check Workflow Staleness
  • GitHub Check: governance / Guix packaging policy (Nix retired)
  • GitHub Check: scan / shell-secrets
  • GitHub Check: governance / Language / package anti-pattern policy
  • GitHub Check: governance / Debt ratchet
  • GitHub Check: governance / Security policy checks
  • GitHub Check: analyze (actions, none)
  • GitHub Check: Validate K9 contracts
  • GitHub Check: Validate A2ML manifests
  • GitHub Check: Groove manifest check
  • GitHub Check: Coordinator boundary (no language leakage)
  • GitHub Check: Empty-linter (invisible characters)
  • GitHub Check: Language registry consistency
  • GitHub Check: semgrep
  • GitHub Check: lint-workflows
  • GitHub Check: lint-workflows
🔇 Additional comments (1)
.github/workflows/dogfood-gate.yml (1)

135-135: LGTM!

Also applies to: 146-146


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of hidden and non-printing characters, including within binary files.
    • Expanded validation coverage for additional control characters.

Walkthrough

The workflow’s invisible-character scan now uses Unicode code-point escapes, includes additional C0 control characters, and treats binary files as text during grep scans.

Changes

Invisible-character gate

Layer / File(s) Summary
Pattern and binary scan
.github/workflows/dogfood-gate.yml
The PATTERNS regex now uses Unicode code-point escapes and covers additional C0 control characters. The grep command now scans binary files as text.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to aceaa

This localized CI change corrects invisible-character matching and adds coverage for previously missed control characters without changing product runtime behavior. No actionable merge-blocking risk remains after normal checks and review.

Poem

A rabbit checks each hidden mark,
From dawn-lit files to bytes dark.
Code points guide the careful scan,
Binary text joins the checking plan,
Clean gates guard the burrow’s arc.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements the codepoint escapes, C0 control detection, and grep -a requirements from [#70]. The provided changes do not show the required separate leading-BOM check, matching updates to the co… Add or provide evidence for the separate leading-BOM check, consistent C0-control detection in the compiled linter, and the required estate-wide updates to all affected gate copies. Verify the complete set of issue acceptance criteria after…
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: fixing the CI invisible-character gate.
Description check ✅ Passed The description directly explains the gate failure, root cause, implemented fixes, and verification.
Out of Scope Changes check ✅ Passed The two-line workflow change is directly related to fixing the invisible-character gate described in [#70]. No unrelated code changes are shown.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Full details: Linked Issues check

Explanation

The PR implements the codepoint escapes, C0 control detection, and grep -a requirements from [#70]. The provided changes do not show the required separate leading-BOM check, matching updates to the compiled linter, or correction of the inlined pattern across the affected estate.

Resolution

Add or provide evidence for the separate leading-BOM check, consistent C0-control detection in the compiled linter, and the required estate-wide updates to all affected gate copies. Verify the complete set of issue acceptance criteria after these changes are applied.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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 successfully migrates the invisible-character gate to use PCRE-compatible Unicode escapes and expands the detection range to include control characters and null bytes. While the core logic is an improvement and Codacy results are up to standards, there is a regression: the Narrow No-Break Space (U+202F) was omitted during the refactor. Additionally, the grep command in the workflow contains redundant flags and silences stderr, which could lead to false negatives if the PCRE engine encounters internal errors. These issues should be resolved before merging to ensure the linter is both comprehensive and reliable.

About this PR

  • The PR does not include automated test cases or fixture files containing the 'invisible' characters. Without these, it is difficult to verify the fix or prevent future regressions in the patterns.

Test suggestions

  • Verify detection of Non-Breaking Space (U+00A0)
  • Verify detection of Soft Hyphen (U+00AD)
  • Verify detection of Byte Order Mark (U+FEFF)
  • Verify detection of C0 control character like Backspace (\x08)
  • Verify grep processes files containing NUL bytes (\x00) instead of skipping them
  • Verify detection of Bidi Override characters (e.g., U+202E)
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify detection of Non-Breaking Space (U+00A0)
2. Verify detection of Soft Hyphen (U+00AD)
3. Verify detection of Byte Order Mark (U+FEFF)
4. Verify detection of C0 control character like Backspace (\x08)
5. Verify grep processes files containing NUL bytes (\x00) instead of skipping them
6. Verify detection of Bidi Override characters (e.g., U+202E)

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

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

🟡 MEDIUM RISK

Avoid silencing stderr with 2>/dev/null and remove the redundant -r flag. Silencing errors is risky when using grep -P because internal PCRE errors or malformed UTF-8 can cause the linter to silently fail, resulting in false negatives. Furthermore, using + instead of \; allows find to batch file paths, improving performance.

Suggested change
-exec grep -aPrl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null
-exec grep -aPl "$PATTERNS" {} + > /tmp/empty-lint-results.txt

# non-breaking spaces, null bytes, and other invisible Unicode in source files.
set +e
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}'

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 pattern for U+202F (Narrow No-Break Space) is missing. This character was covered in the previous version and should be included to maintain full coverage of invisible characters.

Suggested change
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='\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{202f}|\x{2060}|\x{feff}'

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