Skip to content

fix: report-write failures should not look like findings in check and lint - #10

Merged
hanslemm merged 1 commit into
mainfrom
fix/report-write-failures
Jul 27, 2026
Merged

fix: report-write failures should not look like findings in check and lint#10
hanslemm merged 1 commit into
mainfrom
fix/report-write-failures

Conversation

@hanslemm

Copy link
Copy Markdown
Owner

Follow-up to #9, which reported this rather than fixing it.

check wrote --html and --markdown, and lint --fix rewrote the user's own source file, with no error handling and no encoding. Both defects escaped as exit 1 — the code both commands use for real findings — so an unwritable path was indistinguishable from a failed gate and CI would block on a healthy run.

That makes this worse in check and lint than the equivalent bug was in advise: advise never exits 1, so there the failure was merely wrong. Here it is actively misleading.

Two failure modes, one helper

No encoding. Path.write_text defaults to a platform-dependent encoding, and these outputs carry non-ASCII — the gate verdict is an emoji:

check --markdown  non-ASCII=['❌']  -> FAILS ascii: UnicodeEncodeError

So on an ASCII locale, every check --markdown was a guaranteed crash. lint --fix is worse in kind rather than degree: read_sql_file already reads as UTF-8, so writing without one could round-trip a non-ASCII comment into mojibake — in a file the user explicitly asked us to rewrite in place.

No handler. UnicodeEncodeError is a ValueError, so pinning the encoding makes it unlikely, not unreachable — a lone surrogate in an identifier is unencodable in any codec. Hence except (OSError, UnicodeError).

The renderers now run before the write, so a renderer bug cannot be reported as a write failure.

A note on the tests

The two encoding tests assert the encoding= argument rather than emulating an ASCII locale. That is deliberate: on this Python neither locale.getpreferredencoding nor locale.getencoding is consulted by write_text, so my first attempt — a locale-emulating test — passed with the bug still present. Asserting the argument is a weaker kind of test, but an honest one.

All four new tests were mutation-checked: reverting encoding="utf-8" and narrowing the catch back to OSError fails them.

411 tests · ruff check · ruff format --check · mypy — all green

🤖 Generated with Claude Code

`check` wrote --html and --markdown, and `lint --fix` rewrote the user's own
source file, with no error handling and no encoding. Both defects escaped as
exit 1 -- the code both commands use for real findings -- so an unwritable path
was indistinguishable from a failed gate, and CI would block on a healthy run.

Two failure modes, folded into one helper:

- No encoding. The default is platform-dependent and these outputs carry
  non-ASCII: the gate verdict is an emoji, measured as ['x'] in the markdown
  report, so on an ASCII locale every `check --markdown` was a guaranteed crash.
  `lint --fix` was worse in kind rather than degree -- read_sql_file already
  reads as UTF-8, so a non-ASCII comment could round-trip into mojibake in a
  file the user asked us to rewrite in place.
- No handler. UnicodeEncodeError is a ValueError, so pinning the encoding makes
  it unlikely rather than unreachable -- a lone surrogate in an identifier is
  unencodable in any codec -- hence catching UnicodeError alongside OSError.

The renderers now run before the write, so a renderer bug cannot be reported as
a write failure.

This is the same bug fixed for `advise` in #9 and reported there as follow-up.
It is worse in `check` and `lint` precisely because those two use exit 1
legitimately, while `advise` never does.

The two encoding tests assert the argument rather than emulating a locale: on
this Python neither locale.getpreferredencoding nor locale.getencoding is
consulted by write_text, so a locale-emulating test passed with the bug present.
Verified by mutation that all four new tests fail without the fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hanslemm
hanslemm merged commit 7054389 into main Jul 27, 2026
4 checks passed
@hanslemm
hanslemm deleted the fix/report-write-failures branch July 27, 2026 08:29
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