Skip to content

Should the sys_metadata overlay merge move down into MetadataService.list(), so every consumer gets merged rows? #8722

Description

@qq9340100

Archived per the maintainer ruling on #8328 (option 3, recorded 2026-08-13 ~23:50Z). Unscheduled by decision — filed so the divergence is recorded, not so it gets done. It re-grades only when real business pull appears.

The divergence

Two layers answer "what rows exist for this metadata type", and they disagree whenever a runtime override exists:

  • IMetadataService.list(type) — the registry plus this service's own loaders. No sys_metadata overlay merge.
  • the metadata protocol's getMetaItems({ type }) — merges the sys_metadata customization overlay over the registry and MetadataService baselines, resolved per (slot, package), org-scoped rows over env-wide ones.

So after a runtime PUT to /api/v1/meta/[type]/[name] returns 200, list() keeps answering with the packaged row while GET /api/v1/meta/[type] serves the overridden one. Same name, two answers.

Why it is worth recording rather than fixing now

Measured on #8328: the MCP prompt bridge read list('skill') and served prompts an admin had already overridden through the meta API. That consumer is fixed in PR #8724 by pointing it at the merged read — a per-consumer repair, which leaves the divergence itself in place for the next consumer.

The trap has no local symptom, which is what makes it worth a card: at the call site the type is the same, the shape is the same, and only the CONTENT is stale — and only when an override happens to exist. Every new consumer of list() can rediscover it, and each rediscovery is individually green. PR #8724 marks the trap in the contract's TSDoc so it is at least visible at the point of use.

The question, stated for whoever picks it up

Is the overlay merge part of the metadata contract (so it belongs in list(), and every consumer gets it), or is it a protocol-layer serving concern (so climbing a layer is correct and the contract note is the right permanent answer)?

Costs of moving it down, as understood at filing time:

  • it is a cross-lane contract change touching every IMetadataService implementation and every list() consumer;
  • some consumers legitimately want the authored baseline rather than the overridden view, so "merge for everyone" is not obviously right — it may need to be a second member rather than a change to list();
  • getMetaItems also applies org scoping, draft preview, disabled-package filtering and artifact-protection governance; only the overlay-merge part of that is in question here.

⛔ Deliberately not chosen on #8328: cross-lane contract change with zero measured pull at the time. Do not read this card as a queued intention — it is a record.

Back-link: #8328 · implementation PR: #8724

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions