From 7164f69e1b7bd73f70116746efbebeca6fdbeff1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:40:15 +0000 Subject: [PATCH 01/12] skills(i18n): drop the preamble, the When-to-Use list and Core Concepts (I18N-B-03, I18N-B-04, I18N-A-01, I18N-B-01) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-B-03: the opening paragraph restated the frontmatter description the agent already holds when the skill loads. - I18N-B-04: "When to Use This Skill" restated the description in seven bullets; one of them pointed at a contract-only surface with no implementation, and one was I18N-A-01. - I18N-A-01: the locale-formatting trigger (dates, numbers, currency) routed agents here for work this package teaches nowhere — a whole-file grep for currency/timezone/format/Intl. matched only those five lines. The currency fallback is carried by objectstack-data's field-types rules and objectstack-ui; the localization endpoint is API surface. - I18N-B-01: "Core Concepts / Translation Architecture Overview" was a table of contents — each of its four items is restated in full by a later section (object sub-keys, bundle authoring, coverage, runtime authoring). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 48 -------------------------------- 1 file changed, 48 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 9d89523685..ac7954afe3 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -18,54 +18,6 @@ metadata: # Internationalization — ObjectStack I18n Protocol -Expert instructions for designing internationalization (i18n) and localization (l10n) -strategies using the ObjectStack specification. This skill covers translation bundle -structures, locale configuration, object-first translation patterns, coverage detection, -and integration with the I18nService. - ---- - -## When to Use This Skill - -- You are **configuring i18n** for a new ObjectStack project. -- You need to **create translation bundles** for multiple locales. -- You are designing **object-first translation structures** (per-object translation files). -- You need to **detect missing translations** (`os i18n check` coverage analysis). -- You are extending the service contract with **AI translation suggestions** (TMS / machine-translation integrations). -- You are implementing **locale-specific formatting** (dates, numbers, currency). - Related: workspace regional defaults (`timezone`, `locale`, `currency`) live in the - tenant-scoped `localization` settings, are resolved onto each request's - `ExecutionContext`, and are exposed at `GET /api/v1/auth/me/localization`; a currency - field falls back to `localization.currency` when it omits its own (ADR-0053). -- You need to understand **translation file organization strategies** (bundled, per_locale, per_namespace). - ---- - -## Core Concepts - -### Translation Architecture Overview - -1. **Runtime format — `objects.*` (`TranslationData`)**: each locale is authored as one - `TranslationData` value. All translatable content for an object (label, fields, - options, views, sections, tabs, actions) is grouped under `objects.{object_name}`, - with global groups (`apps`, `messages`, `globalActions`, `dashboards`, `pages`, - `flows`, `settings`, `metadataForms`, `settingsCommon`) at the top level. - -2. **Bundle registration**: per-locale files are assembled with - `defineTranslationBundle({ en, 'zh-CN': … })` into a `TranslationBundle` - (locale code → `TranslationData`) and registered via - `defineStack({ translations: [...] })`. This is the format the runtime resolvers, - `os i18n extract`, `os i18n check`, and the example apps all use. - -3. **Coverage detection**: `os i18n check` compares registered bundles against source - metadata to report missing keys per locale. - -4. **Runtime authoring — `TranslationItem`**: a `translation` metadata item authored - in the Studio / metadata API carries the **same** `objects.*` groups plus the - `locale` it translates. There is only one shape; see "Authoring at Runtime" below. - ---- - ## Translation Configuration ### Stack-Level I18n Config From 1da918fb691de29996b9c7e89de95e717791be52 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:41:15 +0000 Subject: [PATCH 02/12] skills(i18n): compress the layout section to one table and demote it below the object constructs (I18N-D-02, I18N-D-03, I18N-B-05) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-D-02: three prose "strategies" with ASCII trees and size heuristics became one three-row table. The per-namespace layout has zero real usages in the repo (a search for an i18n//*.json tree finds only package.json/tsconfig.json), and the section already conceded the layout is inert — the import graph, not the platform, assembles it. - I18N-D-03: the FileI18nAdapter localesDir flat-file rule was stated twice, here and again under Plugin Setup. Both go: localesDir has zero real usages and os serve never passes it (see I18N-C-01). The surviving row states the operative fact — your own imports assemble the tree. - I18N-B-05: the layout prose sat between the config table and the object sub-key table, so ~380 tokens of authoring convention stood in front of the most decision-changing construct in the file. The order is now config → canonical bundle → object sub-keys → naming → layout. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 66 +++++++------------------------- 1 file changed, 14 insertions(+), 52 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index ac7954afe3..406139294e 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -48,58 +48,6 @@ export default defineStack({ --- -## File Organization Strategies - -### 1. Bundled (Single File) - -All locales in one file. Best for small projects with few objects. - -``` -src/translations/ - crm.translation.ts # { en: {...}, "zh-CN": {...} } -``` - -**When to use:** Fewer than 5 objects, 2-3 locales, < 200 translation keys total. - -### 2. Per-Locale (Recommended) - -One file per locale containing all namespaces. Recommended when a single locale file stays under ~500 lines. - -``` -src/translations/ - en.ts # TranslationData for English - zh-CN.ts # TranslationData for Chinese - ja-JP.ts # TranslationData for Japanese -``` - -**When to use:** Medium projects (5-20 objects), 3-5 locales, organized by language. - -### 3. Per-Namespace (Enterprise) - -One file per namespace (object) per locale. Aligns with Salesforce DX and ServiceNow conventions. - -``` -i18n/ - en/ - account.json # ObjectTranslationData - contact.json - common.json # messages + app labels - zh-CN/ - account.json - contact.json - common.json -``` - -**When to use:** Large projects (20+ objects), 5+ locales, team collaboration, CI/CD pipelines. - -> These are **authoring conventions**: your import graph assembles whichever layout you -> choose into the `TranslationBundle` values you register on the stack. -> `FileI18nAdapter`'s `localesDir` loads only flat top-level `{locale}.json` files -> (subdirectories are skipped) — a per-namespace tree must be assembled by your own -> imports or build step. - ---- - ## Authoring Translation Bundles (`objects.*`) The canonical authoring path: one `TranslationData` per locale, assembled with @@ -257,6 +205,20 @@ silently in its source locale while every neighbouring one resolves. --- +## File Organization Strategies + +Layout is an **authoring convention**: whichever one you pick, your own import graph +assembles it into the `TranslationBundle` you register on the stack — nothing loads a +directory tree for you. + +| Layout | Files | Use when | +|:--|:--|:--| +| Bundled | one `crm.translation.ts` holding every locale | under 5 objects, 2-3 locales | +| Per-locale (recommended) | `src/translations/{en,zh-CN,ja-JP}.ts` + `index.ts` | 5-20 objects, 3-5 locales | +| Per-namespace | `i18n/{locale}/{object}.json`, assembled by your own imports | 20+ objects, 5+ locales | + +--- + ## Authoring at Runtime: the `translation` Item Translations do not have to ship as files. A **`translation` metadata item** — From c97dafddd93d4a7de8b346ffa7c0f46d76992b48 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:41:55 +0000 Subject: [PATCH 03/12] skills(i18n): reduce the runtime translation item to one schema-pointing paragraph (I18N-F-03, I18N-D-04) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-F-03: the `translation` metadata item held 570 tokens (9% of the file) including a full worked example, for a surface with zero measured usage — a search for defineTranslation( across examples and packages returns only the schema's own docstring and definition. It is a live surface, so the last mention stays: one paragraph carrying the three rules that differ from a file bundle (locale required, one locale per item, layers over the shipped bundle) and a pointer to TranslationItemSchema. - I18N-D-04: the retired `o.*` dialect was stated twice — here and under Common Pitfalls. Only the pitfall copy carries the migration map for the sibling keys, so that is the copy that survives. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 60 +++++--------------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 406139294e..32249c0994 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -221,58 +221,14 @@ directory tree for you. ## Authoring at Runtime: the `translation` Item -Translations do not have to ship as files. A **`translation` metadata item** — -created in the Studio, through the metadata API, or by an agent — is one -locale's worth of the **same** `objects.*` groups documented above, plus the -`locale` it translates. There is exactly one shape; nothing converts between -formats. - - -```typescript -import { defineTranslation } from '@objectstack/spec/system'; - -export default defineTranslation({ - locale: 'zh-CN', - objects: { - account: { - label: '客户', - pluralLabel: '客户', - fields: { - name: { label: '客户名称', help: '公司或组织的法定名称' }, - industry: { label: '行业', options: { tech: '科技', finance: '金融' } }, - status: { options: { active: '活跃', inactive: '停用' } }, - }, - _views: { all_accounts: { label: '全部客户' } }, - _sections: { basic_info: { label: '基本信息' } }, - _actions: { - merge: { label: '合并客户', confirmText: '此操作无法撤销,确认合并?' }, - }, - }, - }, - apps: { crm: { label: '客户关系管理', navigation: { home: { label: '首页' } } } }, - messages: { 'common.save': '保存' }, -}); -``` - -Rules that differ from a file bundle: - -- **`locale` is required.** A file bundle names its locales as map keys; an item - carries its own. The sync falls back to a BCP-47-looking item *name*, then skips - the item with an `[i18n] … — skipped` warning nobody watches. -- **One locale per item.** Author `zh-CN` and `ja-JP` as two items. -- Published items are loaded at boot and on every publish (no restart), and - layer **over** the file bundles — an authored value wins over a shipped one - for the same key; deleting the item restores the shipped value. - -Exact Zod shape: `node_modules/@objectstack/spec/src/system/translation.zod.ts` — -`TranslationItemSchema`. - -### Retired: the `o.*` dialect - -A second object-first shape keyed on `o.{object_name}` (with `app`, `nav`, -`dashboard`, `reports`, `notifications`, `errors`, `_globalOptions`, `_meta`, -`namespace`, `_actions.confirmMessage`) was once documented for Studio authoring. -**No resolver ever read it**, and both doors now reject it — files included. +Translations do not have to ship as files. A **`translation` metadata item** — created in +the Studio, through the metadata API, or by an agent — carries one locale's worth of the +**same** `objects.*` groups documented above plus the `locale` it translates. `locale` is +required, one locale per item, and published items load at boot and on every publish, +layering **over** the file bundles (delete the item and the shipped value returns). There +is exactly one shape; nothing converts between formats. Author with `defineTranslation`; +exact Zod shape is `TranslationItemSchema` in +`node_modules/@objectstack/spec/src/system/translation.zod.ts`. --- From ff489c1830e4edfab394ca378011bca366f80a31 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:42:33 +0000 Subject: [PATCH 04/12] skills(i18n): replace hand-wired Plugin Setup with the registration fact (I18N-C-01, I18N-E-01, I18N-E-02) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-C-01: the section taught new ObjectKernel() + kernel.use(new I18nServicePlugin({localesDir, registerRoutes, basePath})) + bootstrap. os serve auto-registers I18nServicePlugin whenever the config carries translations or i18n, and passes only defaultLocale/fallbackLocale — never localesDir. Zero apps in this repo hand-wire it. Kernel bootstrap is objectstack-platform's domain, whose Runtime Boot Sequence section already carries the same fact; this file keeps one sentence plus the three routes. - I18N-E-01: that block was the one unmarked fence presenting as a complete program that would fail the example gate — it used II18nService with the import in a different fence (TS2304). It dies with the section. - I18N-E-02: the same block called kernel.use(...) un-awaited while ObjectKernel.use is `async use(plugin: Plugin): Promise` (packages/core/src/kernel.ts:192) and the platform's own call site awaits it. It dies with the section rather than being patched. - I18N-D-03 (second half): the duplicate localesDir flat-file note goes with it. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 32249c0994..89635d5f8a 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -373,30 +373,12 @@ The contract also declares optional methods — `getFieldLabels`, `getCoverage`, as extension points for a custom workbench or TMS adapter. (`getAppBundle` / `loadAppBundle` went with the `o.*` shape they returned.) -### Plugin Setup +### Registration -```typescript -import { ObjectKernel } from '@objectstack/core'; -import { I18nServicePlugin } from '@objectstack/service-i18n'; - -const kernel = new ObjectKernel(); -kernel.use(new I18nServicePlugin({ - defaultLocale: 'en', - localesDir: './i18n', - fallbackLocale: 'en', - registerRoutes: true, // Auto-register REST endpoints - basePath: '/api/v1/i18n', -})); - -await kernel.bootstrap(); - -const i18n = kernel.getService('i18n'); -``` - -> `localesDir` loads only flat, top-level `{locale}.json` files from the directory -> (subdirectories are skipped). `registerRoutes: true` (the default) self-registers -> `GET {basePath}/locales`, `/translations/:locale`, and `/labels/:object/:locale` -> once an HTTP server is available. +You do not wire this plugin: `os serve` registers `I18nServicePlugin` itself whenever the +stack config carries `translations` or `i18n` (kernel bootstrap is +**objectstack-platform → Runtime Boot Sequence**). It self-registers +`GET /api/v1/i18n/locales`, `/translations/:locale` and `/labels/:object/:locale`. --- From 84a1928d51fbaadad547c6c4be9f8ea4f550babc Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:43:41 +0000 Subject: [PATCH 05/12] skills(i18n): drop three sections that restate facts already stated (I18N-D-01, I18N-D-05, I18N-D-07) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-D-01: "AI-Powered Translation Suggestions" was a vendor list plus a best-practice aside for a contract method no shipped adapter implements and no CLI reaches. The same "contract-only" fact is already stated by the Diff & Coverage Schemas paragraph and again by the service-contract section. - I18N-D-05: the "CRM I18n Blueprint" table restated the config table, the canonical assembly and the naming callout. The only facts it alone carried were the two example paths, which is what remains. - I18N-D-07: "Mismatched Object Names" restated the Critical callout under Naming Conventions, and "Hardcoded Option Values" restated the option-value paragraph there — which is the stronger statement, because it names the failure (both the display label and a hyphenated spelling parse, ship, and resolve to nothing). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 65 ++------------------------------ 1 file changed, 3 insertions(+), 62 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 89635d5f8a..2eb714fea3 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -324,21 +324,6 @@ workflows at `os i18n check` / `os lint --i18n-strict` instead. --- -## AI-Powered Translation Suggestions - -`II18nService.suggestTranslations(locale, items)` is an optional contract method -that enriches diff items with `aiSuggested` / `aiConfidence`. It is -**contract-only today**: no shipped adapter implements it, and there is no CLI -command for it. Implement it on a custom adapter to integrate: - -- Translation Management Systems (TMS) like Phrase, Crowdin, Lokalise -- Machine translation APIs (Google Translate, DeepL) -- Internal translation memory databases - -> **Best Practice:** Review and approve machine suggestions before committing them. - ---- - ## Integration with II18nService ### Service Contract @@ -418,22 +403,10 @@ Commit the translation files, import them into your bundle, and register it via --- -## CRM I18n Blueprint +## Shipped examples -`examples/app-crm` ships the bundled layout (one `crm.translation.ts`, `en` + -`zh-CN`); `examples/app-todo` the per-locale one (`{en,zh-CN,ja-JP}.ts` + `index.ts`). - -Use this structure for metadata apps: - -| Layer | CRM Pattern | -|:--|:--| -| Stack config | `i18n` with an explicit locale list; the source layout is a convention | -| Translation assembly | One `defineTranslationBundle` call — inline locales, or importing per-locale files | -| Locale content | Object-scoped translations (`objects.crm_account.fields.*`, `_views`, `_actions`) + global app/messages | -| Naming integrity | Translation object/field keys exactly match metadata machine names | - -For new locales, copy one locale file as a baseline, then run `os i18n check` -before release. +`examples/app-crm` — the bundled layout (one `crm.translation.ts`, `en` + `zh-CN`). +`examples/app-todo` — the per-locale layout (`{en,zh-CN,ja-JP}.ts` + `index.ts`). --- @@ -457,38 +430,6 @@ Same rule for its sibling keys: `app` → `apps`, `nav` → `_globalOptions` → `objects..fields..options`, `_meta.locale` → top-level `locale`, and `_actions.confirmMessage` → `_actions.confirmText`. -### ❌ Mismatched Object Names - -Translation keys must match metadata exactly: - -```typescript -// Metadata -{ name: 'project_task' } - -// Translation (WRONG) -{ objects: { projectTask: { label: '项目任务' } } } - -// Translation (CORRECT) -{ objects: { project_task: { label: '项目任务' } } } -``` - -### ❌ Hardcoded Option Values - -Always use lowercase machine values for options: - -```typescript -// Metadata -options: [ - { value: 'in_progress', label: 'In Progress' }, -] - -// Translation (WRONG) -options: { 'In Progress': '进行中' } - -// Translation (CORRECT) -options: { in_progress: '进行中' } -``` - ### ❌ Ignoring Coverage Reports Run `os i18n check` before releases; `extract --check` is what sees staleness. From 74dd2f70c41bf4e1c0a431cba1d56348ae7fa5fa Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:44:39 +0000 Subject: [PATCH 06/12] skills(i18n): drop the duplicate template, trim Verify, add the missing lint surface (I18N-B-02, I18N-C-02, I18N-G-01, I18N-D-06) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - I18N-B-02: "Quick-Start Template" was a strict subset of the canonical example under Authoring Translation Bundles — same object, same sub-keys, same apps/messages — and its own preamble said so. Two checked example blocks were paying to teach one shape. - I18N-C-02: "Verify your work" restated objectstack-platform's own section and then pointed at it. Two commands and the pointer remain. - I18N-G-01: the lint unknown-target enumeration presented as exhaustive but omitted tabs. validateTranslationReferences walks objects.._tabs. and reports translation-target-unknown for it, and this file's own object sub-key table already lists _tabs. - I18N-D-06: the validationMessages note narrated why the key was removed. The removal changes no decision the reader can act on; where to author the message does. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 74 +++++--------------------------- 1 file changed, 11 insertions(+), 63 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 2eb714fea3..a6398ecb6b 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -167,11 +167,9 @@ Top-level groups alongside `objects`: `apps` (label, description, navigation), `messages`, `globalActions` (object-less actions), `dashboards`, `pages`, `flows`, `settings`, `metadataForms`, `settingsCommon`. -> **Validation messages are not a translation group.** `validationMessages` was -> removed in spec 17.0.0 — nothing ever read it, so a translated rule -> message was stored and never shown. Author the message on the rule itself -> (`object.validations[].message`), which the engine returns on every rejected -> write. +> `validationMessages` is not a translation group — it was removed in spec 17.0.0. +> Author the message on the rule itself (`object.validations[].message`), which the +> engine returns on every rejected write. For the exact Zod shape (and any field that may have been added since), read `node_modules/@objectstack/spec/src/system/translation.zod.ts` — @@ -198,10 +196,10 @@ parse, ship, and resolve to nothing. `os validate` / `os lint` / `os compile` check this direction and report it as warnings (`translation-target-unknown`, `translation-option-key-unknown`): a key -naming an object, field, view, action, param, section, app, nav item, dashboard, -widget or flow screen that does not exist is listed alongside the names that do. -A bundle keyed to something since renamed still parses — the label just renders -silently in its source locale while every neighbouring one resolves. +naming an object, field, view, tab, action, param, section, app, nav item, +dashboard, widget or flow screen that does not exist is listed alongside the names +that do. A bundle keyed to something since renamed still parses — the label just +renders silently in its source locale while every neighbouring one resolves. --- @@ -436,65 +434,15 @@ Run `os i18n check` before releases; `extract --check` is what sees staleness. --- -## Quick-Start Template - -One compact per-locale file — assemble locales with `defineTranslationBundle` and -register via `defineStack({ translations: [...] })` as shown in -"Authoring Translation Bundles" above: - - -```typescript -// src/translations/zh-CN.ts -import type { TranslationData } from '@objectstack/spec/system'; - -export const zhCN: TranslationData = { - objects: { - account: { - label: '客户', - pluralLabel: '客户', - fields: { - name: { label: '客户名称' }, - email: { label: '邮箱', placeholder: '输入邮箱地址' }, - status: { - label: '状态', - options: { - active: '活跃', - inactive: '停用', - }, - }, - }, - _views: { - all_accounts: { label: '全部客户' }, - }, - }, - }, - - apps: { - crm: { label: '客户关系管理' }, - }, - - messages: { - 'common.save': '保存', - 'common.cancel': '取消', - }, -}; -``` - ---- - ## Verify your work -After editing a `*.translation.ts` bundle: - ```bash -os i18n check # translation coverage vs the default locale (missing-key report) -os validate # the bundle conforms to the protocol schema (no artifact) -# or: os build # the same schema gate, plus emits dist/ +os i18n check # coverage: which keys are missing, per locale +os validate # the bundle conforms to the protocol schema ``` -`os i18n check` lists keys missing per locale; `os lint --i18n-strict` turns -coverage gaps into hard errors. In a scaffolded project the schema gate is -`npm run validate`. See objectstack-platform → **Verify your work**. +`os lint --i18n-strict` turns coverage gaps into hard errors. For the build and scaffold +gates see objectstack-platform → **Verify your work**. --- From 36c7a16cac97071ea69cb13df2ef53dc6f5e5a09 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:57:19 +0000 Subject: [PATCH 07/12] skills(i18n): teach the generated-bundle shape and make the extract workflow converge (I18N-F-01, I18N-F-02, I18N-F-04, I18N-G-02) - I18N-F-01: the highest-count real pattern had no canonical example. Eight packages ship their own generated bundle (36 *.objects.generated.ts across four locales, 11 withSourceFallback call sites, 5 kernel:ready loadTranslations sites) and the generated module exports an objects subtree rather than a TranslationData, so a reader following the extract workflow dead-ended at a file that cannot be registered. The block shows the wrap, the bundle, and the kernel:ready alternative for a plugin. - I18N-F-04: --source-hashes had one word in a flag list although stale fill is the platform's own headline i18n hazard. Its purpose is now stated where the argument is passed: without the companion a leaf whose source moved goes on serving the superseded fill under a green os i18n check. - I18N-F-02 / I18N-G-02: the documented extract-translate-check workflow could not converge. os i18n extract defaults to --objects-only (default: true, allowNo: true) so it writes only objects/globalActions, while os i18n check's COVERAGE_SOURCE also demands app, navigation, dashboard, widget, page and flow. The flag was missing from a six-flag enumeration presented as the remainder; it is named now, with the divergence and the way out. The block is deliberately NOT marked for check:skill-examples: that gate's skills surface resolves @objectstack/spec only, and the real shape needs withSourceFallback from @objectstack/platform-objects. Marking it would fail on correct code. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 45 +++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index a6398ecb6b..7324b6d3f3 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -379,12 +379,18 @@ This writes `.objects.generated.ts` TypeScript modules (not JSON), plus `.metadata-forms.generated.ts` companion unless `--no-metadata-forms` — the default locale is filled from schema labels, other locales follow `--fill` (`empty | default | todo`). `os i18n extract --help` lists the rest: `--filter`, -`--default-locale`, `--no-merge`, `--source-hashes`, `--dry-run`, `--json`, … +`--default-locale`, `--no-merge`, `--objects-only`, `--source-hashes`, `--dry-run`, +`--json`, … + +⚠️ **`--objects-only` is on by DEFAULT**, so extract writes only the `objects` / +`globalActions` subtree — while `os i18n check` also demands `app`, `navigation`, +`dashboard`, `widget`, `page` and `flow` keys. Run the workflow as written and coverage +reports gaps the extract never scaffolded. Pass `--no-objects-only` to include those +groups, or author them by hand. ### 2. Translate -Fill in the values manually. (AI suggestion is a contract-only concept — -`suggestTranslations()` has no CLI and no shipped implementation.) +Fill in the values manually. ### 3. Verify Coverage @@ -394,10 +400,37 @@ os i18n check --locales=zh-CN Add `--strict` / `--threshold=95` in CI to fail on locale gaps. -### 4. Commit & Register +### 4. Register + +A stack registers its bundles with `defineStack({ translations: [...] })`. A **package or +plugin shipping its own generated bundle** — the most common shape in this repo — has one +more step: a generated module exports an objects *subtree* +(`NonNullable`), not a `TranslationData`, so it must be +wrapped before it is a bundle at all. + +```typescript +// src/translations/index.ts +import type { TranslationBundle, TranslationData } from '@objectstack/spec/system'; +import { withSourceFallback } from '@objectstack/platform-objects/apps'; +import { enObjects } from './en.objects.generated.js'; +import { zhCNObjects } from './zh-CN.objects.generated.js'; +import { zhCNGeneratedSourceHashes } from './zh-CN.source-hashes.generated.js'; + +const enSource: TranslationData = { objects: enObjects }; + +export const StorageTranslations: TranslationBundle = { + en: enSource, + // 4th argument = the `--source-hashes` companion. Without it a leaf whose SOURCE has + // moved goes on serving the superseded fill under a green `os i18n check` forever. + // The 3rd stays undefined: it judges hand-authored `apps` / `dashboards` / `pages`, + // which a fully generated set does not have. + 'zh-CN': withSourceFallback({ objects: zhCNObjects }, enSource, undefined, zhCNGeneratedSourceHashes), +}; +``` -Commit the translation files, import them into your bundle, and register it via -`defineStack({ translations: [...] })`. +A plugin that owns its objects loads that bundle from its own `kernel:ready` hook rather +than registering it on the stack: `i18n.loadTranslations(locale, data)` deep-merges, so +every plugin contributes its own `objects.*` slice. --- From 4de6130e98c516998be147185d8eb0594c97a5c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:58:25 +0000 Subject: [PATCH 08/12] skills(i18n): make the description trigger on what the body actually teaches (I18N-A-02) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The description triggered on adding *.translation.ts files, wiring a locale and resolving missing-translation warnings. It did not name the `translation` metadata item — nor, after this flight, the package-ships-its-own-generated- bundle shape, which is the highest-count real pattern in the repo and the one construct this flight added. Both are now trigger phrases, so an agent facing either task can load the package at all. "per-locale source layout" became "source layout": the file no longer privileges one of the three. skills/README.md and content/docs/ai/skills-reference.mdx are generator output (`pnpm --filter @objectstack/spec gen:skill-docs`), regenerated because check:skill-docs demanded it; both files carry only the derived description. No prose in skills/README.md was hand-edited — the I18N-A-03 routing bullet is a follow-up recorded in the PR body. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- content/docs/ai/skills-reference.mdx | 6 +++--- skills/README.md | 2 +- skills/objectstack-i18n/SKILL.md | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/content/docs/ai/skills-reference.mdx b/content/docs/ai/skills-reference.mdx index 270b9894f5..41dbf8e18f 100644 --- a/content/docs/ai/skills-reference.mdx +++ b/content/docs/ai/skills-reference.mdx @@ -50,7 +50,7 @@ ObjectStack ships **11 skills** — one per authoring domain, plus process skill | 5 | [Automation](#automation) | `automation` | `skills/objectstack-automation/` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, scheduled jobs, and webhooks. | | 6 | [AI](#ai) | `ai` | `skills/objectstack-ai/` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | 7 | [API](#api) | `api` | `skills/objectstack-api/` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch/versioning contracts. | -| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | 9 | [Formula](#formula) | `expression` | `skills/objectstack-formula/` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. | | 10 | [PM Dispatch](#pm-dispatch) | `process` | `skills/objectstack-pm-dispatch/` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required) and the upstream-reporting procedure for platform defects an app project finds. | | 11 | [Upgrade](#upgrade) | `process` | `skills/objectstack-upgrade/` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. | @@ -159,9 +159,9 @@ Do not use for: consuming an ObjectStack API from a client (that is just standar **Domain** `i18n` · **Path** `skills/objectstack-i18n/` -Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. +Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. -Use when the user is adding `*.translation.ts` files, wiring a new locale, or resolving missing-translation warnings. +Use when the user is adding `*.translation.ts` files, authoring a `translation` metadata item in the Studio or through the metadata API, shipping a generated bundle from a package or plugin, wiring a new locale, or resolving missing-translation warnings. Do not use for general i18n library questions unrelated to ObjectStack bundles. diff --git a/skills/README.md b/skills/README.md index dd1f67036e..6ff22afd41 100644 --- a/skills/README.md +++ b/skills/README.md @@ -36,7 +36,7 @@ apps too). | [Automation](./objectstack-automation/SKILL.md) | `automation` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, scheduled jobs, and webhooks. | | [AI](./objectstack-ai/SKILL.md) | `ai` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | [API](./objectstack-api/SKILL.md) | `api` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch/versioning contracts. | -| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | [Formula](./objectstack-formula/SKILL.md) | `expression` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. | | [PM Dispatch](./objectstack-pm-dispatch/SKILL.md) | `process` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required) and the upstream-reporting procedure for platform defects an app project finds. | | [Upgrade](./objectstack-upgrade/SKILL.md) | `process` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. | diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 7324b6d3f3..43b7099d5a 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -3,10 +3,12 @@ name: objectstack-i18n description: > Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale - fallback, coverage reporting, and the per-locale source layout. Use when - the user is adding `*.translation.ts` files, wiring a new locale, or - resolving missing-translation warnings. Do not use for general i18n - library questions unrelated to ObjectStack bundles. + fallback, coverage reporting, and the source layout. Use when the user is + adding `*.translation.ts` files, authoring a `translation` metadata item in + the Studio or through the metadata API, shipping a generated bundle from a + package or plugin, wiring a new locale, or resolving missing-translation + warnings. Do not use for general i18n library questions unrelated to + ObjectStack bundles. license: Apache-2.0 compatibility: Requires @objectstack/spec 17.x (Zod v4 schemas) metadata: From d0dbe12cd7a29327d558ddde5dac57dbb0a21938 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 11:53:10 +0000 Subject: [PATCH 09/12] skills(i18n): delete the planned-eval stub and step its ratchet ceiling down (I18N-H-01) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maintainer ruling on #14296 (decision batch 1), reply `1A 2A 3A 4A`. Item 2 option A, verbatim from the card: 「删除存根(整包约 −2,200 tokens),保留真实 fixture(ui 的 analytics json、automation 的 approvals md);formula 不新建。」 and 「裁后执行:各飞行内删除存根,棘轮上限随之下调」. skills/objectstack-i18n/evals/README.md was 45 lines / 410 tokens shipped into every customer session: an ASCII tree naming six eval files that do not exist (the package has three files in total), plus Format / Status / Contributing process prose about evals that do not exist. Zero rubrics — nothing in it can grade anything. It is the stub the ruling names. The only change to scripts/check-skills-token-ratchet.mjs is dropping the deleted file's ceiling row; nothing else in that script is touched, and the expanding-remedy authority sweep (check-ratchet-remedy-authority) stays green. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- scripts/check-skills-token-ratchet.mjs | 1 - skills/objectstack-i18n/evals/README.md | 45 ------------------------- 2 files changed, 46 deletions(-) delete mode 100644 skills/objectstack-i18n/evals/README.md diff --git a/scripts/check-skills-token-ratchet.mjs b/scripts/check-skills-token-ratchet.mjs index db0e70145b..e82bf3256e 100644 --- a/scripts/check-skills-token-ratchet.mjs +++ b/scripts/check-skills-token-ratchet.mjs @@ -443,7 +443,6 @@ export const CEILINGS = new Map([ // the remaining skills' eval notes ['skills/objectstack-ai/evals/README.md', 315], ['skills/objectstack-api/evals/README.md', 546], - ['skills/objectstack-i18n/evals/README.md', 411], ]); /** diff --git a/skills/objectstack-i18n/evals/README.md b/skills/objectstack-i18n/evals/README.md deleted file mode 100644 index f1148327e4..0000000000 --- a/skills/objectstack-i18n/evals/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Evaluation Tests (evals/) - -This directory is reserved for future skill evaluation tests. - -## Purpose - -Evaluation tests (evals) validate that AI assistants correctly understand and apply the rules defined in this skill when generating code or providing guidance. - -## Structure - -When implemented, evals will follow this structure: - -``` -evals/ -├── bundle-shape/ -│ ├── test-objects-vs-o-keys.md # runtime `objects.*`; retired `o.*` is rejected -│ ├── test-snake-case-keys.md # object/field keys match metadata machine names -│ └── test-option-machine-values.md # lowercase option values, not display labels -├── interpolation/ -│ └── test-double-brace-params.md # {{userName}}, not {userName}; no ICU engine -├── coverage-workflow/ -│ ├── test-extract-command.md # os i18n extract --locales/--out flags & TS output -│ └── test-check-command.md # os i18n check --strict/--threshold CI gate -└── ... -``` - -## Format - -Each eval file will contain: -1. **Scenario** — Description of the task -2. **Expected Output** — Correct implementation -3. **Common Mistakes** — Incorrect patterns to avoid -4. **Validation Criteria** — How to score the output - -## Status - -⚠️ **Not yet implemented** — This is a placeholder for future development. - -## Contributing - -When adding evals: -1. Each eval should test a single, specific rule or pattern -2. Include both positive (correct) and negative (incorrect) examples -3. Reference the corresponding section of `SKILL.md` -4. Use realistic scenarios from actual ObjectStack projects From 2d550a266792473a7725adfce5c06beb92ae60f5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 11:56:28 +0000 Subject: [PATCH 10/12] skills: regenerate the skill docs on the merged tree (generator output only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pnpm --filter @objectstack/spec gen:skill-docs` re-derived from all 11 SKILL.md files after merging origin/main. The merge conflicted in both generated artifacts because sibling flights changed them on main; main's side was taken and the generator re-derived on top, which is the only safe order for a generated file — resolving one textually would have kept whichever side the driver happened to pick. Asserted after regeneration: every sibling package's row is byte-identical to origin/main's, and both files still carry all 17 rows. The staged diff is this card's i18n description and nothing else. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- content/docs/ai/skills-reference.mdx | 6 +++--- skills/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/docs/ai/skills-reference.mdx b/content/docs/ai/skills-reference.mdx index 84de10f301..b9cb7eb657 100644 --- a/content/docs/ai/skills-reference.mdx +++ b/content/docs/ai/skills-reference.mdx @@ -50,7 +50,7 @@ ObjectStack ships **11 skills** — one per authoring domain, plus process skill | 5 | [Automation](#automation) | `automation` | `skills/objectstack-automation/` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, scheduled jobs, and webhooks. | | 6 | [AI](#ai) | `ai` | `skills/objectstack-ai/` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | 7 | [API](#api) | `api` | `skills/objectstack-api/` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch contracts. | -| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | 9 | [Formula](#formula) | `expression` | `skills/objectstack-formula/` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. | | 10 | [PM Dispatch](#pm-dispatch) | `process` | `skills/objectstack-pm-dispatch/` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required). | | 11 | [Upgrade](#upgrade) | `process` | `skills/objectstack-upgrade/` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. | @@ -159,9 +159,9 @@ Do not use for: consuming an ObjectStack API from a client (that is just standar **Domain** `i18n` · **Path** `skills/objectstack-i18n/` -Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. +Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. -Use when the user is adding `*.translation.ts` files, wiring a new locale, or resolving missing-translation warnings. +Use when the user is adding `*.translation.ts` files, authoring a `translation` metadata item in the Studio or through the metadata API, shipping a generated bundle from a package or plugin, wiring a new locale, or resolving missing-translation warnings. Do not use for general i18n library questions unrelated to ObjectStack bundles. diff --git a/skills/README.md b/skills/README.md index 0871f4e64e..46d44af07c 100644 --- a/skills/README.md +++ b/skills/README.md @@ -36,7 +36,7 @@ apps too). | [Automation](./objectstack-automation/SKILL.md) | `automation` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, scheduled jobs, and webhooks. | | [AI](./objectstack-ai/SKILL.md) | `ai` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | [API](./objectstack-api/SKILL.md) | `api` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch contracts. | -| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | [Formula](./objectstack-formula/SKILL.md) | `expression` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. | | [PM Dispatch](./objectstack-pm-dispatch/SKILL.md) | `process` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required). | | [Upgrade](./objectstack-upgrade/SKILL.md) | `process` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. | From bc84ff2be44b90fecf7aa44f98527bf796e4ecd9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 12:10:01 +0000 Subject: [PATCH 11/12] skills(i18n): author the generated-bundle example through defineTranslationBundle (I18N-F-01 follow-up, I18N-G-05) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check:doc-authoring (#2035, ADR-0059) refused the block: it exported a bare `: TranslationBundle` literal, which is the one pattern that rule exists to keep out of the published catalog. The file's own canonical example already says to prefer the factory over a bare literal, so the block contradicted its own package — the inconsistency audit finding I18N-G-05 recorded from the other side (the flagship shipped example does the discouraged thing). The factory takes the wrapped values unchanged, so the shape the block teaches is the same one; only the authoring form is now the one the skill prescribes. Re-driven against the real exports before and after (throwaway driver in packages/services/service-storage typechecking the exact block against @objectstack/spec + @objectstack/platform-objects, tsc --noEmit exit 0, deleted in the same step with a clean tree). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- skills/objectstack-i18n/SKILL.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 43b7099d5a..519130b15a 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -412,7 +412,8 @@ wrapped before it is a bundle at all. ```typescript // src/translations/index.ts -import type { TranslationBundle, TranslationData } from '@objectstack/spec/system'; +import { defineTranslationBundle } from '@objectstack/spec'; +import type { TranslationData } from '@objectstack/spec/system'; import { withSourceFallback } from '@objectstack/platform-objects/apps'; import { enObjects } from './en.objects.generated.js'; import { zhCNObjects } from './zh-CN.objects.generated.js'; @@ -420,14 +421,14 @@ import { zhCNGeneratedSourceHashes } from './zh-CN.source-hashes.generated.js'; const enSource: TranslationData = { objects: enObjects }; -export const StorageTranslations: TranslationBundle = { +export const StorageTranslations = defineTranslationBundle({ en: enSource, // 4th argument = the `--source-hashes` companion. Without it a leaf whose SOURCE has // moved goes on serving the superseded fill under a green `os i18n check` forever. // The 3rd stays undefined: it judges hand-authored `apps` / `dashboards` / `pages`, // which a fully generated set does not have. 'zh-CN': withSourceFallback({ objects: zhCNObjects }, enSource, undefined, zhCNGeneratedSourceHashes), -}; +}); ``` A plugin that owns its objects loads that bundle from its own `kernel:ready` hook rather From c20ae51e3e6526b24e882e901fa4579813f1e572 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 14:15:23 +0000 Subject: [PATCH 12/12] docs(skills): regenerate the skill catalog after the main merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen:skill-docs run on the committed merge, never in MERGE state. The regenerated artifacts differ from origin/main by exactly this package's own rows — the delta is line-for-line identical to the one this branch authored before the merge — so every sibling flight's row survives as origin/main has it. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy --- content/docs/ai/skills-reference.mdx | 6 +++--- skills/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/docs/ai/skills-reference.mdx b/content/docs/ai/skills-reference.mdx index ca5368fc22..ba048d9f77 100644 --- a/content/docs/ai/skills-reference.mdx +++ b/content/docs/ai/skills-reference.mdx @@ -50,7 +50,7 @@ ObjectStack ships **11 skills** — one per authoring domain, plus process skill | 5 | [Automation](#automation) | `automation` | `skills/objectstack-automation/` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, and the `jobs` (`defineJob`) / `webhooks` (`defineWebhook`) stack collections. | | 6 | [AI](#ai) | `ai` | `skills/objectstack-ai/` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | 7 | [API](#api) | `api` | `skills/objectstack-api/` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch contracts. | -| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| 8 | [i18n](#i18n) | `i18n` | `skills/objectstack-i18n/` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | 9 | [Formula](#formula) | `expression` | `skills/objectstack-formula/` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. This is the companion skill that objectstack-data, -ui, -api and -automation each tell you to load alongside them. | | 10 | [PM Dispatch](#pm-dispatch) | `process` | `skills/objectstack-pm-dispatch/` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required). | | 11 | [Upgrade](#upgrade) | `process` | `skills/objectstack-upgrade/` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. | @@ -159,9 +159,9 @@ Do not use for: consuming an ObjectStack API from a client (that is just standar **Domain** `i18n` · **Path** `skills/objectstack-i18n/` -Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. +Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. -Use when the user is adding `*.translation.ts` files, wiring a new locale, or resolving missing-translation warnings. +Use when the user is adding `*.translation.ts` files, authoring a `translation` metadata item in the Studio or through the metadata API, shipping a generated bundle from a package or plugin, wiring a new locale, or resolving missing-translation warnings. Do not use for general i18n library questions unrelated to ObjectStack bundles. diff --git a/skills/README.md b/skills/README.md index 8111a0462e..ed7bb1ef11 100644 --- a/skills/README.md +++ b/skills/README.md @@ -36,7 +36,7 @@ apps too). | [Automation](./objectstack-automation/SKILL.md) | `automation` | Design ObjectStack automation — Flows (visual logic), Triggers, Approvals, state machines, and the `jobs` (`defineJob`) / `webhooks` (`defineWebhook`) stack collections. | | [AI](./objectstack-ai/SKILL.md) | `ai` | Design ObjectStack AI skills, tools, knowledge sources, conversations, model registry entries, and MCP integrations. | | [API](./objectstack-api/SKILL.md) | `api` | Design the server-side API surface that an ObjectStack runtime exposes — REST endpoints, auth providers, realtime channels, error envelopes, batch contracts. | -| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the per-locale source layout. | +| [i18n](./objectstack-i18n/SKILL.md) | `i18n` | Author ObjectStack translation bundles — object/field labels, view text, app navigation strings, automation messages — and configure locale fallback, coverage reporting, and the source layout. | | [Formula](./objectstack-formula/SKILL.md) | `expression` | Author CEL expressions used across ObjectStack — formula fields, field conditional rules (`visibleWhen`, `readonlyWhen`, `requiredWhen`), validation / sharing / visibility predicates, flow conditions, and dynamic seed values. This is the companion skill that objectstack-data, -ui, -api and -automation each tell you to load alongside them. | | [PM Dispatch](./objectstack-pm-dispatch/SKILL.md) | `process` | Run a project-manager dispatch loop over a GitHub backlog: triage and queue ready issues, claim each one, dispatch it to a parallel developer agent that returns a structured JSON report, review the results against GitHub, and drive accepted pull requests to landing — escalating to the maintainer only what genuinely needs a human decision. Ships the developer-agent operating template the loop injects into every dispatch (no custom agent types required). | | [Upgrade](./objectstack-upgrade/SKILL.md) | `process` | Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. |