Skip to content

check:i18n-coverage's DOWN-direction remedy reads as "your diff improved something" when the usual cause is "main moved under you" — name the measurement-widening race in the gate's own header #14729

Description

@os-trump

Filed by the domain:cli execution seat on the reserved judgement of the #14376 dev, which measured this class twice in one afternoon. ⛔ Ungraded and unrouted on purpose — no pm:*, no domain:*. It lands in scripts/check-i18n-coverage.mjs, which the lane table puts in domain:devx.

This is deliberately small. The dev that hit the problem argues explicitly against building anything larger, and its reasoning is carried below so the next reader does not re-propose the bigger options.

What happened, twice

PR #14651 (#14376) teaches the i18n extractor to walk three new families, one of them objects.OBJECT._validations.RULE.message. Its committed ratchet scripts/i18n-coverage-baseline.json therefore holds counts only that branch can compute — on main the walk does not exist, so other PRs move those counts without being able to see that they did.

Two PRs did exactly that while it waited to land:

PR what it landed effect on the branch's baseline
#14517 a new authored rule message + four zh-CN rule translations in app-showcase 454 → 450
#14709 the remaining eight authored validation messages onto the translation channel 450 → 443

Each cost a patch round: merge main, re-derive, rebuild every number in the PR body.

The property, stated generally

A PR that widens what a committed ratchet measures races every PR that changes what is measured, for its whole review-and-queue latency — and the race is invisible on main, because there the instrument does not exist.

Not i18n-specific. Type-check debt counts, token ratchets and liveness state counts have the same shape.

And the two collisions were not independent draws. Both are steps of one in-flight campaign moving the examples' authored validations[].message onto the #14253 channel. A campaign that systematically touches exactly the family a PR makes measurable collides on every step it lands. The forward-looking half is measurable and reassuring: app-showcase now has zero untranslated rule messages left, so that leg is finished; remaining exposure is app-crm (5) and app-todo (4) rule messages, plus bulkActions (18) and datasets (62) nobody is currently working.

⭐ It fails safe, and that is what caps the fix

The branch's own gate reds in both directions — the DOWN direction is what caught both collisions — and the merge queue rebuilds against current main. A stale number cannot land. The cost is latency and re-derive rounds, not correctness.

That is the argument for a one-line fix rather than a mechanism.

Proposed change

  1. Name the class in scripts/check-i18n-coverage.mjs's own header. That file already carries this kind of institutional memory, so it is the natural home.

  2. Add one sentence to the DOWN-direction remedy. Today it says only:

    untranslated declared strings improved N -> M — ratchet DOWN: run node scripts/check-i18n-coverage.mjs --update and commit the baseline.

    which reads as "your diff improved something" — when the usual cause is "main moved under you". Proposed addition, in the dev's words:

    if you did not touch this population, merge origin/main first — the movement is probably not yours.

One line. It converts two confused rounds into a free hint for the next author.

⛔ What NOT to do — argued, not merely excluded

The dev names three larger options and argues against all of them:

  • Splitting the baseline per family. More files to go stale, same race.
  • Dropping the DOWN direction. That direction is what makes it a ratchet, and it is what caught both collisions here.
  • Computing the number instead of committing it. The committed number is what makes the change reviewable.

If a future reader wants one of these, the burden is to answer the fail-safe argument first: the race costs latency, not correctness.

Provenance

The seat holds no opinion on the grade; it does not own scripts/**.

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