Skip to content

meta: applySystemFields stamps indexed on organization_id — a key FieldSchema rejects by name, so every registry-backed object read answers _diagnostics: { valid: false } #6810

Description

@os-zhuang

Found while implementing #6562 (the /meta object read serving the effective runtime schema). Out of that issue's scope — the fix is at the injection site, not at the read exits — so filed here rather than folded in.

What

applySystemFields (packages/objectql/src/registry.ts) provisions organization_id with an indexed: opts.multiTenant key:

additions.organization_id = { ...TENANT_SCOPE_FIELD_DEF, indexed: opts.multiTenant };

indexed is not a FieldSchema key. It was removed in the 16.x line (#2377, ADR-0049) and FieldSchema is a strictObject, so a field definition carrying it is rejected — by name, with a purpose-written message:

Unrecognized key(s) on this field: `indexed`.
  • never a FieldSchema key; a field-level index flag built no index (#2377).
    Declare the index in the object's `indexes[]`. Until #4001 closed this shape
    these were dropped silently — the field was still created, minus whatever the
    key was meant to constrain, protect or compute.

registerObject runs applySystemFields before storing, and SchemaRegistry.getItem('object', name) serves that post-injection document. So the key travels all the way out to the /meta surface, where decorateMetadataItem re-parses the served body and stamps the verdict on it.

Measured

origin/main @ 4bb6f01af, via the real SchemaRegistry + the real ObjectStackProtocolImplementation, on a plain business object declaring one field:

--- multiTenant=true  REGISTRY-BACKED getMetaItem ---
_diagnostics: { valid: false,
  errors: [ { path: 'fields.organization_id', code: 'unrecognized_keys',
              message: 'Unrecognized key(s) on this field: `indexed`. …' } ] }
list exit _diagnostics: (identical)

--- multiTenant=false REGISTRY-BACKED getMetaItem ---
(identical — the key is present either way, only its VALUE follows the flag)

Both modes, both exits. The object itself is otherwise spec-clean: delete that one key and the same document parses green.

Why it matters

_diagnostics is what Studio renders invalid-metadata banners and inline field errors from, and what an AI author reads to decide whether a document it produced is acceptable. Here it reports a defect on every tenancy-enabled object, attributed to a field the author never wrote and cannot fix — the platform's own column failing the platform's own schema. It also makes the verdict useless as a signal on those objects: a real authoring error is indistinguishable from this one.

Direction (not a decision — for triage)

The consumer of indexed is a single line in one driver: packages/drivers/driver-mongodb/src/mongodb-schema.ts:87 (} else if (field.indexed) {). Nothing else in the repo reads it. So the plausible shapes are:

  • A. Move the intent to where the schema says it belongs — declare the tenant index in the object's indexes[] and teach driver-mongodb to read that (which is what every other index in the system already does). Removes the key.
  • B. Keep the DDL hint but strip it before the document leaves the registry for any metadata consumer, so the physical layer keeps it and the served/parsed document never sees it.
  • C. Re-declare indexed on FieldSchema. Almost certainly wrong — [11.0][A2] Remove dead author-facing metadata properties (ADR-0049 enforce-or-remove) #2377 removed it precisely because a field-level flag built no index, and re-adding it would restore a declared-but-unenforced key on every field.

A is the contract-first direction; B is smaller. Either is a behaviour change in the DDL/driver lane, which is why it is not folded into #6562.

Relationship to #6562

Independent, not blocking. #6562 converges the overlay-backed /meta object read onto the registry-backed field set; it deliberately does not propagate indexed onto served documents (converging onto a key the object schema refuses would spread this defect rather than close that one), and it pins the residual divergence in both directions in packages/objectql/src/protocol-meta-effective-schema.test.ts:

expect(divergences(registryBacked, overlayBacked)).toEqual(['organization_id.indexed']);
expect(overlayBacked._diagnostics).toEqual({ valid: true });
expect(registryBacked._diagnostics.valid).toBe(false);

Whichever fix lands here flips those three lines, which is the intended tripwire — the pin exists so this cannot be quietly forgotten.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions