Repository navigation
spec(i18n): translateObject writes translated field help onto an undeclared help key — the console warns ~520× per page load and drops the value #21948
Description
Filing gate: ① product defect — reach: measured once through a public entry (GET /api/v1/meta/object/:name, then the console UI).
Reader: triage seat first-touch → the lane that owns packages/spec/src/system/i18n-resolver.ts (expected domain:spec); one fix PR.
Dedup (semantic search, open + closed): objectstack "served object field carries undeclared help key, ingestion choke point cannot canonicalize retired spelling help, inlineHelpText translateObject" → 0 hits; objectui "retired spelling help warning console field help" → 7 hits, all closed, none about a served help key (nearest: objectui#10471, objectui#10176 — different keys).
What happens
The metadata read seam overlays translated field help onto the served field def under the key help:
packages/spec/src/system/i18n-resolver.ts,translateObject→translateField:const translatedHelp = lookupObjectFieldAttr(bundle, objectName, name, 'help', opts); if (translatedHelp) next.help = translatedHelp;
FieldSchema declares no help key. Help text is inlineHelpText (and description); the field conversion table in packages/spec/src/data/field.zod.ts already lists help as an alias spelling of inlineHelpText. So the served field shape carries a key the contract does not declare, on every field whose translation bundle has a help entry.
Reach — measured on a stock showcase boot
Framework ce577ec4 (objectstack dev --seed-admin, fresh SQLite), objectui at f9f4a62d (console dev server).
-
GET /api/v1/meta/object/sys_useras the seeded admin → 18 of 27 fields carryhelp. Sample,two_factor_enabled:help=description= "Whether two-factor authentication is enabled for this user. Maintained by the better-authtwoFactorplugin."; noinlineHelpText. -
Showcase's own objects carry none (
GET /api/v1/meta/object/showcase_task→ 0 of 25), so it is the platform objects whose packages ship translation bundles withhelpentries (e.g.packages/platform-objects/src/apps/translations/*.objects.generated.ts). -
Sign in to the console and load any authenticated page → the console's ingestion step logs one warning per such field, e.g.
[ObjectUI] Object `sys_user`, field `two_factor_enabled`: the ingestion choke point CANNOT canonicalize the retired spelling `help`. `FieldSchema` declares neither `help` nor any key sharing its alias spelling ... The key and its value are LEFT on the def523 warnings on one page load, across 73
sys_*objects, repeated on every full load. The value is not rendered.
Expected
The served field def carries only keys FieldSchema declares, so a consumer renders the translated help it is sent, and an authenticated page load logs zero warnings for platform objects.
Not measured
Whether a non-English locale serves a help value that differs from description (i.e. whether a translation is actually lost to users today, beyond the warnings). The en-US sample above has help equal to description.
Provenance: maintainer instruction in the dispatching session, verbatim — 「把这些问题提成 issue」. Found during a browser dogfood sweep of the console; filed by session session_01WEARdKfDHDT7rTuEhLyT1k.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 6, 2026
Path: ② the capabilities an end user meets in the app — translated field help on platform objects | 缺项 (no item asserts a served field carries only declared keys) | P2
Triage: first grade —
bug·priority:p2·domain:spec·area:i18n·pm:queue. Translated help lands on the declared key the bundle entry translates, never on an undeclaredhelpTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T04:54Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/spec/src/system/i18n-resolver.ts(translateObject→translateField, about:2992–:2993) ⇒domain:spec; rationale: the metadata read seam writes a keyFieldSchemadoes not declare. The served shape breaks its own contract, which is the AGENTS rule that machine-readable surfaces must not lie.main(3c7785d4ab):translateFielddoesif (translatedHelp) next.help = translatedHelp;.helpentries (measured: 18 of 27sys_userfields, 73sys_*objects), the translated help is not rendered.helpentry overlays the declared key it was generated from. The dev reads the generator (packages/platform-objects/src/apps/translations/*.objects.generated.tsand its source) to name that key,inlineHelpTextordescription, and does not guess.helpalias onFieldSchema.field.zod.ts's conversion table already nameshelpas a retired spelling.GET /api/v1/meta/object/sys_userserves nohelpkey, and the translated text appears on the declared key in a non-English locale;helpwarnings on a page load.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Claim: PM loop round 1 (this card, per triage's first grade
6009610488) · 2026-10-06T04:58ZSession:
session_01T9u38rswFp5Rw8DswRUReJAccount:
os-project-manager(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-21948-translated-field-help-declared-keyWorktree:
objectstack-issue-21948Domain:
domain:specSeat:
domain:spec#1(seat post #6017)File surface (at
origin/main3c7785d4ab; stop on breach and explain in the report):helpentry translate? Read the translation extractor (packages/clii18n-extract) and the generator ofpackages/platform-objects/src/apps/translations/*.objects.generated.ts, then state with file:line whichFieldSchemakey the field-levelhelpentry is sourced from (inlineHelpText,description, or both).packages/spec/src/system/i18n-resolver.ts,translateObject→translateField(about:2992–:2993): the translated field help overlays the declared key it was generated from, never an undeclaredhelp.helpalias onFieldSchema.field.zod.ts's conversion table already nameshelpas a retired spelling.helpkey (translation.zod.ts) is unchanged.packages/spec/src/system/:helpkey, and the translated text on the declared key, under a control that an untranslated field is unchanged.helpon the served field moves with the change, at the same strength.helpkey (arest/metadata-protocoltest, the dogfood fixtures, the console via.objectui-sha), stop and report the list. The seat revises this claim and declares each file on its lane post first.@objectstack/specpatch, at the level the precedents set for a served-shape fix. Measure withnpm pack.content/docs/releases/, no generated catalog edited by hand.Container & model:
M,mode:subagent,model: opus. The at-tier contract review follows delivery (path legsystem/i18n-resolver.ts).Clause-②: no (expected: no accept-set change; the dev states the measured answer in the PR)
Thread-read: 6009610488
Serial constraints cleared: none of the 3 open PRs touches
system/i18n-resolver.ts,system/translation.zod.ts,data/field.zod.ts, the*.objects.generated.tscatalogs ori18n-extract(scan at this stamp). runtime strings in thedomain:specpackages carry tracker numbers (spec175 andlint83 messages): this lane's share of the #20513 A/A burn-down #20749's latersystem/stages will rewrite test titles insystem/i18n-resolver.test.ts. They are not claimed yet, and whichever lands second mergesmain.objectstack-fleet commentedon Oct 6, 2026
os-dev-report
{ "issue": 21948, "status": "needs_decision", "branch": "claude/issue-21948-translated-field-help-declared-key", "pr": null, "session": "session_01T9u38rswFp5Rw8DswRUReJ", "premise_still_valid": true, "summary": "Stopped before writing code. Two of the dispatch's own stop conditions hold, both measured at origin/main 3c7785d4ab. (1) Step 1 has an unambiguous answer: the declared source key is `description`. The extractor writes objects.OBJECT.fields.FIELD.help from `field.help ?? field.description` (packages/cli/src/utils/i18n-extract.ts:1223). The `help` arm cannot be reached on a spec-valid field, because FieldSchema refuses `help` with unrecognized_keys (measured). `inlineHelpText` is never read. Corpus: the nine bundle source trees author 0 `inlineHelpText` and 0 field `help`, and the nine en bundles carry 523 `help` entries, which is the card's 523 warnings. The generator (scripts/check-i18n-bundles.mjs) spawns the same `i18n extract` command, so it reaches the same line. (2) Step 5 found readers of the served `help` key in another lane: objectui at .objectui-sha 0abd4f9f, three sites (open_questions[0]). The dispatch says to stop there so the seat can revise the claim. Separately, overlaying onto `description` changes what objectui's `description` readers render and write, beyond what the card describes (open_questions[1]). The repro holds, so the premise is valid. One sub-claim of the card is wrong: the console's forms DO render the translated value today, through objectui's kept `field.help || field.description` read. The loss is limited to readers of `description` alone, for example the record detail panel. Neighbouring overlays in translateField: `label` goes onto the declared `label`, options go onto the declared option `label`, and field `description` is not overlaid today except through this `help` entry. None of them has the undeclared-key defect.", "objectui_warning_site": "objectui at 0abd4f9f: packages/core/src/utils/reference-keys.ts:362 (the console.warn in warnUnfoldableRetiredKey, defined at :342), reached through the `no-declared-twin` arm at :415 of canonicalizeRetiredFieldKeys (called at :563). It fires for any undeclared, non-undefined key on a served field def, so it goes quiet once the served def carries no `help`.", "fix_plan_once_decided": "packages/spec/src/system/i18n-resolver.ts translateField (:2992-:2993): write the translated help onto `description` under the rule chosen in open_questions[1], and stop writing `help`. Drop `help?: string` from the exported ObjectFieldLike (:2420): api-surface/system.json records only the interface name, and the index signature keeps assignability. Fix the translateObject docblock (:2909), which says it translates a field's `help`. Pins in packages/spec/src/system/i18n-resolver.test.ts: zh-CN served field has no `help` and carries the translation on `description`; untranslated control unchanged; a field declaring both `description` and `inlineHelpText` gets the translation on `description` with `inlineHelpText` untouched; and for option B, a diverged `description` is kept. Plus a `@objectstack/spec` patch changeset. dispatch-gates over that surface derives 79 commands (saved in the session scratchpad; none run).", "tests": "No code, so no test suite ran. Repro (scratch script, not committed) at 3c7785d4ab: `npx tsx` over packages/spec/src/system/i18n-resolver.ts, calling translateMetadataDocument('object', sys_user-shaped doc, zh-CN bundle). Verbatim: two_factor_enabled came back as {label: '已启用双因素认证', description: 'Whether two-factor authentication is enabled for this user. Maintained by the better-auth `twoFactor` plugin.', help: '该用户是否已启用双因素认证。由 better-auth 的 `twoFactor` 插件维护。'}, and FieldSchema.safeParse returned unrecognized_keys:[\"help\"]. A field declaring both description 'Desc EN' and inlineHelpText 'Inline EN' came back with help: '描述(中文)' and both declared keys untouched, safeParse unrecognized_keys:[\"help\"]. The untranslated control field came back unchanged, safeParse ok. FieldSchema probe: a field with help 'h' gets unrecognized_keys with the message 'Did you mean `help` → `inlineHelpText`?'. NOT MEASURED: dogfood GET /api/v1/meta/object/sys_user (the stop condition came first; the repro is at the resolver seam the route calls). NOT MEASURED: Clause-② (no diff). Expected `no` for options A and B, because no Zod schema is touched.", "mcp_calls": "0 — none", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/21948/comments (this os-dev-report, scripts/pm/post-stamped.mjs over the fleet-write relay). The empty-branch `git push` is not a REST write. No pr_create, no label-write.", "gates": { "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack": "2 — 'this branch changes nothing against origin/main (merge base 3c7785d4a) — nothing to derive'", "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack packages/spec/src/system/i18n-resolver.ts packages/spec/src/system/i18n-resolver.test.ts": "0 — hypothetical fix surface, 79 commands derived for the re-dispatch, none run", "--ran reconciliation": "not run — empty diff, no gate owed" }, "deviations": [ "No PR, changeset or label-write. I stopped at the dispatch's step-5 condition (a cross-lane reader of the served `help` key exists) and at the claim's condition that serving onto the measured key changes consumer rendering beyond the card.", "Step 2 dogfood half not run. The repro was taken at the resolver seam only.", "Branch claude/issue-21948-translated-field-help-declared-key is pushed and empty (at BASE 3c7785d4ab), as the write probe." ], "files_changed": [], "line_budget": "0 additions / 0 deletions (git diff --shortstat BASE...HEAD is empty)", "open_questions": [ { "question": "Readers of the served `help` key exist in another lane: objectui at .objectui-sha 0abd4f9f (read only; none of the options edits objectui). They are packages/plugin-form/src/ObjectForm.tsx:1033 and packages/plugin-form/src/sectionFields.ts:311 (`description: field.help || field.description`), and packages/app-shell/src/utils/resolveActionParams.ts:714 (`helpText: param.helpText ?? field.help ?? field.description`). All three fall back to `description`. Under open_questions[1] option A or B they render the same translated text, and their `help` arm becomes dead. Under option C they would fall back to the English `description`, and the forms would LOSE the translation they render today. I found no reader in rest, metadata-protocol, objectql, runtime, metadata, client, qa/dogfood or docs. Runtime's `labels.FIELD.help` pins read the bundle-shaped field-labels response, a different surface that stays unchanged. The two docs hits (content/docs/protocol/kernel/i18n-standard.mdx:358/:382) are bundle files. The dispatch says the seat revises the claim and declares these readers first.", "options": [ "A — revise the claim to declare the three objectui sites as known readers that need no edit. The fix lands spec-only, and retiring objectui's dead `help` arms is left to the objectui lane.", "B — pair the spec fix with an objectui card that retires the three `help` arms in the same landing window." ], "recommendation": "A. Business need: none of the three needs a change for its rendered text to hold. Long-term: the dead arms are the objectui lane's retirement, and a later card can do it without a cross-repo landing dependency. AI-error: the spec contract tightens either way. Startup scope: B adds a cross-repo coordination cost to a P2 and buys no render change." }, { "question": "Which value is served on `description`, and when? Serving the bundle's `help` on `description` (the measured source key) changes more than the card describes. In a non-English locale, every objectui reader of a served field's `description` gets the translation. That includes the record detail panel (plugin-detail RecordDetailPanel.tsx:206, the intended win) and the Studio authoring surfaces. ObjectFieldInspector.tsx:887-888 binds `def.description` as an editable input. plugin-designer DataModelDesigner.tsx:155 and PropertyEditor.tsx:180 display it. MetadataService.ts:620 writes `description: field.description` on a field save whose document was fetched with `client.meta.getItem('object', NAME)` (:904), and the metadata-admin client sends Accept-Language. Field `label` already has the same exposure today. I did not trace the inspector draft's source read to the line. The catalog has never touched `description` before. Under a flat overlay, an authored field `description` that diverges from the packaged one (from objectExtensions or a tenant overlay) would be replaced by the catalog in EVERY locale, en included, because the en bundles carry help = the packaged description.", "options": [ "A — flat overlay onto `description`, following the field-`label` precedent: the catalog wins whenever an entry exists. Cost: one line. It overwrites a diverged authored `description` on read, in every locale with a bundle entry.", "B — overlay onto `description` under the ADR-0029 D9.2a comparison. The catalog applies only while the served field's `description` equals packagedBase.fields[FIELD].description, decided by the existing valueOverridesPackagedBase predicate (no second comparison). With no packaged base, the catalog applies (the existing conservative edge). Cost: about ten lines plus a pin for each arm. Field `label` stays flat (the #8284 pin scopes it out), so the two field keys follow different precedence. A translated description saved back from a zh-CN Studio session would then count as authored and be served in every locale, which is how object scalars already behave under #8284.", "C — overlay onto `inlineHelpText`, the key FieldSchema's alias table maps `help` to. This contradicts the measured source, because the bundle entry translates `description`. It would serve description text as always-visible help under inputs. It drops the translation from the three objectui form/param readers, which fall back to the English `description`. The extractor would need a matching change." ], "recommendation": "B. Business need, measured: the 523 entries all come from `description`. The zh-CN/ja-JP/es-ES bundles carry real translations; for example zh-CN sys_user.two_factor_enabled differs from the English description. Readers of `description` alone render English today. NOT MEASURED: whether any deployment authors a diverged field description, because no deployment data was available here. So B's protection covers an unmeasured case, but A's overwrite is a regression that A itself introduces. Long-term: B is the same sentence ADR-0029 D9.2a applies one layer down, and the same one the newer translator overlays already use (dashboard `title`, view bulk-action `confirmText` and param `help`). A extends a flat-catalog rule the maintainer ruled against for scalars. C contradicts the extractor. AI-error: all three remove the undeclared key at the producer. A silently replaces an author's text on read, which is the masked-error class. C creates a trap where bundle `help` means `description` but is served as `inlineHelpText`. Startup scope: A is the smallest. B applies an existing predicate and adds no new mechanism, gate or surface. C is the largest. If the maintainer accepts A's overwrite under the field-label precedent, A is the one-line fallback. Neither A nor B closes the Studio write-back of a translated read (MetadataService.ts:620/:904), which already exists for field `label` and the object scalars." } ], "out_of_scope_findings": [ "carrier: the fix PR for this card (it removes the source) · NOT MEASURED, read-only inference, not filed — probable consequence of this card's defect: Studio `saveFields` (objectui 0abd4f9f packages/app-shell/src/services/MetadataService.ts:898-:939) carries per-field server keys from the translated read back into PUT /api/v1/meta/object/NAME. `help` is not in objectui's RETIRED_FIELD_KEYS (packages/types/src/internal/retired-field-keys.ts holds indexed, referenceTo, formula, isSystem, sortOrder). So a field save on a platform object with bundle `help` entries should send `help`, which FieldSchema refuses with unrecognized_keys. Reach would need one measured PUT. The fix removes the source either way. dedupe words: studio saveFields help unrecognized_keys 422 platform object", "carrier: 承接者:无 (packages/cli is not on this card's file surface) · the extractor's `field.help ??` arm (packages/cli/src/utils/i18n-extract.ts:1223) reads a key FieldSchema refuses, so it is dead on every spec-valid field · noted, not filed", "carrier: the fix PR for this card (same function) · translateField never overlays `placeholder`, even though FieldTranslationSchema declares it and the extractor emits objects.OBJECT.fields.FIELD.placeholder (i18n-extract.ts:1224). The nine shipped bundles carry 0 field-level placeholder entries (the 4 per locale are action params), so it is dormant with no reach · noted, not filed", "carrier: 承接者:无 · `inlineHelpText` has no translation path: the extractor never reads it, so an authored one is never offered for translation. The nine bundle sources author 0 of them, so no reach · Acceptance notes only", "carrier: 承接者:无 · docs drift: content/docs/protocol/kernel/i18n-standard.mdx:166 lists a field's `label` / `help` / `placeholder` as display labels, but FieldSchema declares no `help` · Acceptance notes only" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Claim revision (round 1) of claim
6009655572: same session, account, branch, worktree, domain and seat · 2026-10-06T05:15ZThe dev's report
6009797157stopped before writing code, on two of the dispatch's stop conditions. Both are answered here from governing text; neither is a new ruling.1. The source key, measured:
description.objects.<object>.fields.<field>.helpfromfield.help ?? field.description(packages/cli/src/utils/i18n-extract.ts:1223). Thehelparm cannot be reached on a spec-valid field, becauseFieldSchemarefuseshelp.inlineHelpTextand 0 fieldhelp. The nineenbundles carry 523helpentries, which is the card's 523 warnings.6009610488("overlays the declared key it was generated from"), the translated field help is served ondescription.inlineHelpText. That would contradict the extractor, and it would drop the translation from the readers below.2. The precedence on
description: ADR-0029 D9.2a, by the existing comparison.descriptionequalspackagedBase.fields[<field>].description. This is decided byvalueOverridesPackagedBase, ⛔ never a second comparison./meta/objectread — and neither do extension scalar overrides #8284's existing conservative edge.translateDashboardandtranslateObjectfollow, by the same comparison (valueOverridesPackagedBase; ⛔ never a second one)". It is already applied to the object scalars (The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284), views (i18n: a published org overlay on a packaged view label is served to a zh-CN reader as the catalog translation (进行中), not the edit — the view twin of #20680 #20731) and view bulk actions (metadata: a published org overlay on the built-in system_overview dashboard is never served — the plain read and the rendered board keep the shipped body while ?layers=true reports the overlay as effective #20680).labelstays as it is: flat, as its The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284 pin scopes it. This card does not move it.descriptionon read, in every locale,enincluded. That is a regression this change would introduce, and the rule above forbids it.Known readers in objectui, at
.objectui-sha0abd4f9f(read-only, no edit):plugin-form/src/ObjectForm.tsx:1033andplugin-form/src/sectionFields.ts:311(field.help || field.description);app-shell/src/utils/resolveActionParams.ts:714(param.helpText ?? field.help ?? field.description).All three fall back to
description, so they render the same translated text, and theirhelparm becomes dead. Retiring those arms is objectui's, and this PR does not do it. The ingestion warning (packages/core/src/utils/reference-keys.ts:362) goes quiet once the served field carries nohelp.File surface, unchanged in substance:
packages/spec/src/system/i18n-resolver.ts(translateField):descriptionunder the rule above, and nohelp;help?: stringmember of the exportedObjectFieldLikeis dropped. Its index signature keeps assignability; the at-tier review judges the level;translateObjectdocblock that says it translates a field'shelp.packages/spec/src/system/i18n-resolver.test.ts:helpand carries the translation ondescription;descriptionandinlineHelpTextgets the translation ondescription, withinlineHelpTextuntouched;descriptionis kept against a packaged base;@objectstack/specpatchchangeset.Clause-②: nois expected: no Zod schema is touched. The PR states the measured answer.objectstack-fleet commentedon Oct 6, 2026
os-dev-report
{ "issue": 21948, "status": "done", "branch": "claude/issue-21948-translated-field-help-declared-key", "pr": "https://github.com/objectstack-ai/objectstack/pull/21956", "session": "session_01T9u38rswFp5Rw8DswRUReJ", "premise_still_valid": true, "summary": "Implemented claim revision 6009832895 (Q1 → A, Q2 → B). translateField now serves the bundle's field `help` entry on `description` and writes no `help` key (packages/spec/src/system/i18n-resolver.ts:3054). It is gated by ADR-0029 D9.2a through the existing valueOverridesPackagedBase: the catalog applies only while the served description equals packagedBase.fields[FIELD].description. With no packaged base, the catalog applies. A field the base does not declare counts as diverged; the new finder packagedObjectField (:1434) reads both field-map shapes. Field `label` stays flat. ObjectFieldLike drops `help?: string`; the PR states why this is safe (index signature, the api-surface record, a compile probe with a control leg). The translateObject docblock is corrected. Nine pins are added, and both ablation legs went red exactly as predicted. A @objectstack/spec patch changeset is included, with Clause-② measured as `no`. Draft PR #21956 opened, assignee os-project-manager. The five observations are in its Acceptance notes with carriers, and none is addressed. CI is in_progress at report time (14 completed, 0 failed, 18 in progress). I did not wait for it.", "objectui_warning_site": "objectui at 0abd4f9f: packages/core/src/utils/reference-keys.ts:362 (warnUnfoldableRetiredKey), through the no-declared-twin arm at :415 of canonicalizeRetiredFieldKeys. It fires for any undeclared key on a served field def; at HEAD the served platform corpus carries 0 `help` keys (below).", "tests": "All at HEAD 3ad2f22bed. (1) New pins in packages/spec/src/system/i18n-resolver.test.ts:3552: 9 passed (the zh-CN served field has no help, carries the translation on description and parses with no unrecognized_keys; untranslated control unchanged; description+inlineHelpText; a diverged description is kept in zh-CN and en through translateMetadataDocument; an undeclared base field counts as diverged; no base (undefined/null/omitted) means the catalog applies; an absent description is filled; array-shaped fields against an array base; no input mutation). No existing pin asserted a served field help, so none moved. (2) Ablation on the committed head, scripts/ablation-replace.mjs WRAP plus a trap, predictions recorded first. Leg 1 restores BASE's `next.help` write: predicted 7 failed / 2 passed, observed 'Tests 7 failed | 2 passed'. Leg 2 is a flat overlay (the D9.2a comparison replaced by true): predicted 3 failed (the diverged, undeclared-field and array cases), observed 'Tests 3 failed | 6 passed'. Each leg showed anchor 1 → 0 on disk and was restored with blob a8eade91 == HEAD and git diff HEAD empty. The test imports src via a relative path, so no dist was involved. (3) Corpus at the resolver seam (scratch script): the platform-objects extract config, 48 objects / 617 fields, real bundles. BASE behaviour (leg-1 mutation): 332 served help keys, 332 refused by FieldSchema, sys_user 18 of 26. HEAD: 0, 0, 0 of 26, and in zh-CN 332 descriptions equal the bundle entry; sys_user.two_factor_enabled.description is the Chinese text. NOT MEASURED: the HTTP door GET /api/v1/meta/object/sys_user, because the spec change invalidates the showcase closure (62 of 63 turbo tasks miss). (4) Spec full local project: Test Files 619 passed, Tests 18480 passed | 1 todo. Spec typecheck exit 0, with the test layer compiled and the debt held. service-analytics (the ObjectFieldLike importer) typecheck exit 0, and its 3 translateObject label suites pass, 53 tests. (5) Clause-② probe against the rebuilt dist/system/index.d.ts, exit 0: writing and reading `help` on ObjectFieldLike compile, and `const proof: number = ({} as ObjectFieldLike).help` compiles. The control against the same .d.ts with BASE's `help?: string` restored gives exit 2, with exactly one TS2322 on the proof line. (6) npm pack --dry-run of @objectstack/spec 17.6.0 ships dist/system/index.js, .mjs and .d.ts; both runtime files carry packagedObjectField and 0 `next.help = translatedHelp`.", "mcp_calls": "0 — none", "api_writes": "4 in this session — POST /repos/objectstack-ai/objectstack/issues/21948/comments ×2 (os-dev-report round 1, comment 6009797157, and this report), POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft forced, #21956), POST /repos/objectstack-ai/objectstack/issues/21956/assignees (label-write --assign os-project-manager). All went over the fleet-write relay, and each read-back matched. git push ×3 to the branch (the empty probe and two commits) are not REST writes.", "gates": { "node scripts/check-adr-0087-registration.mjs --base origin/main": 0, "node scripts/check-adr-0087-registration.mjs --self-test": 0, "node scripts/check-changeset-no-major.mjs --base origin/main": 0, "node scripts/check-changeset-no-major.mjs --self-test": 0, "node scripts/check-ci-filter-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs --self-test": 0, "node scripts/check-comment-mask-adoption.mjs": 0, "node scripts/check-comment-mask-adoption.mjs --self-test": 0, "node scripts/check-comment-mask-corpus.mjs": 0, "node scripts/check-dev-prereqs.mjs --self-test": 0, "node scripts/check-dts-emitted.mjs --self-test": 0, "node scripts/check-empty-changeset.mjs --base origin/main": 0, "node scripts/check-empty-changeset.mjs --self-test": 0, "node scripts/check-issue-citations.mjs": 0, "node scripts/check-keyed-text-bounds.mjs": 0, "node scripts/check-keyed-text-bounds.mjs --self-test": 0, "node scripts/check-platform-object-tenancy-census.mjs": 0, "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0, "node scripts/check-plugin-teardown-shape.mjs": 0, "node scripts/check-plugin-teardown-shape.mjs --self-test": 0, "node scripts/check-registry-log-declared.mjs": 0, "node scripts/check-registry-log-declared.mjs --self-test": 0, "node scripts/check-rest-log-spy-declared.mjs": 0, "node scripts/check-rest-log-spy-declared.mjs --self-test": 0, "node scripts/check-spec-docblock-symbol-anchors.mjs": 0, "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test": 0, "node scripts/check-system-context-census.mjs": 0, "node scripts/check-system-context-census.mjs --self-test": 0, "node scripts/check-undeclared-dep-imports.mjs": 0, "node scripts/check-undeclared-dep-imports.mjs --self-test": 0, "node scripts/docs-audit/check-affected-docs.mjs": 0, "node scripts/docs-audit/check-drift-comment.mjs": 0, "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0, "node scripts/release-pending-publish.mjs --self-test": 0, "pnpm --filter @objectstack/lint run check:doc-formula-expressions": 0, "pnpm --filter @objectstack/spec run check:api-surface": 0, "pnpm --filter @objectstack/spec run check:authorable-surface": 0, "pnpm --filter @objectstack/spec run check:browser-reachable-entries": 0, "pnpm --filter @objectstack/spec run check:docs": 0, "pnpm --filter @objectstack/spec run check:dual-source-exports": 0, "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0, "pnpm --filter @objectstack/spec run check:empty-state": 0, "pnpm --filter @objectstack/spec run check:entry-nameability": 0, "pnpm --filter @objectstack/spec run check:export-origins": 0, "pnpm --filter @objectstack/spec run check:exported-any": 0, "pnpm --filter @objectstack/spec run check:liveness": 0, "pnpm --filter @objectstack/spec run check:llms-txt": 0, "pnpm --filter @objectstack/spec run check:objectui-pin-citations": 0, "pnpm --filter @objectstack/spec run check:skill-refs": 0, "pnpm --filter @objectstack/spec run check:strictness-ledger": 0, "pnpm --filter @objectstack/spec run check:variant-docs": 0, "pnpm --filter @objectstack/spec run check:yaml-examples": 0, "pnpm check:changeset-gate-self-tests": 0, "pnpm check:cross-package-test-inputs": 0, "pnpm check:dispatcher-error-vocabulary": 0, "pnpm check:doc-authoring": 0, "pnpm check:driver-memory-census": 0, "pnpm check:dts-closure": 0, "pnpm check:dual-build-cjs-loads": "3 — NOT MEASURED: PREREQUISITE NOT MET (78 packages have no dist/). Narrowed: all 19 require entries of @objectstack/spec exports load from the rebuilt dist", "pnpm check:engine-double-contract": 0, "pnpm check:gitlink-declared": 0, "pnpm check:issue-citations": 0, "pnpm check:lean-entry-closure": "0 — after building the objectql closure (the first run answered 3, PREREQUISITE NOT MET: objectql/core unbuilt)", "pnpm check:logger-receiver-detach": 0, "pnpm check:merge-driver": 0, "pnpm check:nul-bytes": 0, "pnpm check:objectql-double-limit": 0, "pnpm check:objectui-changeset": 0, "pnpm check:org-identifier": 0, "pnpm check:page-declaration-shape": 0, "pnpm check:pm-changeset-deadline-census": 0, "pnpm check:pm-prior-rulings": 0, "pnpm check:published-files": 0, "pnpm check:query-options-erasure": 0, "pnpm check:refd-timer-probe": 0, "pnpm check:slot-lookup": 0, "pnpm check:sourcemap-no-sources-content": 0, "pnpm check:spec-parsed-alias": 0, "pnpm check:test-source-alias": 0, "pnpm check:tier-file-adoption": 0, "pnpm check:type-check-coverage": 0, "pnpm check:type-check-debt": 0, "pnpm check:watch-hint-literal": 0, "pnpm check:where-matcher": 0, "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran-exit.txt": "0 — 'Run reconciliation — 85 derived, 84 run, 1 NOT-MEASURED, 0 UNRUN'", "pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2": "0 — Test Files 619 passed, Tests 18480 passed | 1 todo", "pnpm --filter @objectstack/spec typecheck": 0, "pnpm --filter @objectstack/spec check:generated": 0, "pnpm --filter @objectstack/service-analytics typecheck": 0, "pnpm --filter @objectstack/service-analytics exec vitest run (dimension-labels, dataset-order-labels, dataset-reference-dimension-labels)": "0 — Tests 53 passed", "npx eslint --no-inline-config (the 2 changed .ts files, targeted — not the repo-wide lint, which is CI's)": "0 — 0 errors, 0 warnings" }, "deviations": [ "check:dual-build-cjs-loads is NOT MEASURED: `pnpm check:dual-build-cjs-loads` gives 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/' (78 packages). Declared narrowing: all 19 require entries of @objectstack/spec load from the rebuilt dist. CI builds everything and runs the full gate.", "Dogfood HTTP half NOT MEASURED. Reason: the spec change invalidates the 63-task showcase build closure (62 misses). It was replaced by a corpus run at the same translateMetadataDocument seam, with a BASE control leg.", "origin/main moved to 01e0f71ad8 (#21947, #21940, #21953). None touches this PR's files, so per the dispatch it is not merged.", "The PR's labels documentation, size/m, tests, tooling and protocol:system were set by another actor (the labelers), not by this session. Left as found." ], "files_changed": [ ".changeset/21948-spec-field-help-served-on-description.md", "packages/spec/src/system/i18n-resolver.test.ts", "packages/spec/src/system/i18n-resolver.ts" ], "line_budget": "257 additions / 11 deletions (git diff --shortstat BASE...HEAD: 3 files changed, 257 insertions(+), 11 deletions(-))", "open_questions": [], "out_of_scope_findings": [ "carrier: this PR (removes the source) · Studio saveFields write-back: objectui 0abd4f9f MetadataService.ts:898-:939 carries per-field server keys from the translated read into the object PUT, and `help` is not in objectui RETIRED_FIELD_KEYS · NOT MEASURED, read-only inference, in the PR's Acceptance notes · dedupe words: studio saveFields help unrecognized_keys platform object", "carrier: domain:cli (none in flight) · the extractor's dead `field.help ??` arm, packages/cli/src/utils/i18n-extract.ts:1223 · Acceptance notes", "carrier: none · field `placeholder` declared on FieldTranslationSchema and extracted (:1224) but never overlaid by translateField; 0 field-level placeholder entries in the nine shipped bundles, so dormant · Acceptance notes", "carrier: none · `inlineHelpText` has no translation path (the extractor never reads it); 0 authored in the nine bundle sources · Acceptance notes", "carrier: none · content/docs/protocol/kernel/i18n-standard.mdx:166 lists a field `help` display label, which FieldSchema does not declare · Acceptance notes" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Contract review
Served-tier:
CONTRACT_REVIEW_TIERHead-sha:
3ad2f22bed534424e1af81d7d96c38eab84afd0dLocal-runs: none
Read: card #21948 (body and all five comments: triage
6009610488, claim6009655572, report6009797157, claim revision6009832895, report6010641236), PR #21956 (body, file list, net diff againstmainat merge-base3c7785d4ab: 3 files, +257/-11), and the check-runs on the head. Review owed on the path leg: the diff movespackages/spec/src/system/i18n-resolver.ts, a non-test source file. No governed surface is in the file list.① Derived judgments
helpkey — right.translateFieldno longer writesnext.help.FieldSchemais strict and declares nohelp(its alias table atpackages/spec/src/data/field.zod.ts:1038nameshelpa retired spelling ofinlineHelpText, refused with a prescription, not converted), so this is the served shape coming back to its own contract, as triage's direction required.objects.OBJECT.fields.FIELD.helpentry is served ondescription— right. The measurement holds: the extractor writes that entry fromfield.help ?? field.description(packages/cli/src/utils/i18n-extract.ts:1223); thehelparm is unreachable on a spec-valid field, and the extractor never readsinlineHelpText. So the entry is a translation ofdescription, and triage's "the declared key it was generated from" namesdescription.inlineHelpTextis rightly excluded: serving there would put description text under every input and would drop the translation from the three objectui readers that fall back todescription. Observation, not a defect of this diff:FieldTranslationSchema.helpis still described as "Translated help text" and aliaseshelpText/hint/tooltip, so by name it reads as inline help while by source it isdescription; the resolver's docblock now states the real meaning, the schema's describe text and the docs do not (③, note 5).valueOverridesPackagedBase(:2860).packagedObjectField(:1434) is a finder, not a comparison: it returns the same three answers aspackagedPart(:1407) —undefinedwhen no base was supplied,{}when the base declares no such field, the packaged field otherwise — over the record-keyed field map and the array shapetranslateObjectalready accepts, and it compares nothing. "No base means the catalog applies" is the predicate's first conservative edge; "a field the base does not declare counts as diverged" ispackagedPart's documented convention for views and dashboards. Reach at the HTTP door is real:packages/rest/src/meta-item-read-gate.ts:2147mapsobjecttogetPackagedObjectBase, and bothtranslateMetaList(:2233) andtranslateMetaDocument(:2273) pass it, as does the public form route (rest-server.ts:10934), so the comparison is made on the served reads — the PR's "NOT MEASURED: the HTTP door" is a measurement gap, not a reach gap, and CI's dogfood jobs ran green on the head. One edge sized:getPackagedObjectBasereturns the owner contributor alone (metadata-protocol/src/protocol.ts:8250), so a field a code package contributes throughobjectExtensionsis "not declared" and its description is never translated by the catalog. Measured againstmain: the extractor does not walkobjectExtensions, no shipped package but the showcase declares any, and the showcase's translation sources carry 0 fieldhelpentries — nothing is withheld today. That is a pre-existing gap in the extractor, not a defect this PR introduces; recorded so the convention's cost on object fields is visible.labelstays flat — right. Its lines are untouched and the new pin asserts it beside a divergeddescription.ObjectFieldLike(@objectstack/spec/system) dropshelp?: string— right atpatch. The[key: string]: anyindex signature stays, so a caller that writes or reads.helpstill compiles; the one type-level delta isObjectFieldLike['help']typedanyinstead ofstring | undefined, a loosening — no value or expression that compiled is refused now.packages/spec/api-surface/system.json:462records the interface by name only, socheck:api-surfaceis blind to the member; the dev's compile probe with its control leg (PR body) is the measurement, and the one in-repo importer (services/service-analytics/src/plugin.ts:8) readsoptionsonly. Not an accept-set change.packagedObjectFieldis module-private;FieldSchemaandFieldTranslationSchemaare untouched;check:export-origins,check:authorable-surfaceandSpec property livenessare green on the head..objectui-shais0abd4f9f8769at the merge-base, atorigin/mainand at the head. At that pinplugin-form/src/ObjectForm.tsx:1033,plugin-form/src/sectionFields.ts:311(field.help || field.description) andapp-shell/src/utils/resolveActionParams.ts:714(param.helpText ?? field.help ?? field.description) all fall back todescription, so they render the same translated text and theirhelparm is dead. The one otherfield.helpin objectui (metadata-admin/inspectors/FlowNodeConfigField.tsx:570) reads aFlowConfigField, not a served object field./meta/objectread — and neither do extension scalar overrides #8284, and the per-fieldlabelscoping is kept verbatim.import { FieldSchema }has precedent in the same file (lines 769, 991, 1205, 2650, 2858, 2938); the ablation legs in the PR body went red as predicted. No new id: no added test title, test string or runtime string carries a tracker id;#21948appears only in code comments and the changeset.② Semver level
@objectstack/specpatch,Clause-②: no— right.patch(AGENTS Post-Task Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3). The served-shape change — a non-English locale now serves the translation ondescription, where it served English; every reader ofdescription(record detail panel, Studio inspectors) shows translated text — has its precedent atpatch:427344c(The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284, 17.0.0 Patch Changes: the object catalog yields to an explicit scalar, with REST handing the base, so served output changed) and01a7337(A package extension's scalar overwrites a tenant's Studio rename inside the object fold, so the rename still reaches no read #8460, Patch Changes: the fold's D9.2a).#20680and#20731sat in 17.6.0 Minor Changes, but their entries name a parameter type gain (ResolveOptionstoTranslateDocumentOptions) as the caller-visible change and state the served output was byte-identical without a base — a widening this diff does not make, sincetranslateObjectalready tookTranslateDocumentOptions.Clause-②: noholds: no schema, parse or export accepts more or less; the interface edit loosens a type under an index signature; no(widening)/(narrowing)arm is owed, nothing an author can write is removed or renamed, so no FROM/TO migration is owed. The changeset body carries the Clause line;Check Changesetis green.descriptionsaved back from a non-English Studio session counts as authored and is served in every locale) is the The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284 class fieldlabelalready has, named in the claim revision;patchcovers it under that precedent.③ Boundary flags
/meta/objectread — and neither do extension scalar overrides #8284's catalog layer, and the resolver's own rule statements (:1008–:1035,:1557–:1583) say every translatable string follows that sentence by the one comparison; metadata: a published org overlay on the built-in system_overview dashboard is never served — the plain read and the rendered board keep the shipped body while ?layers=true reports the overlay as effective #20680 and i18n: a published org overlay on a packaged view label is served to a zh-CN reader as the catalog translation (进行中), not the edit — the view twin of #20680 #20731 applied it to new strings without a new ruling.descriptionwas a key the catalog never touched, so the arm that would have needed a ruling is the flat overwrite (it would introduce the The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284 defect class on a new key), not the conservative one chosen. Observation: within one field,labelis now flat anddescriptionis D9.2a; the docblock says so, and the label scoping is The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284's pin, outside this card.saveFieldscarryinghelpinto the PUT: this PR removes the source; reach unmeasured (one PUT), carrier right. (2) The extractor's deadfield.help ??arm:domain:cli, right. (3)placeholderdeclared onFieldTranslationSchemaand extracted (:1224) but never served: dormant (0 shipped entries), but it is the declared-but-unenforced class Prime Directive chore: version packages #10 says takes a card, not a note — escalated to the seat to file; carriernoneis not enough for it. (4)inlineHelpTexthas no translation path: a gap, a note is right. (5)i18n-standard.mdx:166lists a fieldhelpdisplay label: pre-existing drift; with this PR the convention "bundlehelptranslates serveddescription" lives only in the resolver docblock — escalated with note 5 as one docs follow-up that also coversFieldTranslationSchema.help's describe text.check:dual-build-cjs-loadsNOT MEASURED locally (nodist/): CI'sBuild CoreandLint & Repo Gatescover it. The dogfood HTTP half NOT MEASURED locally: CI'sDogfood Regression Gate(3/3) andDogfood Verify CLIran on the head.origin/mainmoved without touching these files: not merged, per the dispatch.success—Build Core,Lint & Repo Gates, the five Type Check jobs (source gates, consumer gates, debt ledger, workspace,TypeScript Type Check),Test Core1/6 through 6/6 and its rollup,Dogfood Regression Gate1/3 through 3/3 and its rollup,Dogfood Verify CLI,Temporal Conformance (live PG + MySQL),Check Changeset,Spec property liveness,Governed Surface Queue Guard,Flag docs affected by code changes,Check Documentation Links,Check PR Size,Auto Label,filter, and the four PR-claim guards; 3skippedby the path filter —Build Docs,Console Pin Gate,Packed-tarball smoke (opt-in); 0 failed, no job lost to its runner. The pin-gate skip costs nothing here: the diff removes no export the pinned sibling could import by name (ObjectFieldLikestays), and a.helpread there still compiles through the index signature.Implemented-by:
claude/issue-21948-translated-field-help-declared-keyReviewed-by:
session_01T9u38rswFp5Rw8DswRUReJVERDICT: PASS
Read at 2026-10-06T06:57Z; read-only — the diff, the card and the head's check-runs; nothing built, run or re-run locally.
objectstack-fleet commentedon Oct 6, 2026
ACCEPT — PR #21956 at
3ad2f22bed(#21948: a served object field carries its translated help ondescription, never on an undeclaredhelp)domain:specseat 1 ·os-project-manager· sessionsession_01T9u38rswFp5Rw8DswRUReJ· 2026-10-06T06:59Z.This is the review of record for the report
6010641236, read with:6009797157;6009655572and its revision6009832895.The at-tier contract review is owed on the path leg (
packages/spec/src/system/i18n-resolver.ts). Its record is PASS6011100461on this head.Checklist (read on GitHub, not from the reports):
Form: draft, base
main, first lineFixes #21948, andClause-②: nostands in the body and the changeset.Scope: 3 files, +257 / −11, exactly the revised claim:
translateFieldand a new finder,packagedObjectField;ObjectFieldLikemember and the docblocks ini18n-resolver.ts;i18n-resolver.test.ts;No cross-lane file. No objectui file.
Changeset:
@objectstack/specpatch, the level of The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either/meta/objectread — and neither do extension scalar overrides #8284 (427344c) and A package extension's scalar overwrites a tenant's Studio rename inside the object fold, so the rename still reaches no read #8460 (01a7337): a served-output change in a translator, with no accept-set move and no new parameter type.Merge: clean onto
mainat80f9f7e6ba, with no file overlap since the base; the merge queue holds no ref at the landing read.check-governed-merges: 0 of 3 paths.What the record establishes, checked against the claim revision:
helpfromfield.help ?? field.description(packages/cli/src/utils/i18n-extract.ts:1223). Thehelparm cannot be reached on a spec-valid field, andinlineHelpTextis never read. So the translation is served ondescription, andinlineHelpTextis rightly untouched.packagedObjectFieldonly locates the packaged counterpart, withpackagedPart's three answers. The only comparison isvalueOverridesPackagedBase.labelstays flat, documented in the docblock.packagedBase(meta-item-read-gate.ts,rest-server.ts), which the reviewer read.helpkeys, all refused byFieldSchema(sys_user18 of 26);descriptions carry the bundle entry.helpwrite: 7 failed / 2 passed;ObjectFieldLikedropshelp?: stringunder its[key: string]: anyindex signature. That is a type loosening, and no compiled caller is refused. The dev's compile probe and its control leg are in the PR body..objectui-sha0abd4f9f: its three readers (ObjectForm.tsx:1033,sectionFields.ts:311,resolveActionParams.ts:714) fall back todescription, so they render the same translated text. The ingestion warning (reference-keys.ts:362) fires for any undeclared key, and the served corpus now carries none.CI on
3ad2f22bed: complete, 35 check-runs: 32 success and 3 skipped, 0 failed.check-expected-skipsreads all three skips (Build Docs, Console Pin Gate, Packed-tarball smoke) as in its roster.Deviations, accepted:
check:dual-build-cjs-loadsNOT MEASURED locally (nodist/for 78 packages), narrowed to the 19 spec entries, and run in full by CI;Out of scope, noted. Each of these pre-exists the PR, and none is introduced by it:
saveFieldswrite-back of a translated read (objectuiMetadataService.ts:898-939): NOT MEASURED, and this PR removes thehelpsource. The same exposure pre-exists for fieldlabeland the object scalars. Carrier: none.field.help ??arm (domain:cli). Carrier: none.FieldTranslationSchema.placeholderis declared and extracted, buttranslateFieldnever serves it. That is the declared-not-enforced class. It is not filed: the nine shipped bundles carry 0 field-level placeholder entries, so there is no producer and no reach (filing gate ①). Carrier: none until a bundle carries one.reach:: one measured wrong result at a public door, or a named real producer. With 0 entries authored, there is neither. The first bundle that carries a fieldplaceholderis that reach, and the card is filed then.inlineHelpTexthas no translation path, and 0 are authored in the bundle sources. Carrier: none.content/docs/protocol/kernel/i18n-standard.mdx:166andFieldTranslationSchema.help's describe text ("Translated help text") should say that a field's bundlehelpis the translation of the serveddescription. Carrier: the next docs PR that touches that page.getPackagedObjectBasereturns the owner alone, so a field contributed byobjectExtensionscounts as diverged and is never catalog-translated. The extractor never walksobjectExtensions, and no shipped bundle carries such an entry, so nothing is withheld today. Carrier: none.Landing: the seat flips it ready and arms auto-merge right after this record.
Fixes #21948closes the card on merge.objectstack-fleet commentedon Oct 6, 2026
Landed: PR #21956 →
bab76850cd. The card is closedcompleteddomain:specseat 1 ·os-project-manager· sessionsession_01T9u38rswFp5Rw8DswRUReJ· 2026-10-06T07:41Z · holder of claim6009655572(revised6009832895), which this act releases.description, never on an undeclaredhelp#21956 merged through the merge queue at 2026-10-06T07:40Z asbab76850cd. It has one parent (80f9f7e6ba) and is an ancestor oforigin/main.Fixes #21948closed the cardcompleted.origin/mainare blob-equal to the reviewed head3ad2f22bed(at-tier PASS6011100461, ACCEPT6011127313).helpkey. The platform-objects corpus served 332 before and serves 0 now, so the console's warning about an undeclared field key stops for this cause.description. A field's bundlehelpentry, which the extractor writes fromdescription, is served ondescription.valueOverridesPackagedBase. The REST object reads hand the packaged base, so this applies at the HTTP door.labelis unchanged. Fieldlabelstays flat.description, so they show the translated text with no objectui edit.ObjectFieldLikedropshelp?: stringunder its index signature.@objectstack/specpatch.FieldTranslationSchema.placeholderis declared and never served. It is held at a note until a bundle carries a fieldplaceholder(filing gate ①).i18n-standard.mdx:166and theFieldTranslationSchema.helpdescribe text should say that a field's bundlehelptranslates the serveddescription. Carrier: the next docs PR on that page.saveFieldswrite-back, the extractor's deadhelparm,inlineHelpText, and theobjectExtensionsedge.packages/spec/src/system/i18n-resolver.ts(translateField). runtime strings in thedomain:specpackages carry tracker numbers (spec175 andlint83 messages): this lane's share of the #20513 A/A burn-down #20749's latersystem/stages that renamei18n-resolver.test.tstitles now merge onto this.This act removes
pm:dispatchedand the assignee.fix(spec): serve a field's translated help on `description`, never on…
test(spec): the first system/ file group's test titles state each cit…