Windows CI command-line output repair — 2026-09-08¶
The supplied CI logs logs_92659471441 contain five Windows Python failures.
All five are output-encoding errors before simulation; the Ubuntu and self-hosted
jobs passed. This repair handles unrepresentable CLI text without changing solver
code, numerical thresholds, contract identifiers, or CI settings.
Actual CI evidence before this repair¶
The three jobs tested GitHub's synthetic merge c390b3b: personal branch commit
c311992e91ef06575fd4ac254afd2ef8380093fb against upstream
753894f186bef9c2a692fae0ca72bd8316d0248f. A synthetic merge used for CI does not
mean the PR was merged into upstream main.
| Job | Build / CTest | Python tests |
|---|---|---|
| Ubuntu, Python 3.11 | PASS | 1606 passed, 406 skipped |
| Windows, Python 3.11 | PASS | 1601 passed, 5 failed, 406 skipped |
| Self-hosted IPC + LBM CUDA 12.8 | PASS | 1624 passed, 388 skipped |
The failures are:
test_candidate_d_d3_contract_check.py::test_d3_contract_check_pass: the checker prints its PASS marker, then fails printing the Greek delta insingle_change=D-Δ3to a cp1252 pipe.test_implicit_mpm_newton_fem_gs_strain_residual.py::test_multi_material_help_lists_gs_strain_residual_flag.test_o2_gs_device_early_exit.py::test_multi_material_help_lists_device_early_exit.test_o2_gs_residual_check_stride.py::test_multi_material_help_lists_stride_flag.test_o3_gs_persistent.py::test_multi_material_help_lists_gs_persistent.
The last four invoke the same multi-material demo with --help. Argparse fails
writing an arrow character to cp1252. No solver step is reached. This failure set
is distinct from the previously recorded sixteen failures in the full MPM CUDA
suite; those numerical/runtime issues remain outside this repair.
Repair¶
At the beginning of the D3 checker and multi-material CLI main(), reconfigure
stdout/stderr with errors="backslashreplace" when the stream supports it.
Keep the stream's existing encoding so redirected output can still be decoded by
the caller. UTF-8 text remains unchanged; unsupported characters on cp1252/ASCII
are printed as escapes. This also preserves readable D3 failure diagnostics and
the existing nonzero exit status for an invalid contract.
No output reconfiguration occurs merely from importing these modules. Frozen contract data and all five original test assertions remain unchanged. No global UTF-8 environment override, test skip, workflow relaxation, or Warp change is introduced.
Local verification¶
- Before the repair, the new regression cases reproduced 8 encoding failures, 4 passes under explicit UTF-8, cp1252 and ASCII pipes. An initial draft test used the wrong stride option name; that draft result is retained separately and is not counted as a product failure. The corrected tests produced the counts above.
- After the repair, the five affected test files plus the new regression file: 39 passed, 8 skipped, including all five original CI failures and all twelve encoding cases. Skips are existing backend prerequisites in related tests.
- The new cases cover the standalone D3 checker, direct demo script, installed module invocation, and invalid-contract diagnostics. They explicitly decode captured output using the same encoding as the child process.
- Ruff
E,W,F,I: zero diagnostics in the new test; no new diagnostics in the two existing CLI files (their six and fifty-five pre-existing diagnostics remain).
This is a focused Linux subprocess reproduction of Windows pipe encoding. The full Python suite and native builds were not repeated for this Python output-only change. Actual Windows CI must rerun on the new commit before declaring the check passed. The supplied logs do not include the documentation deployment workflow.
Reproduction¶
From a checkout with an installed NovaPhy package and test dependencies:
pytest -q python/tests/test_mpm_cli_output_encoding.py \
python/tests/python/implicit_mpm/test_candidate_d_d3_contract_check.py \
python/tests/python/implicit_mpm/test_implicit_mpm_newton_fem_gs_strain_residual.py \
python/tests/python/perf/test_o2_gs_device_early_exit.py \
python/tests/python/perf/test_o2_gs_residual_check_stride.py \
python/tests/python/perf/test_o3_gs_persistent.py
Original logs remain under /home/yin/NovaPhy/logs_92659471441. Their SHA256
manifest, source backups, before/after XML and Ruff comparison are retained in
batch01/publication/four_scene11_ci_preflight_20260908/windows_encoding_fix/.
Command logs and exit codes are in the sibling evidence/windows_encoding_*.log
and .json files. Environments, native libraries, caches and raw CI logs are not
included in the source commit.