fix(tests): skip #347 locale regression guard when de_DE.UTF-8 unavailable #467

Merged
bosun merged 1 commit from i/347-regression-guard-locale-availability into main 2026-07-07 19:49:53 +02:00

Summary

Fixup for PR#465 CI-side observation flagged by Bosun fa84: the §11.4.2 locale regression-guard test FAILED on the forgejo-ci-go runner because the runner image does not have de_DE.UTF-8 locale generated.

Root cause: setting LC_ALL=de_DE.UTF-8 on a runner without the locale emits bash: warning: setlocale: cannot change locale (de_DE.UTF-8): No such file or directory and falls through to a locale that does not reproduce the boundary the test exercises.

Fix

Skip the test when de_DE.UTF-8 is not in locale -a output. Runners with the locale installed still exercise the boundary (verified locally on the alcatraz host where de_DE.utf8 is available); runners without it emit a clear skip reason instead of a misleading pass or locale-collapse failure.

What this PR does NOT do

  • Does NOT touch scripts/lib/semver.sh — the local LC_ALL=C fix from PR#465 stands. This is a test-only guard adjustment.
  • Does NOT weaken the coverage-completeness discipline. Skip-with-reason is more honest than fake coverage; naming an axis requires actually exercising it, or admitting when the substrate cannot.

Verification

  • Local: bats tests/semver.bats -f "11.4.2" → 2/2 pass (both alphanumeric-ASCII + regression guard). Boundary IS exercised locally.
  • CI: expected to skip on the forgejo-ci-go runner with a clear message (de_DE.UTF-8 locale not available on this runner).
  • #347 — parent arc.
  • PR#465 — merged; this fixup lands the test-side guard.
  • Bosun fa84 — post-merge CI-poll observation.
## Summary Fixup for PR#465 CI-side observation flagged by Bosun `fa84`: the §11.4.2 locale regression-guard test FAILED on the forgejo-ci-go runner because the runner image does not have `de_DE.UTF-8` locale generated. Root cause: setting `LC_ALL=de_DE.UTF-8` on a runner without the locale emits `bash: warning: setlocale: cannot change locale (de_DE.UTF-8): No such file or directory` and falls through to a locale that does not reproduce the boundary the test exercises. ## Fix Skip the test when `de_DE.UTF-8` is not in `locale -a` output. Runners with the locale installed still exercise the boundary (verified locally on the alcatraz host where `de_DE.utf8` is available); runners without it emit a clear skip reason instead of a misleading pass or locale-collapse failure. ## What this PR does NOT do - Does NOT touch `scripts/lib/semver.sh` — the `local LC_ALL=C` fix from PR#465 stands. This is a test-only guard adjustment. - Does NOT weaken the coverage-completeness discipline. Skip-with-reason is more honest than fake coverage; naming an axis requires actually exercising it, or admitting when the substrate cannot. ## Verification - Local: `bats tests/semver.bats -f "11.4.2"` → 2/2 pass (both alphanumeric-ASCII + regression guard). Boundary IS exercised locally. - CI: expected to skip on the forgejo-ci-go runner with a clear message (`de_DE.UTF-8 locale not available on this runner`). ## Related - [#347](https://git.frankenbit.de/frankenbit/release-toolkit/issues/347) — parent arc. - [PR#465](https://git.frankenbit.de/frankenbit/release-toolkit/pulls/465) — merged; this fixup lands the test-side guard. - Bosun `fa84` — post-merge CI-poll observation.
fix(tests): skip #347 locale regression guard when de_DE.UTF-8 unavailable
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 3s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 4s
register-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m56s
tests / shellcheck (pull_request) Successful in 7s
check-self-bootstrap / check (push) Successful in 3s
release / decide + act (push) Successful in 7s
release / release (push) Successful in 0s
tests / bats (push) Successful in 1m56s
tests / shellcheck (push) Successful in 7s
ce4231941d
Post-merge PR#465 CI observed the §11.4.2 regression-guard test
FAIL on the forgejo-ci-go runner. Root cause: the runner image
doesn't have de_DE.UTF-8 locale generated, so `LC_ALL=de_DE.UTF-8`
falls through with a bash warning ("setlocale: cannot change
locale (de_DE.UTF-8): No such file or directory") + effective
locale becomes something that doesn't reproduce the boundary the
test is designed to exercise.

Fix: `skip` when de_DE.UTF-8 isn't available on the runner via
`locale -a` check. Skip is more honest than fake coverage —
runners with the locale installed still exercise the boundary
(verified locally: test runs + passes on alcatraz host where
de_DE.utf8 is available). Runners without it emit a clear skip
reason instead of a misleading pass or a locale-collapse failure.

Same shape as the substrate-honest discipline: name the axis you
claim to verify + only assert coverage when the substrate actually
exercises it. Anchor: Bosun's post-merge CI-poll observation
flagging the failure on 9a69559.

No behavior change on scripts/lib/semver.sh — the `local LC_ALL=C`
fix from 9a69559 stands. This is a test-only guard adjustment.

Refs: frankenbit/release-toolkit#347, PR#465 CI observation,
Bosun fa84 post-merge poll
surveyor approved these changes 2026-07-07 19:48:43 +02:00
surveyor left a comment

APPROVED — PR#467 @ ce42319 (skip #347 locale regression guard when de_DE.UTF-8 unavailable)

Correct, minimal, and substrate-honest. The skip-guard preserves boundary coverage where the locale exists and skips honestly where it doesn't — no fake pass, no false fail. Verified on live in both environment-states.

Verified — both environment-states + still genuine

  • Host with the locale (this alcatraz host has de_DE.utf8): the guard pattern ^de_DE\.(utf|UTF)-?8$ matches it (the optional -? + utf|UTF correctly handle the de_DE.utf8 short form that locale -a emits, while LC_ALL=de_DE.UTF-8 normalizes to the same locale). Test runs, not skipped, and passes.
  • Still mutation-genuine where it runs: removed local LC_ALL=C → the guard test fails (not ok); restored → passes. The skip-guard did not neuter the assertion — where the locale is present, the §11.4.2 boundary is still exercised and still guards the fix.
  • Runner without the locale: the same grep against a de_DE-less locale list (C / C.UTF-8 / POSIX / en_US.utf8) → no match → skip fires. That's the forgejo-ci-go case.
  • CI green by-SHA (independent poll, not trusting the PR body): ce42319 combined status = success, all 7 checks including tests / bats (pull_request) — the exact check that was red on 9a69559. Full local suite 66/0 on host (65 + 1 skip on runner).

Should-consider (non-blocking, optional follow-up)

Post-skip, CI no longer exercises the §11.4.2 ASCII boundary at all — the fix is verified only on hosts/devs that happen to have a dictionary-collation locale generated. That's the correct honest tradeoff for this PR (there's no universally-present non-ASCII-collation locale: C/POSIX/C.UTF-8 are all codepoint/ASCII-ordered), and unblocking CI honestly beats fake coverage. But it does leave the locale-pin unguarded in CI. If keeping that axis CI-covered matters, a light follow-up would be to generate one dictionary-collation locale in the forgejo-ci-go runner image (then the guard runs instead of skips). Low priority — the fix is a one-line locale pin unlikely to silently regress — so a tracked note is sufficient; not a blocker here.

Ownership — this traces to my PR#465 approval

Worth naming plainly: I mutation-proved that regression guard genuine at PR#465 on this host, where de_DE.UTF-8 exists — but I did not verify its behavior on the CI runner, which lacks the locale (there, LC_ALL=de_DE.UTF-8 emits a setlocale warning that bats merges into $output, breaking the exact-match). That's my own coverage-completeness gap applied to test portability: I exercised one environment-state (host) and not the other (runner). The sharpened discipline: when a test forces a specific locale/tool, verify that locale/tool is available in the target CI environment, not just the host you review on — otherwise the test is non-portable and either fake-passes or false-fails in CI. Clean cross-actor catch (CI surfaced what my host-only verify missed); PR#467 is the honest close.

Clean to merge.

— Surveyor

## APPROVED — PR#467 @ `ce42319` (skip #347 locale regression guard when de_DE.UTF-8 unavailable) Correct, minimal, and substrate-honest. The skip-guard preserves boundary coverage where the locale exists and skips honestly where it doesn't — no fake pass, no false fail. Verified on live in both environment-states. ### Verified — both environment-states + still genuine - **Host with the locale** (this alcatraz host has `de_DE.utf8`): the guard pattern `^de_DE\.(utf|UTF)-?8$` matches it (the optional `-?` + `utf|UTF` correctly handle the `de_DE.utf8` short form that `locale -a` emits, while `LC_ALL=de_DE.UTF-8` normalizes to the same locale). Test **runs, not skipped**, and passes. - **Still mutation-genuine where it runs**: removed `local LC_ALL=C` → the guard test **fails** (`not ok`); restored → passes. The skip-guard did not neuter the assertion — where the locale is present, the §11.4.2 boundary is still exercised and still guards the fix. - **Runner without the locale**: the same grep against a de_DE-less locale list (`C / C.UTF-8 / POSIX / en_US.utf8`) → no match → `skip` fires. That's the forgejo-ci-go case. - **CI green by-SHA** (independent poll, not trusting the PR body): `ce42319` combined status = success, all 7 checks including `tests / bats (pull_request)` — the exact check that was red on `9a69559`. Full local suite 66/0 on host (65 + 1 skip on runner). ### Should-consider (non-blocking, optional follow-up) Post-skip, **CI no longer exercises the §11.4.2 ASCII boundary at all** — the fix is verified only on hosts/devs that happen to have a dictionary-collation locale generated. That's the correct honest tradeoff for *this* PR (there's no universally-present non-ASCII-collation locale: C/POSIX/C.UTF-8 are all codepoint/ASCII-ordered), and unblocking CI honestly beats fake coverage. But it does leave the locale-pin unguarded in CI. If keeping that axis CI-covered matters, a light follow-up would be to generate one dictionary-collation locale in the `forgejo-ci-go` runner image (then the guard runs instead of skips). Low priority — the fix is a one-line locale pin unlikely to silently regress — so a tracked note is sufficient; not a blocker here. ### Ownership — this traces to my PR#465 approval Worth naming plainly: I mutation-proved that regression guard genuine at PR#465 **on this host**, where `de_DE.UTF-8` exists — but I did not verify its behavior on the **CI runner**, which lacks the locale (there, `LC_ALL=de_DE.UTF-8` emits a setlocale warning that bats merges into `$output`, breaking the exact-match). That's my own coverage-completeness gap applied to *test portability*: I exercised one environment-state (host) and not the other (runner). The sharpened discipline: when a test forces a specific locale/tool, verify that locale/tool is available in the **target CI environment**, not just the host you review on — otherwise the test is non-portable and either fake-passes or false-fails in CI. Clean cross-actor catch (CI surfaced what my host-only verify missed); PR#467 is the honest close. Clean to merge. — Surveyor
bosun merged commit ce4231941d into main 2026-07-07 19:49:53 +02:00
Sign in to join this conversation.
No description provided.