Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
# the same commands, the same scripts in package.json, so a green run here and
# a green run on a laptop mean the same thing. Each gate is its own step so a
# red run names the gate that failed; `pnpm lint` carries `--i18n-strict`, so
# a translatable key missing its zh-CN string is a failure, not a warning.
# a translatable key missing its zh-CN string is a failure, not a warning, and
# it chains `pnpm check:i18n-source`, so an `en.ts` entry that no longer matches
# the label its metadata declares is a failure too (#63). That script runs its
# own `--self-test` first, on every CI run: the gate proves here, in CI, that it
# still reports a drifted value, an orphaned key and a missing one, so a green
# run means "compared and equal" rather than "compared nothing".
#
# Nothing here is allowed to skip: `--frozen-lockfile` refuses to resolve a
# lockfile that disagrees with package.json instead of quietly rewriting it,
Expand Down Expand Up @@ -63,7 +68,7 @@ jobs:
- name: validate — protocol schema, CEL predicates, widget bindings
run: pnpm validate

- name: lint — data-model conventions + zh-CN translation parity
- name: lint — data-model conventions + zh-CN coverage + en.ts source parity
run: pnpm lint

- name: typecheck
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ platform operator) defined as typed metadata. Not a framework, not a package —
```bash
pnpm validate # protocol schema + CEL predicates (record.<field> existence) + widget bindings
pnpm lint # data-model conventions: reserved vocabulary, titles, master-detail, select options
# + zh-CN coverage (--i18n-strict) + en.ts source parity (pnpm check:i18n-source)
pnpm typecheck
```

Expand Down
17 changes: 14 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ coding agents working from the same rules. Those rules live in three files; this
pnpm install
pnpm validate # protocol schema + CEL predicates (record.<field> existence) + widget bindings
pnpm lint # data-model conventions + zh-CN translation parity (--i18n-strict)
# + en.ts source parity (pnpm check:i18n-source, runnable on its own)
pnpm typecheck
```

Expand Down Expand Up @@ -100,9 +101,19 @@ validation messages, action copy, navigation, dashboards, datasets — exists in
- `zh-CN` is authored in [`src/translations/zh-CN.ts`](./src/translations/zh-CN.ts), with the vocabulary
`DESIGN.md` fixes. Do not machine-translate the domain words.

`pnpm lint` fails when a translatable key is missing in either file; `npx objectstack i18n check --show-keys`
lists exactly which. The Studio's own metadata-form strings are the platform's and are not this
repository's to translate (`lint` hides them unless you pass `--include-platform`).
Two different gates, both inside `pnpm lint`:

- **Coverage** — `objectstack lint --i18n-strict` fails when a translatable key is missing from a
non-default locale, i.e. from `zh-CN`; `npx objectstack i18n check --show-keys` lists exactly which. It
cannot speak for `en`: it reports the source locale as 100 % translated, because the source label *is*
the translation.
- **Source parity** — `pnpm check:i18n-source` ([`scripts/check-i18n-source.mjs`](./scripts/check-i18n-source.mjs))
compares every one of `en.ts`'s 507 keys against the label its metadata declares in the built artifact,
and fails on a drifted value, a key whose metadata is gone, or a source label `en.ts` never restates.
Renaming a label without renaming it in `en.ts` is a red gate, not a silent runtime override (#63).

The Studio's own metadata-form strings are the platform's and are not this repository's to translate
(both gates exclude them; `lint` shows them with `--include-platform`).

## Skills for coding agents

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ asks for `zh-CN` ([`07-…-zh-CN.png`](docs/screenshots/07-hiring-pipeline-kanba
- **Three audiences, one metadata set** — platform ops, employer, job seeker each get their own navigation group over the same objects.
- **Credentials are first-class** — "licensed to practise, re-certified before expiry" is core, not a plugin.
- **Industry-neutral by rule** — no vertical vocabulary in the schema; industries live in seed data only.
- **Two locales** — every label, option, section, message and navigation item exists in `en` and `zh-CN`, and `pnpm lint` fails when one is missing.
- **Two locales** — every label, option, section, message and navigation item exists in `en` and `zh-CN`, and `pnpm lint` fails when one is missing, or when an `en` entry stops matching the label its metadata declares.

## Quick start

Expand Down Expand Up @@ -160,6 +160,7 @@ Every metadata change is gated, locally and in [CI](./.github/workflows/ci.yml):
```bash
pnpm validate # protocol schema + CEL predicates + bindings
pnpm lint # data-model conventions (ADR-0090 vocabulary, titles, master-detail) + zh-CN parity
# + en.ts source parity (pnpm check:i18n-source, runnable on its own)
pnpm typecheck
```

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"start": "objectstack start",
"build": "objectstack build",
"validate": "objectstack validate",
"lint": "objectstack lint --i18n-strict",
"lint": "objectstack lint --i18n-strict && pnpm check:i18n-source",
"check:i18n-source": "objectstack build && node scripts/check-i18n-source.mjs --self-test && node scripts/check-i18n-source.mjs",
"typecheck": "tsc --noEmit"
},
"dependencies": {
Expand Down
Loading
Loading