ci: gate objectstack lint's i18n/missing-* warnings to zero - #1098
Merged
Conversation
`objectstack lint` only fails its exit code on rule-level errors; warnings and suggestions are printed but never gate. Most `i18n/missing-*` findings are warnings (only a default-locale gap is an error), so a translation gap could merge through fully green CI — PR #1080 shipped 25 enumerated `i18n/missing-page` warnings that way, and #1084 zeroed that debt the same day, which is what makes today the moment to gate it. Adds scripts/check-lint-i18n-gate.mjs, which runs `objectstack lint --json` and fails when any issue's rule starts with `i18n/missing-`. Wired into `pnpm verify`, both CI workflows, and covered by test/lint-i18n-gate.test.ts (synthetic-fixture cases plus a real end-to-end run against today's baseline). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NM6o28jmBgsyTRQHutn7LC
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
huangyiirene
marked this pull request as ready for review
August 11, 2026 17:29
This was referenced Aug 11, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1018
Description
objectstack lintonly fails its own exit code on rule-level errors — warnings and suggestions are printed but the process exits 0 regardless of how many there are. Mosti18n/missing-*findings are warnings (only a default-locale gap is an error), sopnpm verify'slintstep can never go red on a translation-coverage regression. PR #1080 shipped 25 enumeratedi18n/missing-pagewarnings through a greenQuality Checksrun as a dated instance of this exact gap; #1084 zeroed that debt the same day, which is why today is the moment to gate it — the baseline is zero.This PR is the app-side half described in #1018: a new CI step that asserts the
i18n/missing-*rule-hit count is zero. Making the underlying lint rule itself error-severity is apackages/lint(upstream, platform) change and is out of this repo's reach.F/Pare@objectstack/spectagged-template aliases, used productively everywhere; the card's owngrepreproduction could never return non-zero). This PR does not repeat that three-instance framing anywhere and relies only on the corrected evidence (#1060/PR #1080 as the primary, dated instance).Type of Change
Related Issues
Fixes #1018
Changes Made
scripts/check-lint-i18n-gate.mjs: runsobjectstack lint --json, filters issues whoserulestarts withi18n/missing-, and exits non-zero if that count is not zero (regardless of severity — a default-locale gap is alreadyseverity: "error"and already fails plainpnpm lint, but folding it in here too costs nothing and keeps the assertion about the rule family, not about severity plumbing).pnpm run lint:i18n-gateand wired it intopnpm verify, immediately after the existinglintstep.i18n lint gate (zero i18n/missing-*)) to both.github/workflows/ci.yml(Build and Testjob) and.github/workflows/code-quality.yml(Quality Checksjob), right afterLint metadata conventions.test/lint-i18n-gate.test.ts: synthetic-fixture subprocess runs of the real script (via a--fixtureflag (pointing at a JSON file) testing seam, so no real translation file is ever touched by the suite) covering the pass/fail/parse-error paths, plus one real end-to-end run of the script against this repo's current metadata, asserting today's true baseline is zero — so a regression is caught bypnpm testtoo, not only by the dedicated CI step.patch) — this is a tooling/CI change, not a user-visible product change, but the repo's convention is a changeset regardless.Deliberately not in scope: the ~153 other pre-existing lint warnings/suggestions in this repo (
component-props-invalid,absolute-colspan-discouraged,relationship/line-item-should-be-master-detail, etc.) are untouched — this gate only asserts thei18n/missing-*family is zero, not "no worse than yesterday" for everything else.Premise verification (measured against
origin/main@44067a0c)objectstack lint(plain, non-JSON) exit code: 0 — confirmed both by direct run and by reading@objectstack/cli'slint.js:if (errors.length > 0) process.exit(1);is the only place the non-JSON path exits non-zero; warnings/suggestions never reach it.i18n/missing-*count today: 0 (matches the PM's assumption). Total warnings: 153, suggestions: 10, total: 163 — also matches. (10 PRs merged today per the dispatch note; re-measured live rather than trusting the assumption.)--jsonis machine-readable and reliable:{ passed, total, errors, warnings, suggestions, hiddenPlatform, issues: [{ severity, rule, message, path, fix? }] }. Rule ids for the i18n family follow the patterni18n/missing-${source}(i18n/missing-page,i18n/missing-view,i18n/missing-section, …), confirmed by reading@objectstack/cli/dist/commands/lint.jsand.../utils/i18n-coverage.jsdirectly. This made "count hits by rule name" viable exactly as PM's suggested route proposed, no redesign needed.Reverse verification — the gate must be provable to go red
Per this card's binding clause, I deliberately manufactured a violation and confirmed the new gate fails while the underlying
objectstack lintprocess does not.Isolation, since
src/translations/**is explicitly off-limits (#597 concurrently editing those four files) andsrc/is off-limits entirely for this PR's diff: I made a disposable, fully-isolated copy of this worktree (tarcopy, excludingnode_modules/.git, withnode_modulessymlinked back in) under/tmp, ran the baseline there to confirm parity with the real tree, temporarily deleted one already-translated view label from the copy'ssrc/translations/ja-JP.ts, ran both the real CLI and the new gate against the copy, then deleted the whole copy. The real worktree'ssrc/translations/**was never written to — confirmed withgit status --porcelain src/translations/(clean) and adiffagainstorigin/main's copy of the file (identical) immediately afterward.Sandbox baseline (parity check):
Violation injected (
_views.at_risk_accountslabel removed from the copy'sja-JP.ts):New gate against the same violation:
That is exactly the split #1018 describes:
objectstack lintitself stayed at exit 0 on the injected gap; the new gate caught it and exited 1.Real-repo cleanliness after the sandbox exercise:
Testing
pnpm exec vitest run test/lint-i18n-gate.test.ts(under the shared verify lock): 6 passed (6), including the real end-to-end run asserting today'si18n/missing-*count is 0.pnpm run lint(153 warnings / 10 suggestions, unchanged baseline, exit 0) and the newpnpm run lint:i18n-gate(0i18n/missing-*, exit 0).pnpm run typecheck(tsc --noEmit), no output, exit 0.pnpm run hygiene(source-hygiene gate), clean.src/,objectstack.config.ts, or runtime code touched;pnpm typecheck+ the targeted vitest file are the load-bearing checks for a CI-only change). Fullpnpm verifyis left to CI's real gate-job run.test/lint-i18n-gate.test.ts(6 cases: 4 synthetic-fixture pass/fail/parse-error paths via the script's--fixtureseam, 1 unrelated-rule-family guard, 1 real end-to-end run against current metadata).objectstack lintprocess does not fail on.CI on this PR (first-round observation)
I cannot idle-poll CI convergence (out of scope for this card's report timing), but this PR's own diff is the CI config change, so noting what I could see at draft-PR time: both
ci.yml'sBuild and Testjob andcode-quality.yml'sQuality Checksjob now carry the newi18n lint gate (zero i18n/missing-*)step right afterLint metadata conventions. Locally, the exact command those steps run (pnpm run lint:i18n-gate) passes cleanly againstorigin/main's current metadata (see Premise verification above) — I expect both jobs' new step to be green on this PR's own run, but have not observed the live run's conclusion; that read is the PM's per the standard reporting contract.Checklist
.changeset/i18n-lint-zero-tolerance-gate.md)scripts/check-source-hygiene.mjs's header-comment / CI-step-comment conventions)i18n/missing-*)Additional Notes
File surface for this PR:
.github/workflows/ci.yml,.github/workflows/code-quality.yml,package.json(scripts only),scripts/check-lint-i18n-gate.mjs,test/lint-i18n-gate.test.ts,.changeset/i18n-lint-zero-tolerance-gate.md. No file undersrc/(includingsrc/translations/**) was committed or left modified.Generated by Claude Code