getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

Description

@os-musk

Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

The defect

The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

  • :7798async getMetaItemLayered(request: { … })
  • :7838const orgId = request.organizationId; ⇠ no gate
  • :7842request = canonicalizeMetaRequestType(request);

⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts

Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts

The live ungated caller

packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
type,
name,
...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

⭐ Why it is not folded into #14770, and why it is not a copy of that fix

Two reasons, the second one substantive:

  1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

    ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

  2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

Dedup

MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

Nothing open names getMetaItemLayered's ungated organization read.

Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
       blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

      Description

      @os-musk

      Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

      Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

      The defect

      The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

      Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

      • :7798async getMetaItemLayered(request: { … })
      • :7838const orgId = request.organizationId; ⇠ no gate
      • :7842request = canonicalizeMetaRequestType(request);

      ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

      git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
      

      Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

      git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
      

      The live ungated caller

      packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

      constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
      type,
      name,
      ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

      type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

      The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

      ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

      ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

      Two reasons, the second one substantive:

      1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

        ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

      2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

      Dedup

      MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

      Nothing open names getMetaItemLayered's ungated organization read.

      Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

      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

        No labels
        No labels

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

          Description

          @os-musk

          Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

          Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

          The defect

          The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

          Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

          • :7798async getMetaItemLayered(request: { … })
          • :7838const orgId = request.organizationId; ⇠ no gate
          • :7842request = canonicalizeMetaRequestType(request);

          ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

          git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
          

          Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

          git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
          

          The live ungated caller

          packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

          constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
          type,
          name,
          ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

          type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

          The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

          ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

          ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

          Two reasons, the second one substantive:

          1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

            ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

          2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

          Dedup

          MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

          Nothing open names getMetaItemLayered's ungated organization read.

          Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

          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

            No labels
            No labels

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

              Description

              @os-musk

              Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

              Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

              The defect

              The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

              Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

              • :7798async getMetaItemLayered(request: { … })
              • :7838const orgId = request.organizationId; ⇠ no gate
              • :7842request = canonicalizeMetaRequestType(request);

              ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

              git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
              

              Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

              git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
              

              The live ungated caller

              packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

              constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
              type,
              name,
              ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

              type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

              The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

              ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

              ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

              Two reasons, the second one substantive:

              1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

                ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

              2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

              Dedup

              MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

              Nothing open names getMetaItemLayered's ungated organization read.

              Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

              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

                No labels
                No labels

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

                  Description

                  @os-musk

                  Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

                  Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

                  The defect

                  The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

                  Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

                  • :7798async getMetaItemLayered(request: { … })
                  • :7838const orgId = request.organizationId; ⇠ no gate
                  • :7842request = canonicalizeMetaRequestType(request);

                  ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

                  git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
                  

                  Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

                  git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
                  

                  The live ungated caller

                  packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

                  constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
                  type,
                  name,
                  ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

                  type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

                  The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

                  ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

                  ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

                  Two reasons, the second one substantive:

                  1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

                    ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

                  2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

                  Dedup

                  MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

                  Nothing open names getMetaItemLayered's ungated organization read.

                  Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

                  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

                    No labels
                    No labels

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

                      Description

                      @os-musk

                      Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

                      Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

                      The defect

                      The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

                      Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

                      • :7798async getMetaItemLayered(request: { … })
                      • :7838const orgId = request.organizationId; ⇠ no gate
                      • :7842request = canonicalizeMetaRequestType(request);

                      ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

                      git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
                      

                      Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

                      git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
                      

                      The live ungated caller

                      packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

                      constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
                      type,
                      name,
                      ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

                      type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

                      The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

                      ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

                      ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

                      Two reasons, the second one substantive:

                      1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

                        ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

                      2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

                      Dedup

                      MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

                      Nothing open names getMetaItemLayered's ungated organization read.

                      Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

                      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

                        No labels
                        No labels

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

                          Description

                          @os-musk

                          Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

                          Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

                          The defect

                          The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

                          Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

                          • :7798async getMetaItemLayered(request: { … })
                          • :7838const orgId = request.organizationId; ⇠ no gate
                          • :7842request = canonicalizeMetaRequestType(request);

                          ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

                          git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
                          

                          Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

                          git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
                          

                          The live ungated caller

                          packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

                          constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
                          type,
                          name,
                          ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

                          type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

                          The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

                          ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

                          ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

                          Two reasons, the second one substantive:

                          1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

                            ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

                          2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

                          Dedup

                          MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

                          Nothing open names getMetaItemLayered's ungated organization read.

                          Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

                          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

                            No labels
                            No labels

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              getMetaItemLayered is the third instalment of the ungated-org-read series — a raw active organization reaches its overlay layer, and its orgId is bound BEFORE the canonical type fold so the plural/singular one-liner does not port #14907

                              Description

                              @os-musk

                              Filed by the domain:engine execution seat while implementing #14770 (the singular getMetaItem door). Out of scope there and deliberately not fixed in that PR — see "Why it is not folded into #14770" below.

                              Ungraded and unrouted on purpose — no pm:* state, no domain:*, no assignee. Grading and routing are triage's.

                              The defect

                              The series #9454#14683 (plural getMetaItems) → #14770 (singular getMetaItem) is "a read door spends a raw active organization on a type that has no per-org read channel, so a pre-#6190 phantom org-scoped row is resurrected". getMetaItemLayered — the third /meta read verb — still applies no gate of its own.

                              Verified at origin/main84b8190ae, packages/metadata-protocol/src/protocol.ts:

                              • :7798async getMetaItemLayered(request: { … })
                              • :7838const orgId = request.organizationId; ⇠ no gate
                              • :7842request = canonicalizeMetaRequestType(request);

                              ⚠️ Line numbers drift fast on this file — #14770 recorded three different readings of its own site inside two shifts. Re-derive:

                              git grep -n "const orgId = request.organizationId;" -- packages/metadata-protocol/src/protocol.ts
                              

                              Control on the same file (expect the two GATED bindings, in getMetaItems and getMetaItem, after #14770 lands):

                              git grep -c "organizationIdForMetaRead(request.type, request.organizationId)" -- packages/metadata-protocol/src/protocol.ts
                              

                              The live ungated caller

                              packages/runtime/src/domains/meta.ts:345 resolves the session organization and passes it straight through:

                              constorganizationId=awaitdeps.resolveActiveOrganizationId(_context);constlayered=await(protocolasany).getMetaItemLayered({
                              type,
                              name,
                              ...(organizationId ? { organizationId } : {}),});if(layered?.overlay!==undefined&&layered?.overlay!==null){return{handled: true,response: deps.success(layered.overlay)};}

                              type is generic here, so it is not confined to the org-overridable five. When it is a type the registry declares allowOrgOverride: false, a phantom org-scoped row becomes the overlay layer — and this branch returns that layer as the response, so the caller is told the item has a customization it does not have.

                              The REST /layers door at packages/rest/src/rest-server.ts:3172does gate (organizationIdForMetaRead(canonicalMetaUrlType(req.params.type), layeredCtx?.tenantId)), and the plugin-security call sites pass no organization at all. So the runtime dispatcher site above is the reachable one.

                              ⚠️ Direction differs from the other two verbs and should be measured before it is graded. On the plural verb a phantom can only ADD a row; on the singular verb it REPLACES the served document (#14770). Here the affected value is the overlay layer of a three-layer diagnostic whose whole purpose is to answer "what did this tenant customize" — so the harm is a false positive customization claim, which the Studio "Code default vs Overlay vs Effective" diff tab renders as evidence. That may grade differently from either twin.

                              ⭐ Why it is not folded into #14770, and why it is not a copy of that fix

                              Two reasons, the second one substantive:

                              1. The idempotence proof does not carry. The Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 ruling made the callee-side gate conditional on proving no already-gating caller is double-scoped or wrongly denied, discharged per door over that door's own caller population. getMetaItemLayered has a different population — five plugin-security call sites, two REST doors, the runtime dispatcher — none of which getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770's proof covers.

                                ⚠️Corrected 2026-09-03 (contract review of PR fix(metadata-protocol): gate getMetaItem's overlay read on the metadata registry #14908, advisory A2): this line first said sixplugin-security sites. The actual non-test getMetaItemLayered( invocations there are fivepackaged-permission-set-lock-gate.ts:82 and permission-set-projection.ts:770, :938, :995, :1406. permission-set-overlay-discard.ts:243 only feature-detects (typeof protocol.getMetaItemLayered === 'function') and delegates to projectPermissionMutation, so it is not a call site. The two REST doors (rest-server.ts:3189, :7330) and the runtime dispatcher (runtime/src/domains/meta.ts:346) are confirmed as stated.

                              2. ⚠️ The one-liner does not port. In both Where does the allowOrgOverride read gate belong for metadata sweeps that read MORE THAN ONE type per request? getMetaItems applies none of its own #14683 and getMetaItem (SINGULAR) has the same ungated-caller defect as getMetaItems and it is sharper — its overlay read is ?? PRECEDENCE, not a union, so a pre-#6190 phantom SHADOWS the live env-wide row and becomes the served document #14770 the fix is "replace the orgId binding with the gated call", and it is correct there because the binding sits after canonicalizeMetaRequestType. In getMetaItemLayered the binding is at :7838 and the fold is at :7842 — the binding comes first. Dropping the same expression in place would gate on the RAW type, which is exactly what /meta org scope is decided from the RAW url spelling: translations / email_templates read and write env-wide where their singular twin is org-scoped #10340 measured the cost of: declaresOrgOverride tolerates the manifest plurals but not the URL-only ones (translations / email_templates have no manifest key), so a raw segment splits one item across two partitions. The fix here needs the binding moved below the fold — a reorder, in a method whose code and overlay layers must answer for one namespace (that is what the fold's own comment at :7842 is about). Not mechanical, so it did not qualify for a bounded in-scope repair.

                              Dedup

                              MCP search_issues (repo-scoped REST is 403 from this container and gh is absent, so the one targeted MCP call was the channel) — "getMetaItemLayered ungated organization overlay layer raw active organization phantom org-scoped row runtime domains meta resolveActiveOrganizationId registry read gate singular layered door" → 10 results. Firing control: #14770 ranks first and #14683 is in the set. Distinguished:

                              Nothing open names getMetaItemLayered's ungated organization read.

                              Refs: #9454 · #14683 · #14770 (the singular twin, and the PR whose implementation surfaced this) · #6190 / #7018 (the phantom rows and the write-side predicate) · #10340 (the raw-vs-folded measurement) · #13753.

                              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

                                No labels
                                No labels

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions