Skip to content

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 in single_change=D-Δ3 to 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.