Skip to content

Commit 03ca4f4

Browse files
committed
docs(i18n): state who owns the metadata-form baseline where the gate is taught
`content/docs/ui/translations.mdx` recommends `os i18n check --strict --threshold` as the CI gate; that advice is now reachable for an app package, and the page has to say what is and is not in the number it produces — including why shipping your own `metadataForms` bundle to move it is the wrong repair. The published i18n skill listed metadata forms among the surfaces `check` always reports on. That sentence is false as of this change, so it is corrected in place rather than left to read as a scope statement. `content/docs/protocol/kernel/i18n-standard.mdx` names `metadataForms` only in its ORPHAN-key paragraph (the reverse direction, which `os validate` / `os lint` / `os compile` answer) — untouched by this change and left alone. Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 028f271 commit 03ca4f4

3 files changed

Lines changed: 84 additions & 3 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
"@objectstack/cli": minor
3+
---
4+
5+
fix(cli): `os i18n check` counts the coverage an app actually owns, so `--strict` / `--threshold` can gate an app package (#16681)
6+
7+
## What was wrong
8+
9+
`collectExpectedEntries` walks the Studio metadata-form registries
10+
unconditionally — identically for every config, an empty one included — so
11+
every stack's expected set carries ~773 `metadataForms.*` keys that
12+
`@objectstack/platform-objects` translates and the runtime already serves.
13+
14+
Two of the three commands that see that family already knew it is not the
15+
author's. `os lint` hides it and says so ("platform built-ins: 773 i18n
16+
issue(s) hidden — rerun with `--include-platform`"); `os i18n extract` has
17+
`--no-metadata-forms`. `os i18n check` is the one command that publishes a
18+
**percentage**, and it carried the baseline in its denominator:
19+
20+
```
21+
Coverage by locale
22+
en ████████████████████████ 100.0% (1265/1265, missing 0)
23+
zh-CN █████████░░░░░░░░░░░░░░░ 38.9% (492/1265, missing 773)
24+
```
25+
26+
That is an application with every key it owns translated. `--strict` and
27+
`--threshold` — the two flags whose entire purpose is CI gating — therefore
28+
could not gate an app package at all, and the only way to move the number was
29+
to ship a copy of the platform's bundle, which would *override* the platform's
30+
own and go stale at the next upgrade. The workaround was worse than the defect.
31+
32+
## What it does now
33+
34+
**Ownership is observed, not assumed.** The baseline counts toward coverage
35+
when the stack under examination ships those translations itself, and does not
36+
when it does not — read from the config's own `translations` bundles, requiring
37+
a non-empty string leaf so an `--fill=empty` scaffold is not mistaken for a
38+
claim of ownership. An app gets a number about its own surface with no flag;
39+
`platform-objects`, which does ship the family, stays gated on it with no flag
40+
either. An unconditional exclusion would have turned the app side green by
41+
deleting the platform's own gate, and is what the negative-control tests forbid.
42+
43+
**The flag is `os lint`'s, spelling and all.** `--include-platform` forces the
44+
baseline in; `--no-include-platform` forces it out, for a package that ships a
45+
partial baseline and does not intend to own the rest. Absent, the decision is
46+
the observed one — three states, not two.
47+
48+
**Both output faces carry the decision.** `--json` gains
49+
`platformMetadataForms: { mode, excludedKeys }`, and the console prints
50+
`platform built-ins: N key(s) not counted — rerun with --include-platform to
51+
gate them here` under the coverage table, rendered from those same two numbers.
52+
53+
`os lint` is unchanged. The shared `computeI18nCoverage` seam still counts the
54+
baseline by default, because lint folds it away one seam later and counts what
55+
it folded for its own hint line.
56+
57+
## Compatibility
58+
59+
Additive on the command surface; an invocation that was refused is now
60+
accepted, and no flag is removed or renamed. The behaviour that changes is the
61+
**default coverage number for a stack that ships no `metadataForms` bundle**
62+
it stops reporting a debt that stack must not pay. A run that wants the old
63+
numbers back asks for them with `--include-platform`, on the same argv.

content/docs/ui/translations.mdx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,23 @@ A missing string in the **default** locale is an error; missing strings in
244244
other locales are warnings until you set `--strict` / `--threshold`. The Todo
245245
example ships a completeness test alongside its bundles — worth copying.
246246

247+
### What counts as *your* coverage
248+
249+
The Studio's own metadata forms (`metadataForms.*` — several hundred keys
250+
across every metadata type) are translated by `@objectstack/platform-objects`
251+
and served from there, so they are **not** in your coverage number: an app that
252+
translated everything it declares reads 100%, not 39%. ⛔ Do not "fix" a low
253+
number by shipping your own `metadataForms` bundle — yours would override the
254+
platform's and go stale at the next upgrade.
255+
256+
The rule is **ownership**, read from your own bundles rather than assumed: ship
257+
translations for that family and you are asked to complete them, which is how
258+
the platform packages stay gated on the strings they do own. Pass
259+
`--include-platform` to audit the baseline anyway (`os lint`'s flag, same
260+
meaning), or `--no-include-platform` to keep it out even though you ship part
261+
of it. The command prints how many keys it left out, and `--json` carries the
262+
same two numbers as `platformMetadataForms`.
263+
247264
### Which locales get checked
248265

249266
Your project decides, and the tooling never assumes. `os lint`, `os i18n check`

skills/objectstack-i18n/SKILL.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,10 @@ os i18n check --strict --threshold=95 # CI gate: locale parity + minimum covera
277277

278278
It compares registered bundles against source metadata and reports missing keys
279279
per locale for every surface the extractor walks — objects and their sub-keys,
280-
global actions, apps, dashboards, pages, flow screens, metadata forms. Gaps in
281-
the default locale are errors, `--strict` promotes the rest, `--show-keys` lists
282-
them all; `os lint --i18n-strict` folds the same gate into lint.
280+
global actions, apps, dashboards, pages, flow screens. The platform's metadata
281+
forms count only for a stack that ships their translations (`--include-platform`
282+
audits them anyway). Gaps in the default locale are errors, `--strict` promotes
283+
the rest, `--show-keys` lists them all; `os lint --i18n-strict` folds it in.
283284

284285
### `os i18n extract --check` — freshness, not coverage
285286

0 commit comments

Comments
 (0)