Uh oh!
There was an error while loading. Please reload this page.
fix(i18n): the object catalog loses to an explicitly-set scalar (#8284) - #8454
Conversation
`translateObject` resolved `label` / `pluralLabel` / `description` as a flat `catalog ?? document`. The i18n catalog is keyed by object name and is the packaged translation of the PACKAGED declaration, so it overwrote every value authored on top of that declaration: a code-shipped `objectExtensions` scalar, and — the severe half — a tenant's own Studio rename, which answered 200 and then appeared on neither `GET /meta/object` nor `GET /meta/object/:name`. Maintainer ruling, 2026-08-13: the catalog loses to an explicit override, decided by COMPARISON against the packaged base value, with no provenance flag carried through the fold. Implemented per scalar: - spec: `TranslateDocumentOptions.packagedBase`; the catalog applies only while the document's scalar still equals the base's. Absent base restores the pre-#8284 behaviour exactly, so nothing loses a translation it has today. - metadata-protocol: `getPackagedObjectBase`, over the registry's packaged OWNER contributor (never `getArtifactItem`, whose object branch answers the extender-folded body and would call the extension's label unchanged). - rest: hands the base to the translator at the three sites that localize an object document, feature-detected so `RestProtocol` is not widened. `?layers=true` stays untranslated and diagnostic. Arm B (fold drops scalars) is not implemented and stays rejected. Part of #8284 — the second `it.fails` pin does not invert: a package extension's scalar still overwrites a tenant's rename inside `mergeObjectDefinitions`, one layer below the catalog. Filed separately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 3 package(s): 108 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also reference the affected code. These are read-only:
|
`check:generated` proved exactly two artifacts stale, and only those two are regenerated: the one added public export, `TranslateDocumentOptions` in `./system`. Delta vs main: 1 added, 0 breaking (removed/narrowed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
Discharges the os-regen deferral recorded by the merge commit. The merge took main's side of both shards (ADR/AGENTS: never text-merge a generated file), so this restores the branch's one added export on top of main's current content. Delta vs the merged main: 1 added (`TranslateDocumentOptions`), 0 breaking. `check:generated` on the merged tree: all 13 artifacts up to date. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
Uh oh!
There was an error while loading. Please reload this page.
Part of #8284
Part of, notFixes— the dispatch asked forFixes #8284, and this PR does not close it: one of the card's two acceptance pins does not invert, for a reason measured during implementation (below). Merging this and closing #8284 would drop the severe half on the floor.What the ruling asked for, and what this does
Maintainer ruling (2026-08-13, comment 5278888678): the i18n catalog loses to an explicit override, decided by comparison-based provenance — the catalog value applies only while the document's scalar still equals the packaged base value; a scalar that differs was explicitly set and the catalog yields. No provenance flags through the fold, all three scalars, one mechanism,
?layers=trueuntouched.translateObjectresolvedlabel/pluralLabel/descriptionas a flatcatalog ?? document. The catalog is keyed by object name and is the packaged translation of the packaged declaration, so consulting it first discarded whatever had been authored on top of that declaration.Per scalar, the catalog now applies only while
document[key] === packagedBase[key].Why the diff is four packages, not one
Reported before implementing, in this comment. Short version: the comparison needs the packaged base at translate time, and translate time is the REST boundary, where the document is already base + extension fold + tenant overlay + materialization.
packages/spechas no runtime access (Prime Directive #2), so the value must be handed in.specTranslateDocumentOptions.packagedBase; the per-scalar comparison intranslateObject. Absent base ⇒ pre-#8284 behaviour, exactly.metadata-protocolgetPackagedObjectBase(name)— the registry's packaged OWNER contributor.restRestProtocolis not widened andspec/src/contracts/**is untouched).qa/dogfood⛔ The accessor choice is the trap of this card. The protocol's existing artifact lookup (
SchemaRegistry.getArtifactItem) answersresolveOwnerLayer— owner with its extenders folded on. Comparing against that body would report the extension's label as "unchanged" and hand the catalog back the exact case #8037 filed.getPackagedObjectOwner(ADR-0029 D9.8) is the owner alone. Both are pinned side by side inpackages/objectql/src/protocol-packaged-object-base.test.tsso the difference cannot be re-discovered by accident.The half that does NOT invert, and why
The card's second
it.fails— "a tenant's own rename reaches the reads its forms derive from" — staysit.fails. The catalog is no longer what discards the rename; the fold is:mergeObjectDefinitionsapplies an extender's scalars last onto whatever base it receives, and ADR-0029 D9.2 makes the tenant's overlay that base (overlay ?? own, extenders folded on). So the showcase extension'slabel: 'Account (Success Overlay)'overwrites the tenant's'Customer'inside the fold, and the value is not in the document any read serves. No change at the localization layer can put it there.The card measured this without naming it — its own table records
layers.effective = "Account (Success Overlay)"after the rename, i.e. the extension had already beaten the overlay before i18n ran. Whether a package extension's label should outrank a tenant's Studio rename is a fold-precedence decision the ruling did not make, and it is not arm B (nothing here proposes dropping scalars from the fold). Filed as a sub-issue.So this PR converges the three reads on one label — which is the first pin, now plain green — and a new green case pins what holds in the renamed state, so the file is not silent about it.
Verification
@objectstack/spec— full suite: 390 files / 10346 tests passed.@objectstack/objectql,@objectstack/rest,@objectstack/metadata-protocol, dogfood file — see the report comment on 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 for real output.Changeset:
patchon the three shipped packages.Generated by Claude Code