Skip to content

The i18n catalog is resolved ahead of the document, so a tenant's own Studio rename never reaches either /meta/object read — and neither do extension scalar overrides #8284

Description

@huangyiirene

Filed by the PM on behalf of the #8037 dev agent, which measured this but could not file it — GitHub API 403 for its whole session. It invented no issue number anywhere in its commit; this is the first number attached to this defect.

⚠️ This supersedes #8037's framing. #8037 asked for a label leak "in the object-extension fold". The fold is correct on all six properties. The defect is one layer down, in i18n resolution — and its more severe half has nothing to do with extensions at all.

The mechanism

translateObject (packages/spec/src/system/i18n-resolver.ts) resolves label / pluralLabel / description as catalog ?? document. The catalog is keyed by object name and consulted first, so it overwrites whatever the resolution produced.

GET /meta/object (list) and GET /meta/object/:name are translated. ?layers=true is deliberately untranslated — its own comment says so: "Not translated and not cached, both deliberately: this is a diagnostic." That is the entire reason #8037 presented as "onto ?layers=true only".

Traced live, showing the fold is uniform and the loss is downstream:

[BYNAME] fold(showcase_account) baseLabel="Account" -> outLabel="Account (Success Overlay)"
[BYNAME] served label = "Account"          ← discarded downstream
[LAYERS] fold(showcase_account) baseLabel="Account" -> outLabel="Account (Success Overlay)"
[LAYERS] served code="Account (Success Overlay)" effective="Account (Success Overlay)"

⛔ The severe half — a tenant's rename is silently discarded

The extension-override case (#8037) is the milder one. Because the catalog is keyed by object name and wins unconditionally, it also defeats the tenant's own customisation. Measured on a deployment-shaped boot, renaming via the ordinary Studio round-trip (PUT /meta/object/showcase_account200 OK):

Surface Label
GET /meta/object (list) Account
GET /meta/object/:name Account
layers.overlay Customer ← what the tenant actually saved
layers.effective Account (Success Overlay)

The tenant's rename reaches neither read that a writable form derives from. One object serves three different labels, and the only surface showing the saved value is the one explicitly documented as a diagnostic.

⭐ This is another instance of this lane's recurring shape — a 200 that means nothing happened (now the sixth: #7893, #8018, reassignOrphanedMetadata, #7823, #7736, this).

Scope: three scalars, one mechanism

From the enumeration landed in 3a27c46edb (PR #8258) — mergeObjectDefinitions touches six keys in three merge kinds, and the fold has zero divergences across all of them:

Property Merge kind Reads agree?
fields key-keyed spread (idempotent)
validations concatenated (not idempotent, #8027)
indexes concatenated (not idempotent, #8027)
label scalar, last-writer-wins diverges
pluralLabel scalar, last-writer-wins ⚠️ same exposure, not triggered on main
description scalar, last-writer-wins ⚠️ same exposure, not triggered

All three scalars share one mechanism; label is simply the only one the shipped showcase catalog currently triggers (showcase_account has a catalog label, no catalog description).

⛔ Why the obvious fix is a regression in disguise

The dev reverse-verified the card's proposed "easy half" (make the fold drop scalars) as arm B, and it is the load-bearing row:

Case Arm A (revert #8045) Arm B (card's "fold drops scalars") Arm C (revert #7556 fold)
New sweep (19 cases) 🔴 3 🔴 1 (anti-vacuity only) 🔴 7
#8015 agreement pin 🟢 🟢 🔴 2
#8045 fold pin 🔴 2 🟢 🔴 4

Arm B is invisible to both existing pins — caught only by the new anti-vacuity case. It makes the symptom disappear by deleting a documented ObjectExtensionSchema feature, and leaves the tenant-rename defect completely untouched. ⛔ That is why no behavioural change was shipped.

The ruling needed

Should the catalog lose to an explicit override — which requires carrying scalar provenance through the fold, so "this value was explicitly set" is distinguishable from "this value is the packaged default" — or should the untranslated diagnostic be reconciled with the translated reads?

Both candidate directions change behaviour well outside #8037's declared region, which is why this is a decision card rather than a dispatch.

Reproduction

Pinned in packages/qa/dogfood/test/showcase-object-extension-scalar-divergence.dogfood.test.ts (landed in 3a27c46edb): two it.fails cases that turn red when this is fixed. ⛔ Do not "repair" them to green — inverting them is the signal the fix worked.

Related

#8037 (the card this came from; premise corrected) · PR #8258 = 3a27c46edb (the enumeration + repro pins) · #7556/#8015 · #8027/#8045 · #8268 (nameField, a scalar in the same last-writer-wins class — ⚠️ read together) · ADR-0029 D9.2

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions