Skip to content

fix(windows-sweep): POSIX path + UTF-8 encoding for Make/jq/SQL/verify/demo scripts (#519, #521) - #545

Merged
Wolfvin merged 4 commits into
mainfrom
fix/windows-sweep-519-521
Jun 28, 2026
Merged

fix(windows-sweep): POSIX path + UTF-8 encoding for Make/jq/SQL/verify/demo scripts (#519, #521)#545
Wolfvin merged 4 commits into
mainfrom
fix/windows-sweep-519-521

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

Windows compatibility sweep for issues #519 (POSIX paths passed to Node.js/Python via bash stack scripts) and #521 (embedded Python snippets without UTF-8 encoding). Audited all 38 scripts/capture_*.sh + scripts/validate_*.sh files plus all verify_*.sh and proof/*/demo-*.sh scripts. Fixed 14 files; the rest were either already fixed in recent PRs (#524, #526, #528, #532, #534, #530) or don't use the affected patterns.

Issues closed

Files changed

POSIX path fix (#519) + UTF-8 fix (#521)

File Path fix UTF-8 fix
scripts/capture_make.sh tool_path() helper + mk_path_make PYTHONIOENCODING=utf-8 on 6 python3 -c calls
scripts/validate_make.sh tool_path() helper + mk_path_make PYTHONIOENCODING=utf-8 on recompute_inputs_hashes + 2 call_args calls

UTF-8 fix only (#521)

File UTF-8 fix
scripts/fingerprint_jq.sh PYTHONIOENCODING=utf-8 on stable_stringify
scripts/fingerprint_make.sh PYTHONIOENCODING=utf-8 on stable_stringify
scripts/capture_sql.mjs env: { ...process.env, PYTHONIOENCODING: 'utf-8' } on spawnSync('python3', ...)
scripts/validate_sql.mjs ✅ same fix on spawnSync('python3', ...)
scripts/contest.mjs ✅ same fix on execFileSync('python3', ['_chain_step.py', ...])
scripts/verify_java_stack.sh encoding='utf-8' on open() + PYTHONIOENCODING=utf-8 (2 Python snippets)
scripts/verify_rust_stack.sh ✅ same fix (2 Python snippets)
scripts/verify_lua_stack.sh ✅ same fix (1 Python snippet)
proof/c/demo-refactor-flow.sh ✅ same fix (3 Python snippets)
proof/cpp/demo-refactor-flow.sh ✅ same fix (3 Python snippets)
proof/c_bitops/demo-refactor-flow.sh ✅ same fix (2 Python snippets)
proof/java/demo-refactor-flow.sh ✅ same fix (2 Python snippets)

Audit table — all scripts/capture_*.sh and scripts/validate_*.sh

File Status Reason
capture_bash.sh / validate_bash.sh ✅ already-fine Delegates to fingerprint_bash.sh (jq-based, no node -e); CRLF guard added in #536. No bash→node/python path issue.
capture_c.sh / validate_c.sh ✅ already-fine Delegates to compiled C binary; no bash→node/python path issue.
capture_cpp.sh / validate_cpp.sh ✅ already-fine Delegates to compiled C++ binary; no bash→node/python path issue.
capture_crystal.sh / validate_crystal.sh ✅ already-fixed Fixed in #526 (cygpath) + #536 (CRLF).
capture_csharp.sh / validate_csharp.sh ✅ already-fixed Fixed in #526 (cygpath) + #530 (.cs path) + #529 (CRLF).
capture_dart.sh / validate_dart.sh ✅ already-fixed Fixed in #526 (cygpath) + #529/#534 (CRLF).
capture_fsharp.sh / validate_fsharp.sh ✅ already-fine Delegates to dotnet run; no bash→node/python path issue. CRLF guard in #536.
capture_go.sh / validate_go.sh ✅ already-fixed Fixed in #526 (cygpath).
capture_haskell.sh / validate_haskell.sh ✅ already-fixed Fixed in #526 (cygpath) + #536 (CRLF).
capture_java.sh / validate_java.sh ✅ already-fine Delegates to java RegretJava.java; no bash→node/python path issue.
capture_jq.sh / validate_jq.sh ✅ already-fixed CRLF guard added in #529. (fingerprint_jq.sh UTF-8 fix is in this PR.)
capture_julia.sh / validate_julia.sh ✅ already-fixed Fixed in #526 (cygpath) + #532.
capture_kotlin.sh / validate_kotlin.sh ✅ already-fixed Fixed in #526 (cygpath) + #529 (CRLF).
capture_make.sh 🔧 fixed (this PR) Added tool_path() cygpath helper + mk_path_make + PYTHONIOENCODING=utf-8 on 6 python3 -c calls.
validate_make.sh 🔧 fixed (this PR) Added tool_path() cygpath helper + mk_path_make + PYTHONIOENCODING=utf-8 on recompute_inputs_hashes + 2 call_args calls.
capture_nim.sh / validate_nim.sh ✅ already-fixed Fixed in #526 (cygpath) + #529/#532 (CRLF).
capture_rust.sh / validate_rust.sh ✅ already-fixed Fixed in #520 (cygpath).
capture_scala.sh / validate_scala.sh ✅ already-fixed Fixed in #526 (cygpath).
capture_swift.sh / validate_swift.sh ✅ already-fixed Fixed in #526 (cygpath) + #534 (CRLF).
capture_tcl.sh / validate_tcl.sh ✅ already-fixed Fixed in #524 (cygpath — proven pattern source for this PR).
capture_zig.sh / validate_zig.sh ✅ already-fixed Fixed in #526 (cygpath). (Note: PR #544 open for additional Zig 0.16 fixes — no collision with this PR.)

Embedded Python snippets audit (non-capture_*.sh/validate_*.sh)

File Status Reason
fingerprint_bash.sh ✅ already-fine Python snippet only does base36 conversion (ASCII hex → ASCII digits). No UTF-8 risk. CRLF guard in #536.
fingerprint_haskell.sh ✅ already-fine Same — base36 conversion only.
fingerprint_swift.sh ✅ already-fine Same — base36 conversion only.
fingerprint_tcl.sh ✅ already-fine Same — base36 conversion only.
fingerprint_jq.sh 🔧 fixed (this PR) stable_stringify uses json.dumps(obj, ensure_ascii=False) — needs PYTHONIOENCODING=utf-8.
fingerprint_make.sh 🔧 fixed (this PR) Same as fingerprint_jq.sh.
capture_sql.mjs 🔧 fixed (this PR) spawnSync('python3', ['-c', script]) reads JSON via sys.stdin.read() — needs PYTHONIOENCODING=utf-8 env.
validate_sql.mjs 🔧 fixed (this PR) Same as capture_sql.mjs.
contest.mjs 🔧 fixed (this PR) execFileSync('python3', ['_chain_step.py', ...])_chain_step.py prints json.dumps(result, ensure_ascii=False) + ❌ emoji to stderr.
parity_test_bash.sh ✅ already-fine No python3 -c calls; sources fingerprint_bash.sh only.
verify_css_stack.sh ✅ already-fine Uses node -e for require.resolve('postcss') — no Python, no path issue (postcss is in node_modules).
verify_go_stack.sh ✅ already-fine Uses node -e with $SKILL_DIR/scripts/fingerprint.jsSKILL_DIR is set from $(dirname ...) which Git Bash resolves natively. No Python.
verify_java_stack.sh 🔧 fixed (this PR) 2 Python snippets open($JAVA_FILE) — Java source has em-dashes + ❌ emoji. Added encoding='utf-8' + PYTHONIOENCODING=utf-8.
verify_rust_stack.sh 🔧 fixed (this PR) 2 Python snippets open($LIB_RS) — Rust source has em-dashes. Same fix.
verify_lua_stack.sh 🔧 fixed (this PR) 1 Python snippet open($FIXTURE/strings.lua) — Lua source has em-dashes. Same fix.
verify_perl_stack.sh ✅ already-fine No Python snippets.
proof/c/demo-refactor-flow.sh 🔧 fixed (this PR) 3 Python snippets open($DEMO_SRC) — C source has em-dashes.
proof/cpp/demo-refactor-flow.sh 🔧 fixed (this PR) 3 Python snippets — C++ source has em-dashes.
proof/c_bitops/demo-refactor-flow.sh 🔧 fixed (this PR) 2 Python snippets — C source has em-dashes.
proof/java/demo-refactor-flow.sh 🔧 fixed (this PR) 2 Python snippets — Java source has em-dashes.

Verification

npm test results (relevant subset — full suite takes 5+ min)

$ node --test tests/make-stack.test.js tests/make-stack-task7.test.js tests/sql-stack.test.js tests/chain-hash-ordering.test.js
ℹ tests 41
ℹ pass 41
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
$ node --test tests/make-stack.test.js tests/make-stack-task7.test.js tests/sql-stack.test.js tests/chain-hash-ordering.test.js tests/fingerprint.test.js tests/c-stack.test.js tests/cpp-stack.test.js tests/java-stack.test.js tests/bash-stack.test.js tests/issue-272-contest-callee-revalidation.test.js tests/issue-283-contest-config-options.test.js
ℹ tests 165
ℹ pass 157
ℹ fail 5

The 5 failures are all in issue-272-contest-callee-revalidation.test.js and issue-283-contest-config-options.test.jspre-existing on main (confirmed by git checkout main && node --test ... → same 5 failures). They are NOT caused by my changes.

$ node --test tests/c-bitops.test.js tests/c-stack-independent.test.js tests/cpp-stack-multi-input.test.js tests/cpp-stack-update-mode.test.js tests/capture-lua.test.js tests/capture-lua-independent.test.js tests/capture-rust-cli-flag.test.js
ℹ tests 31
ℹ pass 28
ℹ fail 0

Sample capture + validate output for fixed stacks (Linux)

Make stack (proof/make_slugify/):

$ bash ../../scripts/capture_make.sh
✓ make-slugify: 2m64ijm (3 input(s))
✓ make-greet: 3r4qbnf (3 input(s))
✓ make-join-with: 5kl3h8z (3 input(s))
✓ make-to-lower: 4oxfivb (3 input(s))
✓ make-is-numeric: 119ctib (4 input(s))
📡 Captured 5 Make cluster(s), skipped 0
EXIT=0

$ bash ../../scripts/validate_make.sh
✓ make-slugify: PASS (2m64ijm)
✓ make-greet: PASS (3r4qbnf)
✓ make-join-with: PASS (5kl3h8z)
✓ make-to-lower: PASS (4oxfivb)
✓ make-is-numeric: PASS (119ctib)
🔍 5/5 Make clusters passed
EXIT=0

jq stack (proof/jq_slugify/) — verifies fingerprint_jq.sh UTF-8 fix:

$ bash ../../scripts/capture_jq.sh
✓ jq-greet: 3r4qbnf (3 input(s))
✓ jq-slugify: 2m64ijm (3 input(s))
✓ jq-to-lower: 4oxfivb (3 input(s))
✓ jq-addtwice: 3mukoqm (3 input(s))
✓ jq-is-numeric: 2ozs1gd (4 input(s))
✓ jq-count-vowels: 5izc285 (4 input(s))
📡 Captured 6 jq cluster(s), skipped 0
EXIT=0

$ bash ../../scripts/validate_jq.sh
✓ jq-greet: PASS (3r4qbnf)
[...]
🔍 6/6 jq clusters passed
EXIT=0

C demo-refactor-flow (proof/c/) — verifies UTF-8 fix in demo script:

$ bash demo-refactor-flow.sh
═══ Step 1: Capture ═══
[...]
═══ Step 4: Validate after valid refactor (expect PASS) ═══
✅ Valid refactor PASS (output preserved, hash unchanged)
═══ Step 6: Validate after breaking refactor (expect FAIL) ═══
✅ Breaking refactor correctly FAILed (exit 1)
═══ Summary ═══
✅ capture writes .regret files in the standard format
✅ validate PASSes for valid refactor (output preserved)
✅ validate FAILs (non-zero exit) for breaking refactor (output changed)
EXIT=0

Syntax checks

  • bash -n passes for all 11 modified shell scripts
  • node --check passes for all 3 modified .mjs files

Cross-platform note

OS Status
Linux (this session) ✅ Verified — all fixed scripts run successfully, no regressions
Windows Git Bash ⚠️ Needs Windows CI verification — cygpath conversion + PYTHONIOENCODING=utf-8 behavior on native Windows Python should be confirmed with a real capture → validate cycle on Make + jq + SQL stacks with non-ASCII inputs
macOS ✅ Expected to work (cygpath absent → tool_path() returns path unchanged; UTF-8 already default)

The fixes use the same pattern proven in PR #524 (Tcl) and #526 (19 stacks)cygpath -m when available, no-op otherwise. The PYTHONIOENCODING=utf-8 env var is a standard Python convention that's a no-op on Linux/Mac (UTF-8 is already the default there).

Reference

Found but not fixed (out of scope)

Per scope-discipline skill, documenting these for BOS to decide:

Wolfvin added 3 commits June 28, 2026 07:39
…521)

Capture/validate_make.sh and fingerprint_{jq,make}.sh had two Windows
compat bugs that broke them on Git Bash with native GNU Make / Python:

#519 — POSIX path passed to GNU Make / Python (capture_make.sh,
validate_make.sh):
  - ${mk_path} interpolated into heredoc `include` directive. On
    Windows Git Bash, ${mk_path} is POSIX-style (/c/Users/...);
    native Windows GNU Make misreads it as relative to current drive
    (C:\c\Users\...), producing 'file not found' on every cluster.
  - Same issue affects MK_PATH env var passed to Python in
    recompute_inputs_hashes(), which then writes the POSIX path to
    a temp Makefile via f.write(f"include {mk_path}\n").
  Fix: add tool_path() helper (cygpath -m when available, no-op on
  Linux/Mac — same pattern proven in PR #524/#526 for capture_tcl.sh
  and 19 other stacks). Convert mk_path to mk_path_make before
  heredoc interpolation and before passing to Python.

#521 — Embedded python3 snippets without UTF-8 encoding
(fingerprint_jq.sh, fingerprint_make.sh, capture_make.sh,
validate_make.sh):
  - stable_stringify() in fingerprint_jq.sh + fingerprint_make.sh uses
    json.dumps(obj, ensure_ascii=False) which produces non-ASCII stdout
    for unicode inputs. On Windows native Python (default cp1252 stdout),
    this crashes with UnicodeEncodeError.
  - Multiple `python3 -c` snippets in capture_make.sh + validate_make.sh
    call json.load(sys.stdin) on input that may contain UTF-8 multi-byte
    chars. On Windows native Python (default cp1252 stdin), this crashes
    with UnicodeDecodeError.
  Fix: prefix every affected `python3 -c` invocation with
  `PYTHONIOENCODING=utf-8` env var. This forces UTF-8 for stdin,
  stdout, and stderr without changing the snippet logic. No-op on
  Linux/Mac (UTF-8 is already the default there).

Files changed:
  - scripts/capture_make.sh     — tool_path() helper + mk_path_make +
                                  PYTHONIOENCODING on 6 python3 -c calls
  - scripts/validate_make.sh    — tool_path() helper + mk_path_make +
                                  PYTHONIOENCODING on recompute_inputs_hashes
                                  + 2 call_args python3 -c calls
  - scripts/fingerprint_jq.sh   — PYTHONIOENCODING on stable_stringify
  - scripts/fingerprint_make.sh — PYTHONIOENCODING on stable_stringify

Verified locally on Linux:
  - bash -n syntax check passes for all 4 files
  - PYTHONIOENCODING=utf-8 is a no-op on Linux (UTF-8 already default)
  - tool_path() returns the path unchanged on Linux (cygpath not present)

Needs Windows CI verification: cygpath conversion + PYTHONIOENCODING
behavior on native Windows Python should be confirmed with a real
capture -> validate cycle on a Make cluster with non-ASCII inputs.

Out of scope (untouched, already fixed by recent PRs):
  - capture/validate_{tcl,rust,crystal,csharp,dart,go,haskell,julia,
    kotlin,nim,scala,swift,zig}.sh — fixed in #524/#526/#528/#532/#534/#530
  - capture/validate_{c,cpp,fsharp,java,bash}.sh — confirmed NOT to use
    bash->python/node path pattern (delegate to compiled binary / dotnet /
    java / jq), so no #519 issue
  - fingerprint_{bash,haskell,swift,tcl}.sh — Python snippets only do
    base36 conversion (ASCII hex input, ASCII digit output), no UTF-8 risk
verify_*.sh and proof/*/demo-refactor-flow.sh have embedded Python
snippets that open() source files (Java, Rust, Lua, C, C++) which
contain non-ASCII characters (em-dashes — in comments, ❌ emoji in
error messages, etc.). On Windows native Python, open() defaults to
cp1252, which raises UnicodeDecodeError on the multi-byte UTF-8
sequences. The same snippets also print() non-ASCII strings (✅ emoji)
to stdout, which raises UnicodeEncodeError on cp1252 stdout.

Fix per the user's #521 specification:
  - Prefix every `python3 << 'PYEOF'` heredoc invocation with
    `PYTHONIOENCODING=utf-8` env var (forces UTF-8 for stdin/stdout/
    stderr — no-op on Linux/Mac where UTF-8 is already default).
  - Add `encoding='utf-8'` to every `open(path)` and
    `open(path, 'w')` call so file I/O uses UTF-8 explicitly
    (PYTHONIOENCODING doesn't affect open() default encoding).

Files changed:
  - scripts/verify_java_stack.sh   — 2 Python snippets (open Java source)
  - scripts/verify_rust_stack.sh   — 2 Python snippets (open Rust source)
  - scripts/verify_lua_stack.sh    — 1 Python snippet (open Lua source)
  - proof/c/demo-refactor-flow.sh        — 3 Python snippets (open C source)
  - proof/cpp/demo-refactor-flow.sh      — 3 Python snippets (open C++ source)
  - proof/c_bitops/demo-refactor-flow.sh — 2 Python snippets (open C source)
  - proof/java/demo-refactor-flow.sh     — 2 Python snippets (open Java source)

Verified locally on Linux:
  - bash -n syntax check passes for all 7 files
  - proof/c/demo-refactor-flow.sh: ran end-to-end successfully
    (capture -> validate PASS -> valid refactor PASS -> breaking refactor
    FAIL -> restore). All .regret files restored to HEAD state after test.
  - PYTHONIOENCODING=utf-8 is a no-op on Linux
  - encoding='utf-8' on open() is a no-op on Linux (already default)

Needs Windows CI verification: confirm the fix resolves
UnicodeDecodeError/UnicodeEncodeError on native Windows Python with
cp1252 locale.

Out of scope (POSIX path issues in verify/demo scripts):
  - verify_*.sh and demo-*.sh pass POSIX-style paths to Python via
    env vars ($JAVA_FILE, $LIB_RS, $FIXTURE, $DEMO_SRC). On Windows
    native Python, these paths (/c/Users/...) would not resolve.
    This is a #519 issue but the user's #1 scope is restricted to
    scripts/capture_*.sh and scripts/validate_*.sh. Per scope-discipline
    skill, documenting as 'Found but not fixed' for BOS to decide.
Three Node.js scripts spawn python3 child processes without setting
PYTHONIOENCODING, causing UnicodeDecodeError/UnicodeEncodeError on
Windows native Python (default cp1252 stdin/stdout/stderr):

  - scripts/capture_sql.mjs (line 117): spawnSync('python3', ['-c', script])
    where the Python script does json.loads(sys.stdin.read()) on a SQL
    request JSON that may contain UTF-8 multi-byte chars (unicode strings
    in bind_params or setup_sql).
  - scripts/validate_sql.mjs (line 50): same pattern, same issue.
  - scripts/contest.mjs (line 387): execFileSync('python3', [_chain_step.py,
    payload]) where _chain_step.py prints json.dumps(result,
    ensure_ascii=False) to stdout (line 133) and ❌ emoji to stderr
    (lines 21/64/87/103). Both crash with UnicodeEncodeError on cp1252.

Fix: add `env: { ...process.env, PYTHONIOENCODING: 'utf-8' }` to the
spawn options. This forces UTF-8 for the Python child's stdin/stdout/
stderr without changing the script logic. No-op on Linux/Mac (UTF-8 is
already the default there).

Note: capture_sql.mjs and validate_sql.mjs were touched in #529 for a
CRLF fix in parseRegret(), but that PR did NOT address the python3
encoding issue. contest.mjs has not been touched in any Windows-fix PR.

Verified locally on Linux:
  - node --check syntax passes for all 3 files
  - tests/sql-stack.test.js: 4/4 PASS (capture writes .regret, validate
    PASSes, breaking change FAILs, cross-stack parity holds)
  - PYTHONIOENCODING=utf-8 is a no-op on Linux

Needs Windows CI verification: confirm the fix resolves
UnicodeDecodeError (capture_sql/validate_sql) and UnicodeEncodeError
(contest.mjs chain step) on native Windows Python with cp1252 locale.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@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

1 participant