Repository navigation
Description
Surfaced while building a list-vs-by-name field-set reconciliation for platform-core.metadata-registry-serving. __search is the only residual field-set difference between the two /meta/object reads anywhere in the registry — which makes it the one thing standing between the platform and a clean cross-read agreement gate. It is also, on its own, a self-inconsistency.
Distinct from #7561 (which was about fields.__search carrying an index key that FieldSchema rejects, invalidating /meta/diagnostics) and from #7642 (which was about __search echoing in record bodies). This is the metadata read, and the defect is that one route gives two answers.
Measurement
Showcase, admin bearer, baseline 279ee48a. All 96 registered objects walked, by-name read fetched for each:
list GET /meta/object |
by-name GET /meta/object/:name |
|
|---|---|---|
22 package objects (showcase_*) |
__search present |
__search absent |
71 platform objects (sys_*) |
__search present |
__search present |
3 objects (sys_session, sys_audit_log, showcase_project_membership) |
absent (no companion provisioned) | absent |
The split is exact — 22/22 and 71/71, zero exceptions in either direction. It keys on provenance (package-declared vs platform), not on whether the object is extended, searchable, or large: 21 of the 22 carry no object extension at all.
So GET /meta/object/showcase_account reports 22 fields while GET /meta/object/sys_metadata reports its companion column as a normal field, from the same route, in the same response shape.
Why it matters
__searchis declared client-invisible. The__searchcompanion column, declared client-invisible, is echoed in every record body #7642 fixed exactly that contract on the record-body door and its clause is green on this baseline. The metadata door was never brought along — so the internal search-normalization companion (packages/objectql/src/search-companion.ts,SEARCH_COMPANION_FIELD, 通用拼音搜索:locale 开关 + 名称字段拼音伴随列(接入 ADR-0061,纯加性) #2486) is still published to every metadata reader for the list route and for 71 of 93 by-name reads.- A consumer cannot write one correct rule. Studio, form derivation, and any agreement gate must currently special-case
sys_*vs package objects to get the same field set from the same route. - It silently weakens the new cross-read pins.
packages/rest/src/meta-object-extension-agreement.test.tsandpackages/qa/dogfood/test/showcase-object-extension-meta-read.dogfood.test.ts(added with Object-extension overlay fields are missing fromGET /meta/object/:name(present in the list route) — the overlay's fields can never be set through the UI #7556's fix) reconcile list against by-name — they are green only because they scope toshowcase_account, which happens to sit on the stripping side. Widen either pin to asys_*object and it goes red on this column alone.
Reproduction
- Boot the showcase:
node packages/cli/bin/run.js dev -a dist/objectstack.json --seed-admin -d file:/tmp/x.db -p <port> - Sign in as
admin@objectos.aiwithOrigin: http://localhost:<port>; take the bearer from theset-auth-tokenresponse header. GET /api/v1/meta/object/showcase_account→item.fieldshas no__search.GET /api/v1/meta/object/sys_metadata→item.fieldshas__search.GET /api/v1/meta/object→ the entries for both carry__search.
Expected one answer for one internal column, on every object and every read. Actual three combinations across two routes.
Which answer is right
The by-name package-object behaviour (strip it) looks like the correct side — it matches __search's own "never exposed to clients" declaration and the direction #7642 settled. That would mean the list route and the 71 sys_* by-name reads all need the same strip, applied at one place rather than per route.
The gate that makes it stick is extending the two agreement pins beyond showcase_account to at least one sys_* object, so a per-provenance divergence in either route cannot pass.
Source
Measured during the checklist retest of platform-core.metadata-registry-serving (framework 279ee48a, console 6314e87f2d49).
Activity
hotlong commentedon Aug 12, 2026
Triage: lands in the metadata serving layer,
packages/metadata-protocol(one strip applied at one place for both the list and by-name reads; the companion constant lives inpackages/objectql/src/search-companion.tsbut the divergent behaviour is in serving) →domain:metadata, queued. Re-laned fromdomain:metadata-protocol— that label is not in the lane table;packages/metadata*is thedomain:metadatafamily. Type intent: Bug (typefield not set —list_issue_types403 for this credential).Direction endorsed as filed: strip everywhere —
__searchis declared client-invisible and #7642 already settled that direction on the record door; this restores declared = enforced on the metadata door, so it is a bug fix, not a decision card. The gate is the one the filer names: widen both agreement pins (packages/rest/src/meta-object-extension-agreement.test.ts, the dogfood twin) pastshowcase_accountto at least onesys_*object.Serial constraints for the metadata seat: #8027 is in flight and #8031 is queued in the same serving family (
protocol.ts/ meta reads), and #8037 (this round) touches the same read paths — treat these as same-package serial; do not batch any two together without file-surface disjointness confirmed at claim time.Size/model suggestion: M,
opus.Generated by Claude Code
fix(meta): /meta/object/:name reports the __search companion, agreein…