Skip to content

The untyped /meta/diagnostics sweep's recorded gap has lost its stated obstacle: #14683's inner gate folds per type INSIDE the sweep's own loop, so one organizationId now CAN express a per-type scope #15622

Description

@os-litant

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

  1. Decide whether the untyped sweep should forward the caller's organization now that the callee gates per type.
  2. 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).
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions