Skip to content

[finding] The /meta/:type/:name/published door argues in a comment that a RAW tenant "is right for a READ" — the argument organizationIdForMetaRead exists to refute, and the door the #14907 card recorded as already gating #16032

Description

@claude

Found while implementing #14907 (the getMetaItemLayered read gate). ⛔ Not a defect in that PR — that PR's callee-side gate makes this door's BEHAVIOUR correct. What is left is the comment, which still argues for the shape the gate removed, and which is why two successive cards recorded this door as already gating. Filed rather than folded in, because correcting it pulls packages/rest into a packages/metadata-protocol diff and adds a verification surface the in-scope repair does not otherwise owe.

The site

packages/rest/src/rest-server.ts, the GET /meta/:type/:name/published handler (route declared around :7685, the layered consult around :7775 on the branch base f7db8f4fd). ⚠️ Line numbers on this file drift fast; re-derive with:

git grep -n 'publishedProtocol.getMetaItemLayered' -- packages/rest/src/rest-server.ts

The door passes the tenant straight through, unlike its /layers sibling twenty lines of grep away, which computes organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId):

const layered = await publishedProtocol.getMetaItemLayered({
    type,
    name,
    ...(publishedCtx?.tenantId ? { organizationId: publishedCtx.tenantId } : {}),
});
if (layered?.overlay !== undefined && layered?.overlay !== null) {
    res.json(layered.overlay);
    return;
}

The comment, which is the actual finding

Immediately above it:

The raw tenant is right for a READ (the write doors run it through organizationIdForMetaWrite instead): getMetaItemLayered's overlay layer is org-scoped-first, THEN env-wide, so this is fail-open in the safe direction — an org-less caller reads exactly what it reads today, and an org-scoped caller still falls back to the env-wide row. Nothing that resolves today stops resolving.

That is precisely the reasoning organizationIdForMetaRead's own docblock was written to refute, quoted from packages/metadata-core/src/meta-write-org-scope.ts:

⛔ The tempting shorter fix — pass the active org at every read site — is wrong in a way that only shows on databases with history. [...] A read door that named the org for EVERY type would resolve them again — resurrecting, on the read side, exactly the phantom writes #6190 stopped minting.

"Nothing that resolves today stops resolving" is the fail-open direction, and fail-open is the direction that RESURRECTS pre-#6190 phantoms. The comment predates #9454's read-side predicate and was never revisited when it landed.

Why this matters beyond tidiness

The #14907 card, and its triage comment, both recorded that this door already gates — the card's self-correction under contract review of PR #14908 explicitly re-confirmed "the two REST doors ... are confirmed as stated". Measured on the branch base, one of the two does not. The comment is the reason: it reads as a deliberate, reasoned decision to gate, so an enumeration that greps for the predicate name and then reads the surrounding prose comes away satisfied.

⇒ Two seats in the same series inherited the same wrong reading from this comment. That is the cost, and it is why the fix is not "delete a stale sentence" but "state the direction the predicate actually rules on".

The class

This is the third recorded instance of one shape — a comment arguing for a scope decision that a later callee-side gate falsified:

⚠️ Worth reading as a set rather than three tidy-ups: the series now has a callee-side gate on all three /meta read verbs, and every caller-side comment reasoning about read scope was written before that was true.

Suggested remedy

Replace the "raw tenant is right for a READ" paragraph with a statement that the callee gates (post-#14907), so this door does not need to and MUST NOT pre-gate on the raw URL segment — declaresOrgOverride answers false for the URL-only spellings (translations / email_templates), which is the #10340 measurement. The #8805 half of the comment above it stays true and should be kept: this door really can produce an org-scoped publish for a tier-A type, and really must serve it back.

⛔ No behaviour change is proposed here. If a future reader concludes the door should compute the predicate itself, note that doing so on req.params.type (raw) would be the #10340 defect; the fold is what makes it safe, and the callee already does it.

Verification notes

Measured on origin/main at f7db8f4fd in a dedicated worktree. Control for the zero-hit half: git grep -c 'organizationIdForMetaRead' -- packages/rest/src/rest-server.ts fires (six sites), and none of them is inside this handler.


Generated by Claude Code

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

    Labels

    documentationImprovements or additions to documentationfinding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions