Skip to content

Object-extension fold leaks the extension's label onto ?layers=true only — the two reads #7556 reconciled on FIELDS now disagree on LABEL #8037

Description

@baozhoutao

Found while re-testing #7556 on a baseline that contains its fix. #7556 / PR #8015 is genuinely fixed — do not revert it.GET /meta/object/:name now serves all three account.extension.ts overlay fields, ?layers=true carries them on both code and effective, the edit form renders real controls for them, and a PATCH round-trip persists. Every acceptance clause of platform-core.metadata-registry-serving passes. This is a smaller, adjacent inconsistency the same fold introduces.

Symptom

One object, three metadata reads, two different labels:

readlabel
GET /api/v1/meta/object (list)Account
GET /api/v1/meta/object/showcase_accountAccount
GET /api/v1/meta/object/showcase_account?layers=truecode.label / effective.labelAccount (Success Overlay)

Reproduced 3/3 on baseline 279ee48a (git merge-base --is-ancestor e3c8ed0f8675 HEAD → in build).

Mechanism

examples/app-showcase/src/data/extensions/account.extension.ts:15 declares a label alongside its additive fields:

exportconstAccountExtension=defineObjectExtension({label: 'Account (Success Overlay)',
...
priority: 210,});

mergeObjectDefinitions (packages/objectql/src/registry.ts:137-140) merges fields/validations/indexes additively but overrides the scalars last-writer-wins:

// Override scalar props (last writer wins)if(extension.label!==undefined)merged.label=extension.label;if(extension.pluralLabel!==undefined)merged.pluralLabel=extension.pluralLabel;if(extension.description!==undefined)merged.description=extension.description;

Before #8015 the code layer served the raw MetadataService body straight from the artifact (objects.showcase_account.label = 'Account', 12 fields) and never went through the fold, so the overlay label had nowhere to surface. Now the fold runs on that layer — which is exactly what fixed the fields — and it carries the scalar override with it, while the list and by-name reads still report the base label.

Why the existing pins can't see it

Both agreement pins added with the fix compare field names onlypackages/rest/src/meta-object-extension-agreement.test.ts and packages/qa/dogfood/test/showcase-object-extension-meta-read.dogfood.test.ts reconcile via fieldNamesOf. Both are green (6/6 and 5/5 on this baseline). A scalar divergence is structurally outside what they assert.

Reproduction

  1. Boot the showcase: node packages/cli/bin/run.js dev -a dist/objectstack.json --seed-admin -d file:/tmp/x.db -p <port>
  2. Sign in as admin@objectos.ai (Origin: http://localhost:<port>), take the bearer from set-auth-token.
  3. GET /api/v1/meta/object/showcase_accountitem.label is Account.
  4. GET /api/v1/meta/object/showcase_account?layers=truecode.label and effective.label are Account (Success Overlay).

Expected one object, one label, on every read. Actual the layered read disagrees with the other two.

Which side is right is a decision, not a given

Both readings are defensible and the fix should pick one deliberately:

  • The overlay label should win everywheredefineObjectExtension accepts label, mergeObjectDefinitions documents last-writer-wins, and priority 210 says the extension outranks the base. Then the list and by-name reads are the ones under-reporting.
  • The base label should win everywhere — an additive overlay arguably has no business renaming the object it extends, and the showcase's (Success Overlay) suffix is a fixture affordance, not a product intent. Then the fold should not carry scalars, or defineObjectExtension should refuse a label.

Whichever way it goes, the gate that keeps it from drifting again is extending the two agreement pins past fieldNamesOf to the scalar triple (label, pluralLabel, description) across all three reads.

Scope

Extension-independent objects are unaffected: across all 96 registered objects, no object other than showcase_account gains an extension field, and showcase_task (unextended) serves 24 fields with none of the overlay fields. The fold is also not double-applying — validations stayed at 5 with zero duplicates across three consecutive reads, so the non-idempotency PR #8015 warns about is not firing here.

Source

Extracted from the checklist retest of platform-core.metadata-registry-serving (framework 279ee48a, console 6314e87f2d49).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions