Skip to content

CI does not run pnpm lint:i18n-gate — the one gate that catches a missing translation key is the one a human has to remember #67

Description

@zhuangjianguo

The gap

.github/workflows/ci.yml runs three gates:

- run: pnpm validate
- run: pnpm lint
- run: pnpm typecheck

pnpm lint:i18n-gate is not among them. It exists as a script, scripts/check-lint-i18n-gate.mjs implements it, and every dev this session ran it by hand — but nothing makes it unskippable.

Why that is the wrong one to leave out

The workflow's own header says what it is for:

ObjectStack metadata fails SILENTLY at runtime, not at edit time … objectstack validate is where that class surfaces — and running it is something a human, or an AI agent authoring metadata in this project, has to remember. This workflow is what makes it unskippable.

A missing translation key is precisely that class. It raises nothing, passes validate, passes lint, passes typecheck, and surfaces as a raw key or an English string in front of a zh-CN user — the exact failure mode this repository has already had to route upstream twice this week (objectstack-ai/objectstack#17344, #13469). The gate that catches it is the one left to memory.

It is also a two-locale repo by rule (DESIGN.md §11: en default · zh-CN), and the i18n gate is the only check that both bundles stayed in step. src/translations/en/app.ts and src/translations/zh-CN/app.ts are edited together on nearly every card that touches a user-visible string — three times this session alone (#48/PR #57, #59/PR #62, and the widget description in each). Nothing in CI notices if one of them is forgotten.

What it is not

Not a CLAUDE.md violation. CLAUDE.md's ⛔ rule names exactly three gates — pnpm validate && pnpm lint && pnpm typecheck — and CI matches that contract precisely. This card proposes widening the contract, not enforcing an existing one.

Not currently broken. Measured on 296fab8: the gate passes — 0 missing keys across 2 locale(s), 1541 keys expected, 12 surface classes walked. This is about the next PR, not this tree.

The change

Add one step to the verify job, after pnpm typecheck:

- run: pnpm lint:i18n-gate

Consider whether CLAUDE.md's inlined gate sentence should name four gates rather than three so the two stay in step — ⚠️ but CLAUDE.md is a governed surface, so if you conclude it should, say so and ⛔ leave it to a separate maintainer-merged PR rather than folding it in here. AGENTS.md is governed too; check whether it states the gate set anywhere and report, do not edit.

Also check package.json's verify script: if it composes the gate list, it should agree with CI, and if it already includes the i18n gate then the divergence is CI's alone and worth saying so in the PR body.

Acceptance

  • The new step runs in CI and is green on the PR's own head — which is self-demonstrating: this PR's CI run is the evidence.
  • All four gates 0 locally, exit codes captured before any pipe.
  • Verify the step actually fails when it should: make a missing key locally (delete one leaf from src/translations/zh-CN/app.ts), show the gate exits non-zero and names the key, then restore and show the tree is byte-identical (git diff empty). A gate nobody has watched fail is not known to be a gate — that reverse check is the deliverable here, more than the one-line diff.
  • ⛔ Do not touch any governed surface. ⛔ Do not reorganise the workflow, add jobs, add caching, or "modernise" action versions — one step, in the existing job.
  • No browser run owed.

Provenance

Found by the PM seat while answering a maintainer question about why this project's PRs merge quickly. The honest answer is that CI here is three metadata gates at ~30 seconds and there is no test suite at all in the repository (.test. / .spec. / __tests__ matches: 0) — which makes the gates that do exist carry more weight than usual, and makes an omitted one cost more than it would elsewhere.

Related

.github/workflows/ci.yml · scripts/check-lint-i18n-gate.mjs · CLAUDE.md's three-gate rule (governed) · objectstack-ai/objectstack#17344 · #13469 (the i18n failure class, upstream)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions