Repository navigation
Conversation
On native Windows (Git for Windows, no WSL) a Herdr spawn cannot prove its pane's folder and teardown cannot take the presentation lock. Every new branch is gated on a Cygwin-family uname plus cygpath, so POSIX hosts keep their exact behavior. Folder discovery: Herdr never reports foreground_cwd off Unix, and a Windows pane's cwd is the launched shell's own folder, which does not follow a cd in Git Bash. Before any harness starts, the spawn's worktree assertion now asks the pane's shell with a nonce-tagged printf every tenth poll and accepts only a POSIX-absolute answer. Relaunch keeps the passive read and never types into a pane that may hold a live agent, so it still refuses there. Pane shell: Herdr opens PowerShell on Windows unless [terminal] default_shell names another shell, and the spawn's commands are POSIX. PowerShell answers the probe with a drive-letter $PWD and cmd.exe with nothing, so such a pane is refused before launch with a hint naming the setting, instead of receiving a POSIX launch line. Teardown lock: Git for Windows mounts /tmp noacl, so the presentation lock namespace always stats 755 and the mode-700 check refused teardown outright. On Windows the namespace is accepted only when it sits directly inside a /tmp mounted noacl and usertemp, the caller's per-user %TEMP%. Ported from the native Windows Herdr fix on trngthnh369/firstmate (d17e85f) and re-derived for the leased-slot spawn flow. Refs kunchenguid#3283 Co-authored-by: trngthnh369 <183968430+trngthnh369@users.noreply.github.com>
…hell The folder probe now returns 2 when its answer arrives but is not POSIX-absolute, as PowerShell's drive-letter $PWD is, so the spawn refuses at the first probe instead of waiting out the full assertion deadline. Live on Windows Herdr 0.9.3 this cut a PowerShell-pane refusal from 355s to 54s. Refs kunchenguid#3283 Co-authored-by: trngthnh369 <183968430+trngthnh369@users.noreply.github.com>
[Medium impact] The PR appears safe to merge; no new actionable issue remains. Reviews (4) · Last reviewed commit: "fix(herdr): read the Windows folder prob..." · Reviewed by Greptile |
… fix in tests/fm-backend-herdr.test.sh; no production code changed. Rule broken: the namespace test must give the same answers on any host. It fakes uname as MINGW, which sends both namespace readers in bin/backends/herdr.sh to GNU `stat -c '%a'` and `stat -c '%u'`. BSD stat on macOS rejects `-c`. Those two calls are the only host-dependent commands the test reaches; uname, cygpath and mount were already faked. Fix: ns_valid_via first reads the test folder's real mode and owner from the host (GNU `stat -c`, falling back to `/usr/bin/stat -f` on macOS). It then writes a fake GNU-style `stat` into the same folder as the other fakes; the fake answers `%a` and `%u` with those values and fails on anything else. The refusal cases still mean something: a POSIX host still needs mode 700 (the fake reports the real 755), and wrong mount options and the nested folder are still refused. Verification: test_presentation_lock_namespace_on_a_windows_usertemp_mount passes when run by itself on this Windows host. It has not been run on macOS or Linux. Running the whole file here stops at an earlier test ('version_check did not report herdr as missing') before reaching the namespace test; the cause was not confirmed and is probably that Herdr is installed on this machine. shellcheck is not installed here, so the file was not linted. ci-1 needs no code change: you chose to leave it alone (it waits on a maintainer's full-ci label)
…o tests/fm-backend-herdr.test.sh; not confirmed with ShellCheck, which isn't installed on this host. Test-only change; no production code changed. The rule: ShellCheck 0.11.0 with -x must report nothing on this test file. The generated helper scripts need a literal $, so each place that writes one with a quoted printf needs a scoped suppression. Where else it applies: ns_valid_via writes four fake commands (uname, stat, cygpath, mount). Only the fake stat contains a $: its `case "$2"`, which reads the fake command's own second argument. The other three contain none, so they can't trigger SC2016. The `bash -c '...'` line at the end was not reported; ShellCheck normally exempts single-quoted bash -c code from this warning. The fix: one line, `# shellcheck disable=SC2016 # $2 is the generated stub's own argument.`, directly above the fake-stat printf. This matches the file's existing style (for example line 2720). The fake stat behaves exactly as before. Verification: `bash -n` on the file passes. test_presentation_lock_namespace_on_a_windows_usertemp_mount passed when run by itself on this Windows host, using a temporary copy with the other tests left out; the copy was deleted afterwards. Not done: ShellCheck 0.11.0 is not on PATH here, so the lint step should be re-run to confirm SC2016 is gone and nothing new was flagged. ci-1 (Full suite) was not touched: the user chose to leave it; it waits on a maintainer's full-ci label
|
Found while trialing this PR on native Windows (Git for Windows MSYS 3.6.4, Herdr 0.9.5, Git Bash panes via Repro: The same spawn with a short path (probe answer 112 characters) succeeds: the worker starts, writes its report, and its status line wakes the watcher. Suggested fix: read the probe answer with soft wraps joined (or match it across wrapped lines), or have the probe print the path in fixed-size chunks that the parser reassembles. |
|
Follow-up on the wrap defect above: Herdr already has a read mode that avoids it. In a Herdr 0.9.5 session with Git Bash panes on native Windows, I printed a 155-character probe answer with this PR's exact
|
# Conflicts: # tests/fm-backend-herdr.test.sh
A worktree path long enough to make the probe answer wider than the pane was hard-wrapped by `pane read --source recent`, so the answer line never matched and a Git Bash pane was refused as if it ran another shell. Read the probe with `--source recent-unwrapped`, falling back to the plain read on a Herdr without that source. The fake pane in the lease tests now wraps its recent source at 120 columns.
|
Speaking as Kun's firstmate: thank you @cr101 for picking up defects 2–4 of #3283 (with co-author credit to trngthnh369) and for the Windows-gated, fail-closed shape. I read tip Waiting on you for one thing. @tin-hong trialled this tip on native Windows (Git for Windows MSYS 3.6.4, Herdr 0.9.5, Git Bash panes) and found that a long worktree path hard-wraps the probe answer at the pane width, so Contract-class: restore. Native Windows Herdr spawn/teardown for defects 2–4 of #3283; every new branch is gated on Cygwin-family Rockets: none. Security: none. |
|
Thanks for the careful repro and the follow-up — both were spot on. f0032a0 switches only the folder probe to |
|
Speaking as Kun's firstmate: thank you @cr101 — and @tin-hong for the wrap repro. Tip Gates on this head: attestation binds Contract-class (re-checked on tip vs main): new-default. On native Windows Herdr the unconfigured spawn now runs a nonce Nothing more needed from you right now — this is with the coordinator for the |
|
Speaking as Kun's firstmate: tip |
Intent
Fix the long-path failure reported on #8181 (comment) inside PR #8181 itself (no new PR): rebase #8181 onto current main (it now conflicts), switch the folder probe to read the pane with soft wraps joined, add a test with a path longer than the pane width, check it live on this Windows host with a path over 120 characters, and push it through the same full validation into #8181.
Context for reading that ask:
__FM_CWD_<nonce>__<path>__was hard-wrapped across two lines of a 120-column pane. The same spawn with a short path (answer 112 characters) succeeds end to end. Suggested fix: read the probe answer with soft wraps joined, or match across wrapped lines, or print the path in fixed chunks.fm_backend_herdr_probe_pathreads viafm_backend_herdr_capture, which callsherdr pane read --source recent. Herdr 0.9.5 also offers--source recent-unwrapped.What Changed
foreground_cwd,spawn_assert_agent_worktreenow checks a new pane-folder probe on every tenth poll. The probe isfm_backend_herdr_probe_path. It types a nonce-taggedprintfof$PWDinto the pane and reads the answer back withpane read --source recent-unwrapped, so a folder path wider than the pane is joined back into one line. If Herdr rejects that source, it falls back to the plain recent read. Only a POSIX-absolute answer counts. A non-POSIX answer (from PowerShell or cmd.exe) stops the wait right away. When no Git Bash answer arrives, the error tells the user to set Herdr's[terminal] default_shellto Git Bash. Relaunch never runs the probe.noacl/tmpcan't hold mode 700, so on a Windows host the namespace is accepted if it sits directly inside a/tmpmountedusertemp,noacl(the account's own%TEMP%). The uid must still match, and every other mount shape is still refused.docs/herdr-backend.mdnow covers the Git Bashdefault_shellprerequisite, the Windows lock-namespace rule and the probe-or-refuse behavior. New tests cover the Windowsusertempnamespace and these probe cases: a Git Bash pane, a PowerShell pane, a pane that never moves, an answer wider than the pane, a missing or malformed answer, relaunch without probing, and a POSIX host that never probes.Risk Assessment
✅ Low: The fix is narrow: the Windows-only probe now reads with
--source recent-unwrappedand falls back to the plain read when that source is rejected. It has a regression test whose fake hard-wraps the plain read at 120 columns, so it fails without the fix. Relaunch still refuses at its own passive folder check before the probe can run, and POSIX hosts are gated out.Testing
I drove the changed probe live against a disposable Herdr lab session on this Windows host. A Git Bash pane in a 134-character folder (more than the 120-column pane width) returned exactly that folder through the new soft-wrap-joined read. On the same pane the old plain read split the answer over two rows and extracted nothing, which reproduces the reported bug. A PowerShell pane in a 166-character folder was still rejected with rc=2. I also re-ran the soft-wrap and malformed/missing-answer lease tests on their own, without the rest of the file: both pass. The earlier malformed-answer failure was therefore timing or load, not a regression, and no code was changed. A full real
fm-spawninto a long treehouse path was not run. The lab session and temp folders were torn down.A full real
fm-spawnand cleanup into a long path was run outside this pipeline on the same host, through a named Herdr lab session: a 131-character folder (158-character probe answer, hard-wrapped by the plain read) spawned and cleaned up; a short path also passed; the pre-fix code refused the same long path after about 416 s.bin/fm-brief.sh --herdr-lab, project registration and a live harness on a lab session. That could not be done safely inside this turn's 30-m…Evidence: Live long-path probe: new read matches the 134-char folder, old recent read extracts nothing (wrapped rows shown)
Source: Live long-path probe: new read matches the 134-char folder, old recent read extracts nothing (wrapped rows shown)
Evidence: Live adversarial: PowerShell pane in a 166-char folder, probe returns rc=2 (refused)
Source: Live adversarial: PowerShell pane in a 166-char folder, probe returns rc=2 (refused)
Evidence: Isolated lease tests: wider-than-pane accepted, missing/malformed answer refused
Source: Isolated lease tests: wider-than-pane accepted, missing/malformed answer refused
ok - native Windows Herdr accepts a folder probe answer the pane soft-wraps ok - native Windows Herdr refuses a missing or malformed folder probe answer exit=0Pipeline
Updates from git push no-mistakes
✅ **Intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/backends/herdr.sh:3239- The intent says to "rebase fix(herdr): spawn task workers on native Windows Herdr with Git Bash panes #8181 onto current main (it now conflicts)". The branch history instead brings main in with a merge commit (96daeb0 "Merge main into fix/herdr-windows-spawn") on top of the earlier PR commits c29e3f6..52bb479; no rebase was done. The conflict is resolved either way, and the diff against main b77b66c has no leftover socket-path workaround, since fix(bin): canonicalize Windows drive-letter herdr socket paths before identity comparison #8185 already covers defect 1. Even so, a merge is a different history shape from the one the intent asked for. Please confirm whether a merge is acceptable or the branch should be rebased before it is pushed into fix(herdr): spawn task workers on native Windows Herdr with Git Bash panes #8181.🔧 **Test** - 2 issues found → no changes applied → fix attempted; result not reported ✅
tests/fm-spawn-herdr-lease.test.sh:401- In a targeted run of tests/fm-spawn-herdr-lease.test.sh on this Windows host, test_windows_missing_or_malformed_probe_answer_refuses failed on the malformed-answer case: the refusal output did not contain 'not its recorded worktree'. The output showed only warnings and no refusal line. The silent-pane case and the new soft-wrap test passed. The file then ran past the 10-minute background limit and was stopped, so the root cause is not established. It may be a real regression from the fake-pane or read change, or timing flakiness under load. Please re-run this test alone, or check the CI result, before shipping.bin/fm-herdr-lab.sh name/provision/run/teardownnamed lab session fm-lab-longpath-87058-8931 (default session untouched)Live: sourced bin/backends/herdr.sh and called fm_backend_herdr_probe_path on a lab PowerShell pane (rc=2)Live: Git Bash in a lab pane, cd into a 155-char folder; fm_backend_herdr_probe_path with the pre-fix 52bb4793 backend (empty answer) vs the f0032a01 backend (full path)herdr pane read --source recentvs--source recent-unwrappedon the same lab pane, to show the hard wrapbash tests/fm-spawn-herdr-lease.test.sh(partial: 4 ok, 1 not ok, then stopped at the 10-minute limit)🔧 Fix attempted; result not reported.
3 issues (1 error, 2 warnings) still open:
tests/fm-spawn-herdr-lease.test.sh:401- In a targeted run of tests/fm-spawn-herdr-lease.test.sh on this Windows host, test_windows_missing_or_malformed_probe_answer_refuses failed on the malformed-answer case: the refusal output did not contain 'not its recorded worktree'. The output showed only warnings and no refusal line. The silent-pane case and the new soft-wrap test passed. The file then ran past the 10-minute background limit and was stopped, so the root cause is not established. It may be a real regression from the fake-pane or read change, or timing flakiness under load. Please re-run this test alone, or check the CI result, before shipping.bin/fm-herdr-lab.sh name/provision/run/teardownnamed lab session fm-lab-longpath-87058-8931 (default session untouched)Live: sourced bin/backends/herdr.sh and called fm_backend_herdr_probe_path on a lab PowerShell pane (rc=2)Live: Git Bash in a lab pane, cd into a 155-char folder; fm_backend_herdr_probe_path with the pre-fix 52bb4793 backend (empty answer) vs the f0032a01 backend (full path)herdr pane read --source recentvs--source recent-unwrappedon the same lab pane, to show the hard wrapbash tests/fm-spawn-herdr-lease.test.sh(partial: 4 ok, 1 not ok, then stopped at the 10-minute limit)🔧 No changes applied.
✅ Re-checked - no issues remain.
bin/fm-brief.sh --herdr-lab, project registration and a live harness on a lab session. That could not be done safely inside this turn's 30-m…bin/fm-herdr-lab.sh name probewrap+provision→ lab session fm-lab-probewrap-146745-5569, workspace w1:p1 (120 columns), Git Bash started in the pane,cdinto a 134-char /tmp/fm-lab.VgiO5p/... folderSourced bin/backends/herdr.sh and calledfm_backend_herdr_probe_path <lab>:w1:p1; compared with the pre-fixfm_backend_herdr_capture(--source recent) extraction on the same paneAdversarial: switched the same pane back to PowerShell, ranSet-Locationinto the 166-char Windows path, then calledfm_backend_herdr_probe_pathand expected rc=2 (non-POSIX answer)bin/fm-herdr-lab.sh teardownof the lab session, then removed the temp folderbash tests/zz-tmp-lease-subset.test.sh(temporary copy of tests/fm-spawn-herdr-lease.test.sh that runs only test_windows_probe_answer_wider_than_the_pane_is_accepted and test_windows_missing_or_malformed_probe_answer_refuses; deleted afterwards)✅ **Document** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.