bug(windows): native go test ./... still fails on an LF checkout — cmd/rt does not build, and POSIX-only tests run unguarded #1501

Closed
opened 2026-10-02 11:31:32 +02:00 by claude · 1 comment
Member

#1485 fixed the line endings. On its LF checkout, a native Windows go test ./... still fails, for Windows causes #1485 listed as out of scope. Release binaries are linux/amd64 only, so this is about contributors developing on Windows.

Measured 2026-10-02 at 55a12b9 (live main): a fresh clone under the system core.autocrlf=true (622 w/lf, 0 w/crlf), Go 1.27.1 on Windows 11, Git for Windows bash 5.3.15 (MSYS runtime). The same tree passes all 29 packages in golang:1.25.

build failed
  internal/release, cmd/rt   lock.go: syscall.Flock / LOCK_EX / LOCK_NB / LOCK_UN are undefined on windows

failing
  internal/register  TestScanTree
                     hits reported as docs\guide.md; the allow-list dir docs/internal/ never matches
  internal/wrappers  TestRepinFile_PreservesModeAndSkipsNoMatch
                     mode = -rw-rw-rw-, want 0640
  internal/wrappers  TestDiscoverUnreadableIsUngradeable
                     unreadable file must be ungradeable, got 0
  internal/prep      TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential
                     post_bump_hook not executable: hook.sh
  internal/gates     TestHeaderEmDashLocaleAndByteClassMutation
                     byte-class mutant did not reproduce the UTF-8 control under LC_ALL=C.utf8

With only the lock build failure fixed, cmd/rt compiles and shows four more failures that were hidden behind it:

  TestChangelogBodyCheckBadThreshold            builds "rt" without .exe: executable file not found
  TestFragmentCheckSummaryWordWarnExecutes      a C:\ temp path is outside the annotation safe-char set,
  TestFragmentCheckLengthWarnCountsRunes          so the warning correctly takes the stderr fallback
  TestPrepStagesTheRegeneratedTwinIntoTheIndex  looks up git's '/' index paths with filepath.Join keys

There is also one arm that passes for the wrong reason: TestWritePostCutManifestCustomTagFormat/config_is_UNREADABLE_by_mode_is_could_not_grade. On Windows, chmod 0o000 leaves the config readable. A probe run logged the error the arm saw: the unrelated manifest-in-history refusal.

TestPushManifestAuthedRejectsSecondPush failed once under parallel load. Its 2s deadline cancelled attempt 2 before the pre-push hook ran; the error text still matched, and the attempt counter read "x", not "xx". It passes uncontended.

Causes

  • Lock. flock is unix-only. A Windows backend must keep the ErrConcurrentCut semantics (#499): non-blocking; held per open file, so a second acquire in the same process contends (TestNewCutter_concurrentCut relies on this); released by the OS when the holder dies.
  • ScanTree. This is a real rt register-check bug on Windows. filepath.WalkDir yields paths with the OS separator, while allow-list entries and selfExcluded keys are written with /.
  • POSIX semantics. Windows has no mode bits beyond read-only and no executable bit, and cannot exec a #!/bin/sh hook.
  • MSYS regex. Under C.utf8, [—] matches an em-dash but [-—], [—-] and [éa] do not. The mutant is therefore rejected in every locale, and its UTF-8 control cannot be reproduced.

Acceptance criteria

  • internal/release and cmd/rt build on Windows. A Windows lock backend returns ErrConcurrentCut on contention, both in-process and cross-process, and the lock is freed when the holder is killed. — DONE @ #1505 (b47a824, reviewed as 8e2cf58). On 96d2646, natively: TestNewCutter_concurrentCut, TestAcquireLock_anotherProcessHoldsIt and TestAcquireLock_killedHolderDoesNotStrandTheLock PASS.
  • On Windows, ScanTree matches allow-list and self-exclusion entries in / form and reports hits that way. Linux output is unchanged. — DONE @ #1505 (90ef268, reviewed as 6aef15b). TestScanTree and the new TestScanTreeExplicitOSPath PASS natively and in golang:1.25.
  • Tests that need POSIX mode bits, an executable bit or glibc regex skip on Windows with a reason in the existing t.Skip style, and still run (not skip) on Linux. — DONE, exceeded, @ #1505 (96d2646 and 25d0c0b, reviewed as ca66a11 and 0ac9790). Only two arms skip on Windows, each with a reason: TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential (rt prep now refuses hooks there by name) and the mutant/C.utf8 subtest. The 0o000 arms and the repin mode check are graded on Windows instead, through a per-OS makeUnreadable and a 0666 expectation. Every one of these PASSES, unskipped, in golang:1.25 as a non-root user.
  • The four cmd/rt path and .exe assumptions are fixed in the tests, not skipped. — DONE @ #1505 (96d2646, reviewed as ca66a11). TestChangelogBodyCheckBadThreshold (rt.exe), TestFragmentCheckSummaryWordWarnExecutes and TestFragmentCheckLengthWarnCountsRunes (relative dir), and TestPrepStagesTheRegeneratedTwinIntoTheIndex (slash keys) PASS natively, none skipped.
  • Native Windows go test ./... passes on an LF checkout, and golang:1.25 stays green when run as non-root. — DONE @ #1505 (96d2646, reviewed as ca66a11). Fresh clone of 96d2646 under the system core.autocrlf=true: go test -count=1 ./... is 29/29 ok natively (Git Bash, Go 1.27.1) and 29/29 in golang:1.25 as a non-root user.

Out of scope

  • Windows release binaries (.goreleaser.yaml stays linux/amd64) and Windows release runners (Phase 8).
  • The post-cut 0o000 arm asserts only err != nil. Asserting the could-not-read message, as its directory sibling does, would close the wrong-reason pass on every OS. Not measured on Linux.

Anchor

Baseline: a fresh clone of 55a12b9. The four cmd/rt failures were measured on an LF tree of 02fae6a with only the lock split applied.

#1485 fixed the line endings. On its LF checkout, a native Windows `go test ./...` still fails, for Windows causes #1485 listed as out of scope. Release binaries are linux/amd64 only, so this is about contributors developing on Windows. Measured 2026-10-02 at `55a12b9` (live `main`): a fresh clone under the system `core.autocrlf=true` (622 `w/lf`, 0 `w/crlf`), Go 1.27.1 on Windows 11, Git for Windows bash 5.3.15 (MSYS runtime). The same tree passes all 29 packages in `golang:1.25`. ``` build failed internal/release, cmd/rt lock.go: syscall.Flock / LOCK_EX / LOCK_NB / LOCK_UN are undefined on windows failing internal/register TestScanTree hits reported as docs\guide.md; the allow-list dir docs/internal/ never matches internal/wrappers TestRepinFile_PreservesModeAndSkipsNoMatch mode = -rw-rw-rw-, want 0640 internal/wrappers TestDiscoverUnreadableIsUngradeable unreadable file must be ungradeable, got 0 internal/prep TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential post_bump_hook not executable: hook.sh internal/gates TestHeaderEmDashLocaleAndByteClassMutation byte-class mutant did not reproduce the UTF-8 control under LC_ALL=C.utf8 ``` With only the lock build failure fixed, `cmd/rt` compiles and shows four more failures that were hidden behind it: ``` TestChangelogBodyCheckBadThreshold builds "rt" without .exe: executable file not found TestFragmentCheckSummaryWordWarnExecutes a C:\ temp path is outside the annotation safe-char set, TestFragmentCheckLengthWarnCountsRunes so the warning correctly takes the stderr fallback TestPrepStagesTheRegeneratedTwinIntoTheIndex looks up git's '/' index paths with filepath.Join keys ``` There is also one arm that passes for the wrong reason: `TestWritePostCutManifestCustomTagFormat/config_is_UNREADABLE_by_mode_is_could_not_grade`. On Windows, `chmod 0o000` leaves the config readable. A probe run logged the error the arm saw: the unrelated manifest-in-history refusal. `TestPushManifestAuthedRejectsSecondPush` failed once under parallel load. Its 2s deadline cancelled attempt 2 before the pre-push hook ran; the error text still matched, and the attempt counter read `"x"`, not `"xx"`. It passes uncontended. ## Causes - **Lock.** flock is unix-only. A Windows backend must keep the `ErrConcurrentCut` semantics (#499): non-blocking; held per open file, so a second acquire in the same process contends (`TestNewCutter_concurrentCut` relies on this); released by the OS when the holder dies. - **`ScanTree`.** This is a real `rt register-check` bug on Windows. `filepath.WalkDir` yields paths with the OS separator, while allow-list entries and `selfExcluded` keys are written with `/`. - **POSIX semantics.** Windows has no mode bits beyond read-only and no executable bit, and cannot exec a `#!/bin/sh` hook. - **MSYS regex.** Under `C.utf8`, `[—]` matches an em-dash but `[-—]`, `[—-]` and `[éa]` do not. The mutant is therefore rejected in every locale, and its UTF-8 control cannot be reproduced. ## Acceptance criteria - [x] `internal/release` and `cmd/rt` build on Windows. A Windows lock backend returns `ErrConcurrentCut` on contention, both in-process and cross-process, and the lock is freed when the holder is killed. — DONE @ #1505 (`b47a824`, reviewed as `8e2cf58`). On `96d2646`, natively: `TestNewCutter_concurrentCut`, `TestAcquireLock_anotherProcessHoldsIt` and `TestAcquireLock_killedHolderDoesNotStrandTheLock` PASS. - [x] On Windows, `ScanTree` matches allow-list and self-exclusion entries in `/` form and reports hits that way. Linux output is unchanged. — DONE @ #1505 (`90ef268`, reviewed as `6aef15b`). `TestScanTree` and the new `TestScanTreeExplicitOSPath` PASS natively and in `golang:1.25`. - [x] Tests that need POSIX mode bits, an executable bit or glibc regex skip on Windows with a reason in the existing `t.Skip` style, and still run (not skip) on Linux. — DONE, exceeded, @ #1505 (`96d2646` and `25d0c0b`, reviewed as `ca66a11` and `0ac9790`). Only two arms skip on Windows, each with a reason: `TestRunPostBumpHooks_theHookDoesNotReceiveTheGitCredential` (`rt prep` now refuses hooks there by name) and the `mutant/C.utf8` subtest. The `0o000` arms and the repin mode check are graded on Windows instead, through a per-OS `makeUnreadable` and a `0666` expectation. Every one of these PASSES, unskipped, in `golang:1.25` as a non-root user. - [x] The four `cmd/rt` path and `.exe` assumptions are fixed in the tests, not skipped. — DONE @ #1505 (`96d2646`, reviewed as `ca66a11`). `TestChangelogBodyCheckBadThreshold` (`rt.exe`), `TestFragmentCheckSummaryWordWarnExecutes` and `TestFragmentCheckLengthWarnCountsRunes` (relative dir), and `TestPrepStagesTheRegeneratedTwinIntoTheIndex` (slash keys) PASS natively, none skipped. - [x] Native Windows `go test ./...` passes on an LF checkout, and `golang:1.25` stays green when run as non-root. — DONE @ #1505 (`96d2646`, reviewed as `ca66a11`). Fresh clone of `96d2646` under the system `core.autocrlf=true`: `go test -count=1 ./...` is 29/29 ok natively (Git Bash, Go 1.27.1) and 29/29 in `golang:1.25` as a non-root user. ## Out of scope - Windows release binaries (`.goreleaser.yaml` stays linux/amd64) and Windows release runners (Phase 8). - The post-cut `0o000` arm asserts only `err != nil`. Asserting the could-not-read message, as its directory sibling does, would close the wrong-reason pass on every OS. Not measured on Linux. ## Anchor Baseline: a fresh clone of `55a12b9`. The four `cmd/rt` failures were measured on an LF tree of `02fae6a` with only the lock split applied.
Author
Member

Landed through #1505 (tracker #1502), not #1503: the operator merged #1505, the competing PR for the same defect. All five acceptance criteria hold on live main and are ticked above with the landed and reviewed SHAs.

  • Landed vs reviewed: git range-diff 8e2cf58^..ca66a11 b47a824^..96d2646 shows all four commits as =.
  • Approval: none effective. #1505's only review row is a review request, and its landing identity record (comment 114368) reads "effective official approval(s): none effective at record time". alex merged it at 22:19.
  • Checks: the combined status on 96d2646 is success, 16 of 16.
  • Measured on a fresh clone of 96d2646: 29/29 natively on Windows and 29/29 in golang:1.25 as a non-root user. The tests named in the criteria PASS on both, apart from the two Windows skips the third criterion names.

The second out-of-scope item landed too: #1505 makes the post-cut 0o000 arm assert "could not be read", which removes the wrong-reason pass on every OS.

#1503 covered the same scope and is superseded by #1505. It stays open until the operator decides on it.

Shutting this tracker by hand.

Landed through #1505 (tracker #1502), not #1503: the operator merged #1505, the competing PR for the same defect. All five acceptance criteria hold on live `main` and are ticked above with the landed and reviewed SHAs. - **Landed vs reviewed:** `git range-diff 8e2cf58^..ca66a11 b47a824^..96d2646` shows all four commits as `=`. - **Approval:** none effective. #1505's only review row is a review request, and its landing identity record (comment 114368) reads "effective official approval(s): none effective at record time". alex merged it at 22:19. - **Checks:** the combined status on `96d2646` is success, 16 of 16. - **Measured on a fresh clone of `96d2646`:** 29/29 natively on Windows and 29/29 in `golang:1.25` as a non-root user. The tests named in the criteria PASS on both, apart from the two Windows skips the third criterion names. The second out-of-scope item landed too: #1505 makes the post-cut `0o000` arm assert "could not be read", which removes the wrong-reason pass on every OS. #1503 covered the same scope and is superseded by #1505. It stays open until the operator decides on it. Shutting this tracker by hand.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frankenbit/release-toolkit#1501
No description provided.