Found while executing #15034 (PR #15619), which repairs the ?type= arm's comment. This is the other half of what that measurement turned up, and it moves observable behaviour — so it is a decision on a card, ⛔ never a side effect of a comment repair.
What the gap's own reasoning says today
The ?type= door's comment and the pin in packages/rest/src/rest-server-meta-read-org-scope.test.ts both record the untyped sweep as deliberately env-wide, on this argument:
targetTypes is then the whole registry — five allowOrgOverride: true types and every other declared type together — while the request carries ONE organizationId. Naming the tenant there does not merely over-reach: getMetaItems UNIONs the env-wide rows with the named org's rows, so a non-overridable type's org-scoped rows — the pre-#6190 phantoms — would be read back INTO the governance report [...] One org id cannot express a per-type scope, and inventing one at this call site (a fan-out per overridable type, plus a REST-side re-aggregation of total/stats/scannedTypes) would make this door a second owner of the sweep's arithmetic.
Why that obstacle is gone
getMetaDiagnostics does not spend the organization once. It loops:
for (const t of targetTypes) {
listed = await this.getMetaItems({ type: t, organizationId: request.organizationId, packageId: request.packageId });
}
and since #14683 the first thing getMetaItems does with that organization is organizationIdForMetaRead(request.type, request.organizationId) — per t, after the canonical fold (packages/metadata-protocol/src/protocol.ts:6958).
⇒ A single organizationId handed to the untyped arm is already narrowed per type by the callee: the org for the five allowOrgOverride: true types, undefined for every other. That is exactly the "org-scoped for those five, env-wide for the rest" the comment says one org id cannot say. No fan-out, no REST-side re-aggregation, no second owner of the sweep's arithmetic — the gate sits inside the loop that already exists.
Measured, not inferred (PR #15619, ablation M1): the door's predicate was replaced with a raw diagnosticsCtx?.tenantId and the ?type=object phantom control — a pre-#6190 org-scoped object row planted directly in the store — stayed green, because the inner gate refused to spend the unfolded org on a non-overridable type. The untyped arm reaches the same getMetaItems through the same loop.
What is NOT claimed
- ⛔ Not claimed that the gap should be closed. That is this card's question, not its premise.
- ⛔ Not claimed the phantom risk is the only consideration.
stats / total / scannedTypes arithmetic is unchanged by the gate, but whether a governance sweep should become org-scoped by default is a product decision, and an org-scoped caller would start seeing counts it did not see before.
- The
?type= arm is untouched by this and is correct as it stands.
Acceptance
- Decide whether the untyped sweep should forward the caller's organization now that the callee gates per type.
- If yes: the pin
an org-scoped item is absent from the whole-registry sweep in packages/rest/src/rest-server-meta-read-org-scope.test.ts reddens by design — it carries an explicit "if this reddens, read the card before making it green" note, and this is that card. Replace it with the positive assertion rather than deleting it, and add a phantom control for a non-overridable type on the untyped arm (there is none today — the existing phantom control only covers ?type=object).
- If no: record the current reason, because the one written in the tree is no longer it.
Provenance
Measured on origin/main ba426b0f091. Note the resolution path when re-measuring: packages/rest's vitest config does not alias @objectstack/metadata-protocol, so it resolves through dist/ — build the closure and confirm the gate reached the artifact before reading any result.
Found while executing #15034 (PR #15619), which repairs the
?type=arm's comment. This is the other half of what that measurement turned up, and it moves observable behaviour — so it is a decision on a card, ⛔ never a side effect of a comment repair.What the gap's own reasoning says today
The
?type=door's comment and the pin inpackages/rest/src/rest-server-meta-read-org-scope.test.tsboth record the untyped sweep as deliberately env-wide, on this argument:Why that obstacle is gone
getMetaDiagnosticsdoes not spend the organization once. It loops:and since #14683 the first thing
getMetaItemsdoes with that organization isorganizationIdForMetaRead(request.type, request.organizationId)— pert, after the canonical fold (packages/metadata-protocol/src/protocol.ts:6958).⇒ A single
organizationIdhanded to the untyped arm is already narrowed per type by the callee: the org for the fiveallowOrgOverride: truetypes,undefinedfor every other. That is exactly the "org-scoped for those five, env-wide for the rest" the comment says one org id cannot say. No fan-out, no REST-side re-aggregation, no second owner of the sweep's arithmetic — the gate sits inside the loop that already exists.Measured, not inferred (PR #15619, ablation M1): the door's predicate was replaced with a raw
diagnosticsCtx?.tenantIdand the?type=objectphantom control — a pre-#6190 org-scopedobjectrow planted directly in the store — stayed green, because the inner gate refused to spend the unfolded org on a non-overridable type. The untyped arm reaches the samegetMetaItemsthrough the same loop.What is NOT claimed
stats/total/scannedTypesarithmetic is unchanged by the gate, but whether a governance sweep should become org-scoped by default is a product decision, and an org-scoped caller would start seeing counts it did not see before.?type=arm is untouched by this and is correct as it stands.Acceptance
an org-scoped item is absent from the whole-registry sweepinpackages/rest/src/rest-server-meta-read-org-scope.test.tsreddens by design — it carries an explicit "if this reddens, read the card before making it green" note, and this is that card. Replace it with the positive assertion rather than deleting it, and add a phantom control for a non-overridable type on the untyped arm (there is none today — the existing phantom control only covers?type=object).Provenance
Measured on
origin/mainba426b0f091. Note the resolution path when re-measuring:packages/rest's vitest config does not alias@objectstack/metadata-protocol, so it resolves throughdist/— build the closure and confirm the gate reached the artifact before reading any result.