Repository navigation
finding: the tenant-scope index is declared on FEDERATED objects, where the wall composes no predicate and no DDL is ever issued — the #8608 disagreement's mirror image #8753
Description
Restart-when: any PR makes provisionTenantScopeIndex in packages/objectql/src/registry.ts read injected-column provenance (#7865 convergence map resumes), or a gate begins pinning /meta/object/:name index accuracy
Observed while implementing #8608 (rebinding the tenant-scope index to the wall's derivation). Filed as an observation, not fixed — it is a divergence in the opposite direction from the one that card ruled on, it is pre-existing, and #8608's ruling was explicitly about granting the index where the wall applies, not withholding it where the wall does not.
Measured
packages/objectql/src/registry.ts, applySystemFields on an ADR-0015 external object carrying the registry's own injected anchor, multiTenant: true:
{ name: 'ext_customer', external: { remoteName: 'customers' }, fields: { name: ... } }
=> indexes: [{"fields":["organization_id"]}]
The same on the pre-#8608 tree — external is not one of the injection plan's opt-out rows, so resolveInjectedSystemColumns(...).tenant was already true there. This card's finding is not introduced by #8608 and is not changed by it.
Why that entry appears to serve nothing
Two independent facts, both already established in the repo:
- The wall composes no predicate on it. plugin-security injects org- and owner-shaped predicates onto federated external objects too — the #7738 defect on a layer outside objectql #7835 established that a federated object's injected
organization_idis a phantom anchor:hasPhantomTenantAnchormarks it,computeTenantLayer0FilteranswersobjectHasOrgIdField: false, and Layer 0 contributes nothing. Pinned inpackages/plugins/plugin-security/src/federated-tenant-layer0.test.ts. - No DDL is ever issued for it.
Engine.syncObjectSchemareturns early whenobj.external != null(registers read metadata, nosyncSchemacall), so no index is created on any table — the remote schema is owned externally.
So the declared entry is inert metadata: an index that does not exist, cannot be created by us, and would serve a predicate that is never composed. It is still served on /meta/object/:name (the materialization seam stamps it), which is the part that may matter — a federated object reports an index the platform neither has nor can build, which is the "declared but not delivered" shape Prime Directive #10 names.
Why it is filed rather than fixed
#8608's ruling is "the index follows the wall" — read strictly, that sentence withholds here, because the wall composes nothing. But:
- the change is a narrowing on a surface no gate or test currently pins, and the card that just landed was scoped to widening one row;
- the observable harm is bounded to metadata accuracy — no missing index, no slow query, no isolation gap — so severity judged at filing time is genuinely uncertain in both directions;
- an author who declares a real remote
organization_idon a federated object keeps a working wall (plugin-security injects org- and owner-shaped predicates onto federated external objects too — the #7738 defect on a layer outside objectql #7835's provenance half) and should keep any index question with it, so a naiveexternal != nullwithholding would be wrong. Whatever fix lands has to read provenance, exactly ashasPhantomTenantAnchordoes.
That last point is the reason this is worth recording rather than dropping: the correct predicate here is provenance-aware, and provenance is precisely what carriesTenantScopeColumn deliberately stopped reading in #8459.
Suggested disposition
Triage as either (a) a metadata-accuracy repair in provisionTenantScopeIndex gated on unprovisionedInjectedColumns / resolveInjectedColumnProvenance (the machine-readable marker #7865 minted for exactly this), or (b) a deliberate no-op documented at the seam so the next reader does not re-derive the question. Either way it belongs on the #7865 convergence map beside #8608's entry.
Related: #8608 · #8459 · #7835 (phantom anchors) · #7865 (the convergence map) · #6810 · ADR-0015
Generated by Claude Code
Generated by Claude Code
Activity
hotlong commentedon Aug 14, 2026
Triage — finding first-touch grading: HOLD ⇒
pm:on-hold,domain:engine-core, typeTask. Date 2026-08-14, graded by the triage seat Routine (not a maintainer ruling — provenance stated so the restart bar is read correctly).Reason
The filing's own measurement is what decides this, and it decides against queueing today:
Engine.syncObjectSchemareturns early onobj.external != null, so no DDL was ever going to exist, and plugin-security injects org- and owner-shaped predicates onto federated external objects too — the #7738 defect on a layer outside objectql #7835 already established the wall composes nothing on a phantom anchor. The entire observable surface is one inert entry served on/meta/object/:name. No consumer of that entry has been measured.external != nullwithholding would be wrong: an author who declares a real remoteorganization_idon a federated object keeps a working wall (plugin-security injects org- and owner-shaped predicates onto federated external objects too — the #7738 defect on a layer outside objectql #7835's provenance half) and should keep the index question with it. The right predicate is provenance-aware —unprovisionedInjectedColumns/resolveInjectedColumnProvenance, the marker [Decision]applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865 minted for exactly this — andcarriesTenantScopeColumndeliberately stopped reading provenance in An author-declaredorganization_idwithholds the platform's tenant index — the wall's hottest predicate runs unindexed on a multi-tenant deployment #8459. So this card is one entry on the [Decision]applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865 convergence map, not a standalone one-liner, and it should land when that map is being worked rather than alone.① is the one facet pointing the other way — an index the platform neither has nor can build is served as declared, which is the Prime Directive #10 shape. That is real, and it is why this is held rather than closed.
Named restart conditions (any one lifts the hold)
applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865's convergence-map work resumes, or any card lands that makesprovisionTenantScopeIndexread injected-column provenance. This card is then an in-scope member, not a new card.os migrate plan, a migration planner, or a customer report. That converts ② from zero to non-zero and this goes straight topm:queue./meta/object/:nameindex accuracy. The narrowing stops being unpinned, and the cost argument above dissolves.Opportunistic trigger — named files, per hold discipline
packages/objectql/src/registry.ts, specificallyapplySystemFieldsandprovisionTenantScopeIndex. Any dispatch whose declared file surface intersects those two functions should name this card and carry the fix as a declared add-on rather than leaving it for a dedicated run. Recorded here so the trigger has a reader at the moment it fires, not just an intention.Explicitly not a blocker relationship with #8608
#8608 (
pm:dispatched) is in flight on the same file and the mirror-image question. The filing measured that this finding is pre-existing on the pre-#8608 tree and is not changed by #8608 —externalis not one of the injection plan's opt-out rows, soresolveInjectedSystemColumns(...).tenantwas alreadytrue. So: noBlocked-by:, nopm:blocked. It is a file-serialization concern for whoever picks it up later, and restart condition 1 is where the two rejoin.Generated by Claude Code
fix(pm): H9's issue-ref class requires the reference at the declarati…
objectstack-fleet commentedon Sep 23, 2026
关
not_planned—— 维护者逐张复核 on-hold 卡时同意关闭;只是元数据准确性问题,没有实际影响分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T08:59Z。维护者 2026-09-23 在分诊会话里逐张复核pm:on-hold卡,对第四组的回复原文:「第四组 同意」。 本卡在那一组里的建议是关闭。呈给维护者的事实
/meta/object/:name会报出一条organization_id租户索引。这条索引不存在:Engine.syncObjectSchema对external对象不发任何 DDL。它也用不上:plugin-security injects org- and owner-shaped predicates onto federated external objects too — the #7738 defect on a layer outside objectql #7835 已确定,租户墙在幻影锚点上不加任何谓词。external != null,因为作者自己声明了真实远端organization_id的对象,是要保留租户墙的。本卡当初等的收敛计划 [Decision]applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865 已经不在开放卡里了。5296987248),不是维护者裁定。重开条件
测到有使用方读取联邦对象的索引列表并据此做决定;或者有门禁或测试开始钉
/meta/object/:name的索引准确性。关闭理由:
not_planned,同时摘掉pm:on-hold。Generated by Claude Code