Skip to content

fix(i18n): drop shebangs that break test collection on Windows - #2378

Merged
bolichen97 merged 1 commit into
kirodotdev:mainfrom
k33bz:fix/scripts-shebang-breaks-windows
Aug 9, 2026
Merged

fix(i18n): drop shebangs that break test collection on Windows#2378
bolichen97 merged 1 commit into
kirodotdev:mainfrom
k33bz:fix/scripts-shebang-breaks-windows

Conversation

@k33bz

@k33bz k33bz commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Problem / Motivation

scripts/check-i18n-strings.mjs and scripts/i18n-translate.mjs open with
#!/usr/bin/env node. Four i18n tests import them. On Windows, Vite's CJS interop
prepends its generated requires to line 1, which leaves the shebang sitting after
executable code:
const fileURLToPath = __vite__cjsImport3_node_url["fileURLToPath"];#!/usr/bin/env node
^ Invalid Character !

Rolldown fails the parse, and the importing file collects zero tests, reporting
no tests rather than a red assertion.

Why it matters

Four gates stop gating on Windows, silently:

What changed (motivation → approach → change)

Root cause: a shebang is only legal on line 1, and the CJS transform takes line 1.
Change: delete both shebangs. They were decorative. Both files are mode 100644
(not executable) and every invocation goes through node scripts/<name>.mjs from
package.json, so nothing could have executed them directly. The modules already
extracted so gates can be shared with tests, scripts/lib/*.mjs, carry none, which is
the pattern this follows.
Guard: src/test/scriptsShebang.test.ts asserts that no script under scripts/
imported from src/ opens with #!. A Linux-only CI cannot see this class of bug, so
a convention would not survive it.
Considered and not done: moving the imported exports into scripts/lib/ the way
qa-checks.mjs did. That is arguably the better end state, but it touches four test
files and two scripts to fix a two-line defect. Happy to follow up if preferred.

Tests

src/test/scriptsShebang.test.ts, two assertions:

  • no imported script opens with a shebang. Mutation-checked: restoring either
    shebang fails it and names the file.
  • the discovered import set is non-empty, so a future move behind scripts/lib/
    cannot make the guard vacuously green.

Manual verification

Check Windows Linux
4 affected suites + guard 0 collected → 119 passed 119 passed
Full src/i18n/ suite 597 passed
npm run check 864 files passed
npm run lint:i18n normal report, exit 0
node scripts/i18n-translate.mjs prints usage, exits clean
The last two matter most. Removing a shebang from a file that gets run is how you break
a build, so both scripts were exercised the way package.json and the docs invoke them.
One unrelated failure in the full run: unitLiterals timed out at 19.7 s under
--coverage on a 16-core box. It passes in isolation and is untouched by this diff.
Same pre-existing flake reported in #2023, #1810 and #2159.

Screenshots / video

N/A. No UI change.

Related Issues

None open for this. Adjacent Windows issues: #2297, #2301.

Checklist

  • Single commit with a Conventional Commits title
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable): N/A
  • No secrets, credentials, or internal references in the diff

check-i18n-strings.mjs and i18n-translate.mjs opened with
#!/usr/bin/env node. Four i18n tests import them, and on Windows Vite's
CJS interop prepends its generated requires to line 1, which leaves the
shebang sitting after executable code:

  const fileURLToPath = __vite__cjsImport3_node_url["fileURLToPath"];#!/usr/bin/env node

Rolldown fails the parse on the "!", and the importing file then collects
ZERO tests and reports "no tests" rather than a red assertion. So
unitLiterals, localeFormatting, untranslatedRatchet and translateDriver
stop gating anything on Windows, silently. CI is Linux-only, where the
transform leaves the shebang on its own line, so nothing catches it.

The shebangs were decorative. Both files are mode 100644, not executable,
and every invocation goes through `node scripts/<name>.mjs` from
package.json. The modules already extracted so gates can be shared with
tests, scripts/lib/*.mjs, carry none.

Add src/test/scriptsShebang.test.ts to hold the line: a script under
scripts/ imported from src/ must not open with "#!". It is
mutation-checked, so restoring either shebang fails it and names the
file. It also asserts the import set is non-empty, so a future move
behind scripts/lib/ cannot make it vacuously green.

Verified on both platforms. The four suites plus the guard go from 0
collected to 119 passed on Windows and on Linux, and `npm run lint:i18n`
and `node scripts/i18n-translate.mjs` still run.
@k33bz
k33bz requested a review from a team as a code owner August 9, 2026 16:26
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5, fork) — ✅ PASS

Advisory UX-level review of 541da895a61c600ca97c14e13efdc60c7f344915 via the fork AI-review pipeline — updated in place on each push; does not block merge.

UX-Verdict: PASS

Developer-tooling-only change — removes two script shebangs and adds a test guard; no user-facing surface, string, or rendered pixel is touched.

[UX-REVIEWED] 541da89

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review (fork) — ✅ no blocking findings

Reviewed 541da895a61c600ca97c14e13efdc60c7f344915 via the fork AI-review pipeline; updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 541da89

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5, fork) — ✅ PASS

Advisory design-level review of 541da895a61c600ca97c14e13efdc60c7f344915 via the fork AI-review pipeline — updated in place on each push; does not block merge.

Design-Verdict: PASS

Root-cause fix (shebang is only legal on line 1), verified decorative (mode 644, node-invoked), with a cross-platform guard a Linux-only CI can't provide.

[DESIGN-REVIEWED] 541da89

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review (fork) — ✅ no blocking findings

Reviewed 541da895a61c600ca97c14e13efdc60c7f344915 via the fork AI-review pipeline; updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 541da89

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 9, 2026
@bolichen97
bolichen97 enabled auto-merge (squash) August 9, 2026 18:24
@bolichen97
bolichen97 disabled auto-merge August 9, 2026 18:24
@bolichen97
bolichen97 merged commit ab20b4e into kirodotdev:main Aug 9, 2026
58 of 59 checks passed
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 9, 2026
bolichen97 added a commit that referenced this pull request Aug 9, 2026
Squashed to one commit to satisfy the Enforce single commit hygiene gate;
the per-pick provenance is preserved below. Each pick is patch-identical
to the commit already merged on main (verified with git patch-id --stable).

Requested for this RC:

- feat: opt-in Slack setup and multi-channel repositioning (#2340)
  kirocrew setup no longer walks through Slack credentials unless --slack
  is passed, plus multi-channel repositioning across docs, in-app copy,
  and all 13 locales.
  (cherry picked from commit 8f5c937)

- fix(i18n): drop shebangs that break test collection on Windows (#2378)
  (cherry picked from commit ab20b4e)

Required to make this branch green, not optional additions:

- fix(i18n): resync ko Storage catalog with the inventory model (#2306)
  release/0.2.0 already failed catalogParity > ko at 5fe4bd5 with 29
  missing and 36 orphaned pages.sessionStorage.* keys. #2208 rewrote the
  English Storage keys on this branch while its Korean resync stayed on
  main, so Korean users saw raw key names on the Storage page and every
  PR touching website/ was red.
  (cherry picked from commit 841e8b4)

- fix(i18n): match ko sort_largest spacing to the catalog convention (#2370)
  (cherry picked from commit 49aa776)

Added here:

- docs: note opt-in Slack setup in the 0.2.0 changelog. #2340 changes
  first-run behavior and the existing [0.2.0] section did not mention it.

A feat on a cut release branch is a deliberate maintainer decision, not an
oversight: CONTRIBUTING.md reserves a cut branch for bug fixes, and the
multi-channel positioning was judged the accurate story to ship in 0.2.0.
bolichen97 added a commit that referenced this pull request Aug 9, 2026
…2395)

Squashed to one commit to satisfy the Enforce single commit hygiene gate;
the per-pick provenance is preserved below. Each pick is patch-identical
to the commit already merged on main (verified with git patch-id --stable).

Requested for this RC:

- feat: opt-in Slack setup and multi-channel repositioning (#2340)
  kirocrew setup no longer walks through Slack credentials unless --slack
  is passed, plus multi-channel repositioning across docs, in-app copy,
  and all 13 locales.
  (cherry picked from commit 8f5c937)

- fix(i18n): drop shebangs that break test collection on Windows (#2378)
  (cherry picked from commit ab20b4e)

Required to make this branch green, not optional additions:

- fix(i18n): resync ko Storage catalog with the inventory model (#2306)
  release/0.2.0 already failed catalogParity > ko at 5fe4bd5 with 29
  missing and 36 orphaned pages.sessionStorage.* keys. #2208 rewrote the
  English Storage keys on this branch while its Korean resync stayed on
  main, so Korean users saw raw key names on the Storage page and every
  PR touching website/ was red.
  (cherry picked from commit 841e8b4)

- fix(i18n): match ko sort_largest spacing to the catalog convention (#2370)
  (cherry picked from commit 49aa776)

Added here:

- docs: note opt-in Slack setup in the 0.2.0 changelog. #2340 changes
  first-run behavior and the existing [0.2.0] section did not mention it.

A feat on a cut release branch is a deliberate maintainer decision, not an
oversight: CONTRIBUTING.md reserves a cut branch for bug fixes, and the
multi-channel positioning was judged the accurate story to ship in 0.2.0.
@k33bz
k33bz deleted the fix/scripts-shebang-breaks-windows branch August 14, 2026 21:37
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…otdev#2378)

check-i18n-strings.mjs and i18n-translate.mjs opened with
#!/usr/bin/env node. Four i18n tests import them, and on Windows Vite's
CJS interop prepends its generated requires to line 1, which leaves the
shebang sitting after executable code:

  const fileURLToPath = __vite__cjsImport3_node_url["fileURLToPath"];#!/usr/bin/env node

Rolldown fails the parse on the "!", and the importing file then collects
ZERO tests and reports "no tests" rather than a red assertion. So
unitLiterals, localeFormatting, untranslatedRatchet and translateDriver
stop gating anything on Windows, silently. CI is Linux-only, where the
transform leaves the shebang on its own line, so nothing catches it.

The shebangs were decorative. Both files are mode 100644, not executable,
and every invocation goes through `node scripts/<name>.mjs` from
package.json. The modules already extracted so gates can be shared with
tests, scripts/lib/*.mjs, carry none.

Add src/test/scriptsShebang.test.ts to hold the line: a script under
scripts/ imported from src/ must not open with "#!". It is
mutation-checked, so restoring either shebang fails it and names the
file. It also asserts the import set is non-empty, so a future move
behind scripts/lib/ cannot make it vacuously green.

Verified on both platforms. The four suites plus the guard go from 0
collected to 119 passed on Windows and on Linux, and `npm run lint:i18n`
and `node scripts/i18n-translate.mjs` still run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants