Found while shipping #216. Filed unassigned.
Notation: this repo's issue-body sanitizer strips angle brackets and decodes HTML numeric character references, including inside code fences. So glob wildcards are written out as words where a bracket would otherwise appear, and no placeholder uses angle brackets.
The reading
#216 introduced .github/scripts/lib/derived-locales.mjs, a shared leaf module holding DERIVED_FROM — the fact that zh-Hant is generated from zh-Hans. Both check-translations.mjs and check-translation-output.mjs import it.
.github/workflows/translations.yml triggers on:
paths:
- 'content/docs/**'
- 'apps/docs/lib/i18n.ts'
- '.github/scripts/check-translation*.mjs'
- '.github/workflows/translations.yml'
.github/scripts/check-translation*.mjs does not match .github/scripts/lib/derived-locales.mjs — the * wildcard does not cross a path separator, and the basename does not start with check-translation in any case. So a PR that edits only the shared module does not run the Ownership & freshness job at all: no freshness report, no corpus-wide output gate.
Why it matters, and why it is bounded
The exposure is real but partial. ci.yml carries no path filter, so pnpm turbo run test still runs on such a PR, and turbo.json names $TURBO_ROOT$/.github/scripts/** as an input to the test task — a glob that does cross into lib/. Both scripts' --self-test therefore still execute, including the derived-locale fixtures. What a lib/-only PR skips is the run against the real corpus.
So the failure mode is narrow: a change to DERIVED_FROM that the fixtures accept but the corpus would not — adding a locale to the map that is not in i18n.ts is caught by the self-tests, but, for example, retiring the zh-Hant entry would silently return 65 items to the worklist and no workflow on that PR would report it.
The fix
Widen the filter to .github/scripts/**, matching what turbo.json already declares for the test task. That also removes a second, quieter mismatch: check-locale-surface.mjs and check-node-floor.mjs are equally unmatched by the current pattern today, though neither is consumed by this workflow.
Worth checking as one job rather than one line — a path filter that is narrower than the task's declared inputs is a class, not an instance.
Not a regression in #216
The #216 PR itself edits both check-translation*.mjs files, so the Translations workflow runs on it normally. This is about future edits to the shared module.
Found while shipping #216. Filed unassigned.
Notation: this repo's issue-body sanitizer strips angle brackets and decodes HTML numeric character references, including inside code fences. So glob wildcards are written out as words where a bracket would otherwise appear, and no placeholder uses angle brackets.
The reading
#216 introduced
.github/scripts/lib/derived-locales.mjs, a shared leaf module holdingDERIVED_FROM— the fact thatzh-Hantis generated fromzh-Hans. Bothcheck-translations.mjsandcheck-translation-output.mjsimport it..github/workflows/translations.ymltriggers on:.github/scripts/check-translation*.mjsdoes not match.github/scripts/lib/derived-locales.mjs— the*wildcard does not cross a path separator, and the basename does not start withcheck-translationin any case. So a PR that edits only the shared module does not run theOwnership & freshnessjob at all: no freshness report, no corpus-wide output gate.Why it matters, and why it is bounded
The exposure is real but partial.
ci.ymlcarries no path filter, sopnpm turbo run teststill runs on such a PR, andturbo.jsonnames$TURBO_ROOT$/.github/scripts/**as an input to thetesttask — a glob that does cross intolib/. Both scripts'--self-testtherefore still execute, including the derived-locale fixtures. What alib/-only PR skips is the run against the real corpus.So the failure mode is narrow: a change to
DERIVED_FROMthat the fixtures accept but the corpus would not — adding a locale to the map that is not ini18n.tsis caught by the self-tests, but, for example, retiring thezh-Hantentry would silently return 65 items to the worklist and no workflow on that PR would report it.The fix
Widen the filter to
.github/scripts/**, matching whatturbo.jsonalready declares for thetesttask. That also removes a second, quieter mismatch:check-locale-surface.mjsandcheck-node-floor.mjsare equally unmatched by the current pattern today, though neither is consumed by this workflow.Worth checking as one job rather than one line — a path filter that is narrower than the task's declared inputs is a class, not an instance.
Not a regression in #216
The #216 PR itself edits both
check-translation*.mjsfiles, so the Translations workflow runs on it normally. This is about future edits to the shared module.