Filed by the #8375 dev agent, measured while converging the tenant-index stamp across the /meta read-exit seam. Unassigned. Out of #8375's scope — that card preserved this behaviour exactly rather than widening it, and this is the behaviour it preserved.
Symptom
applySystemFields (packages/objectql/src/registry.ts) declares the tenant-scope index only for an object whose organization_id column the PLATFORM provisioned. An author who declares the column themselves gets the column they wrote — which is correct and deliberate, pinned as "does NOT overwrite an author-declared organization_id" — but no index on it, on a multi-tenant deployment:
registry.getObject('x').fields.organization_id ==> the author's own declaration
registry.getObject('x').indexes ==> undefined
The column is still THE tenant isolation key. SecurityPlugin's RLS layer appends organization_id = current_user.organization_id to essentially every read on that object, so the deployment's hottest predicate runs unindexed — the exact condition #6810 landed the indexes[] declaration to fix, reached by a different route.
Why it looks incidental rather than decided
Before #8375 the index push sat physically nested inside the field-injection branch:
if (wantTenant && !schema.fields?.organization_id) {
additions.organization_id = { ...TENANT_SCOPE_FIELD_DEF };
if (opts.multiTenant && !declaresTenantIndex(schema)) { ...push the index... }
}
so "the author declared the column" and "the platform declares no index" were the same condition by nesting, not by an argued decision. Nothing in #6810's reasoning distinguishes the two cases: its argument is that on a walled deployment the tenant column is filtered on constantly and therefore wants an index, which is true regardless of who typed the column.
#8375 lifted the decision into provisionTenantScopeIndex and preserved this behaviour deliberately and exactly (via isInjectedColumnDefinition), because widening it was outside that card and would have changed what the registry answers. That makes this the right moment to decide it on purpose.
Reproduction
new SchemaRegistry({ multiTenant: true }).- Register an object declaring its own
organization_id, e.g. { type: 'lookup', reference: 'sys_organization', label: 'Org' } — any shape not byte-identical to TENANT_SCOPE_FIELD_DEF. registry.getObject(name).indexes is undefined; an object that declared nothing gets [{ fields: ['organization_id'] }].
The decision this needs
Not obviously a straight bug fix — it is a question about whose declaration governs:
C is the narrowest reading of "is this actually the tenant key", but it is a third predicate where #8375 just finished reducing two to one, so it should be weighed against the cost of that.
Dedup
Searched applySystemFields organization_id index / tenant index / author-declared column. Nearest neighbours: #8323 (tenant-scoped UNIQUE indexes going global — driver DDL normalization, not whether the index is declared at all) and #6810 (closed; moved the tenant index from a rejected field-level indexed key into indexes[], and is the card whose intent this gap sits inside). Neither is a twin.
Related
#8375 (the read-exit convergence that surfaced this) · #6810 · #6562 · ADR-0049
Filed by the #8375 dev agent, measured while converging the tenant-index stamp across the
/metaread-exit seam. Unassigned. Out of #8375's scope — that card preserved this behaviour exactly rather than widening it, and this is the behaviour it preserved.Symptom
applySystemFields(packages/objectql/src/registry.ts) declares the tenant-scope index only for an object whoseorganization_idcolumn the PLATFORM provisioned. An author who declares the column themselves gets the column they wrote — which is correct and deliberate, pinned as "does NOT overwrite an author-declared organization_id" — but no index on it, on a multi-tenant deployment:The column is still THE tenant isolation key. SecurityPlugin's RLS layer appends
organization_id = current_user.organization_idto essentially every read on that object, so the deployment's hottest predicate runs unindexed — the exact condition #6810 landed theindexes[]declaration to fix, reached by a different route.Why it looks incidental rather than decided
Before #8375 the index push sat physically nested inside the field-injection branch:
so "the author declared the column" and "the platform declares no index" were the same condition by nesting, not by an argued decision. Nothing in #6810's reasoning distinguishes the two cases: its argument is that on a walled deployment the tenant column is filtered on constantly and therefore wants an index, which is true regardless of who typed the column.
#8375 lifted the decision into
provisionTenantScopeIndexand preserved this behaviour deliberately and exactly (viaisInjectedColumnDefinition), because widening it was outside that card and would have changed what the registry answers. That makes this the right moment to decide it on purpose.Reproduction
new SchemaRegistry({ multiTenant: true }).organization_id, e.g.{ type: 'lookup', reference: 'sys_organization', label: 'Org' }— any shape not byte-identical toTENANT_SCOPE_FIELD_DEF.registry.getObject(name).indexesisundefined; an object that declared nothing gets[{ fields: ['organization_id'] }].The decision this needs
Not obviously a straight bug fix — it is a question about whose declaration governs:
applySystemFieldsstampsindexedonorganization_id— a keyFieldSchemarejects by name, so every registry-backed object read answers_diagnostics: { valid: false }#6810's stated intent; the risk is stamping an index on an author's column whose type they chose (atextorg code, say) where the index may be unwanted.applySystemFields' docs — the author who takes the column over takes its indexing too.lookuptosys_organization(i.e. really the tenant anchor), not merely when it is byte-identical to the platform's definition.C is the narrowest reading of "is this actually the tenant key", but it is a third predicate where #8375 just finished reducing two to one, so it should be weighed against the cost of that.
Dedup
Searched
applySystemFields organization_id index/ tenant index / author-declared column. Nearest neighbours: #8323 (tenant-scoped UNIQUE indexes going global — driver DDL normalization, not whether the index is declared at all) and #6810 (closed; moved the tenant index from a rejected field-levelindexedkey intoindexes[], and is the card whose intent this gap sits inside). Neither is a twin.Related
#8375 (the read-exit convergence that surfaced this) · #6810 · #6562 · ADR-0049