Review 11154: the test asserted the workspace directory as the literal
string "/fake/ws", but on Windows str(Path('/fake/ws')) is '\\fake\\ws' —
a valid spelling of the same directory when passed as a subprocess cwd.
Compare the recorded cwd as paths (Path(ws_dir) == Path('/fake/ws')) so the
assertion holds on every platform. Test-only change: passing a Path as cwd
is correct and remains untouched; no production code change.
Confirmed for the review's open question: the workspace directory is never
string-concatenated into a command — reviewer.py passes ws.dir only as the
cwd argument to Runner.run (for pytest, build_cmd, and the
["git","diff","--check", base, "HEAD"] hygiene list). The only string
containing self.dir is the MergeWorkspace __repr__ debug aid.
Tests: full suite 236 passed, 1 skipped; git diff --check clean.
The review workspace built every git invocation as a shell string. On
Windows, cmd.exe consumes the caret in `<sha>^{commit}` before git sees
it, so ReviewWorkspace could not verify SHAs and could never build a
synthetic merge on the review box (platform the product runs on).
- Runner.run: accept an argument list (executed with shell=False) as
the portable form; string commands (pytest, admin build_cmd) keep
shell semantics. Reject stringified-list commands instead of
silently re-shelling them.
- review_workspace.py: ALL git invocations now pass argument lists,
including the `^{commit}` peel, worktree add/remove with raw tmp
paths (spaces/$ no longer need shlex quoting), merge -m, fetch by
exact SHAs, MERGE_HEAD/diff/status/rev-parse checks.
- reviewer.py: the hygiene `git diff --check <base> HEAD` gate passes
an argument list too.
Sibling call sites audited: reviewer.py's test run
("python -m pytest -q") and build_cmd are the only remaining string
commands and are deliberately shell-driven; no other module in
gitea_saas constructs git command lines. Tests: new
test_caret_peel_reaches_git_as_single_list_token asserts the peel
reaches git as ONE list token; cwd/command-record assertions updated
to list form. Full suite: 236 passed, 1 skipped; git diff --check clean.