Description
Reported by @Polloinfilzato in #233 as a locale-dependent test failure — but the root cause is in
production code, and the blast radius is the rollback path, not the suite.
safe_rollback (src/bmad_loop/verify.py) restores each preserve dir from the pre-reset stash
snapshot and tolerates the benign failure — a preserve dir holding only untracked files — by
substring-matching git's English message:
rc, out = _git(repo, "checkout", snapshot, "--", d)
if rc != 0 and "did not match" not in out:
raise GitError(...)
_run_git spawns git with the inherited environment and no locale override, so under a localized
git (e.g. LANG=it_IT.UTF-8) the benign message is translated, the substring never matches, and
the benign no-op raises GitError — a resolved re-drive that should auto-recover instead
lands in the rollback failure path.
Steps to reproduce
LC_ALL= LANG=it_IT.UTF-8 .venv/bin/pytest tests/test_engine.py::test_rollback_or_pause_resolved_auto_recovers
fails (matches the reporter's observation: fails identically on clean main, passes under
LC_ALL=C).
Fix shape
Force the C locale at the single spawn point, _run_git, so every git message is stable English:
- Build the child env as
{**(env or os.environ), "LC_ALL": "C"} — note the merge must preserve
the explicit-env path (_git_env passes a custom env for the throwaway GIT_INDEX_FILE
snapshot staging; clobbering it would break snapshot_worktree).
- That also future-proofs any other message matching; today
"did not match" appears to be the
only message-content match on a git result, but the chokepoint fix makes the class impossible
rather than patching the instance.
- The tolerance behaviour is pinned by
tests/test_verify.py ("benign 'pathspec did not match'
case is tolerated"); a regression test could run the benign case with a localized LANG in the
parent env and assert it still doesn't raise.
Refs #233 (where it was reported).
Description
Reported by @Polloinfilzato in #233 as a locale-dependent test failure — but the root cause is in
production code, and the blast radius is the rollback path, not the suite.
safe_rollback(src/bmad_loop/verify.py) restores each preserve dir from the pre-reset stashsnapshot and tolerates the benign failure — a preserve dir holding only untracked files — by
substring-matching git's English message:
_run_gitspawns git with the inherited environment and no locale override, so under a localizedgit (e.g.
LANG=it_IT.UTF-8) the benign message is translated, the substring never matches, andthe benign no-op raises
GitError— a resolved re-drive that should auto-recover insteadlands in the rollback failure path.
Steps to reproduce
LC_ALL= LANG=it_IT.UTF-8 .venv/bin/pytest tests/test_engine.py::test_rollback_or_pause_resolved_auto_recoversfails (matches the reporter's observation: fails identically on clean main, passes under
LC_ALL=C).Fix shape
Force the C locale at the single spawn point,
_run_git, so every git message is stable English:{**(env or os.environ), "LC_ALL": "C"}— note the merge must preservethe explicit-env path (
_git_envpasses a custom env for the throwawayGIT_INDEX_FILEsnapshot staging; clobbering it would break
snapshot_worktree)."did not match"appears to be theonly message-content match on a git result, but the chokepoint fix makes the class impossible
rather than patching the instance.
tests/test_verify.py("benign 'pathspec did not match'case is tolerated"); a regression test could run the benign case with a localized
LANGin theparent env and assert it still doesn't raise.
Refs #233 (where it was reported).