Skip to content

[finding] the three i18n gates pin neither their prerequisite exit code nor their advisory text, while the four sibling gates that answer the same words all do #14857

Description

@claude

Found while landing #14008 + #13825 (PR #14856), which moved the PREREQUISITE NOT MET exit code in these three gates from 1 to 3. Out of scope there: that PR's file surface was fixed by triage to the refusal sites and one lane-doc sentence, and adding a pin means extracting a pure text function, which is a shape change rather than a value change.

The reading

Four gates in this repo pin their prerequisite refusal — the exit code AND the advisory text — from their own --self-test, because each first extracted the message into a pure function so the assertion can run without spawning a process or stubbing process.exit:

  • scripts/import-prerequisite.mjsprerequisiteNotMetText(), and selfTest asserts EXIT_PREREQUISITE_NOT_MET === 3, that it differs from EXIT_FINDINGS and from 0, and that the rendered advisory contains both numbers.
  • scripts/check-test-completeness.mjsinvocationVerdict() returns { exit, lines }, and the self-test asserts the refusal's exit is the prerequisite code and has not regressed to the findings code.
  • scripts/check-release-section-coverage.mjs — same shape.
  • scripts/check-type-check-coverage.mjs — same shape, plus a case labelled "the refusal code is 3".

The three gates PR #14856 just moved have no such pin, in any of the five refusal paths:

  • scripts/check-i18n-coverage.mjs — 3 paths
  • scripts/check-i18n-bundles.mjs — 1 path
  • packages/cli/scripts/check-app-nav-i18n.mjs — 1 path

In each, the printer builds its string inline inside console.error(...) and calls process.exit(...) on the next line, so there is no value for a test to read. Measured on fcdbc6d2: grep -n "Exit code" scripts/check-i18n-coverage.mjs scripts/check-i18n-bundles.mjs packages/cli/scripts/check-app-nav-i18n.mjs finds the advisories, and nothing in any selfTest() in those files mentions an exit code at all.

Why it is worth a line

check-i18n-coverage.mjs --self-test does prove its classifiers go red, and says so in its pass line. That reads like coverage of the refusal and is not: the classifiers are pure functions over strings that decide which verdict fires, and they are green whatever number the printer beside them returns.

So the value PR #14856 just moved is unpinned in all three files. A later edit can move it back to 1, or let the printed Exit code N drift away from the process.exit(N) six lines below it, and every gate stays green — which is the exact failure import-prerequisite.mjs's constant docblock argues against ("the self-test pins the value each path actually returns instead of a comment about it").

Not claimed

  • ⛔ No severity claim and no recommendation on ordering. The four sibling gates arrived at the pin one at a time, and whether this is worth the extraction here is triage's call.
  • ⛔ Not a defect in PR fix(gates): answer PREREQUISITE NOT MET with the frame's exit code in the last three i18n gates #14856: the values are correct today, verified live for 3 of the 5 paths with the exit code captured before any pipe. This is about what stops them from silently becoming wrong later.
  • The two coverage paths behind the CLI-build probe (COULD NOT MEASURE, POPULATION EMPTY) are unreachable without a build and unpinned, so they are the two that no local run and no test currently observes at all.

Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions