Skip to content

[finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

Description

@claude

Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

Measured on origin/main @ 71627f7b4e.

What I found

indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

6657 const lookup = async (t: string) => { ... [lexically encloses the call]
6717 const lookup = async (t: string) => { ...
7129 const lookup = async (t: string) => { ... [what the index returns]

(Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

Why the shape check cannot catch it

contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

  • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
  • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

Direction of the error, and why it costs nothing today

Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

Blast radius scales with the depth bound

Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

Sibling, not a duplicate

#13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

Dedupe performed

⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


Generated by Claude Code

Metadata

Metadata

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)) { // Add copy buttons to all
     blocks
    (function() {
    function addCopyButtons() {
    document.querySelectorAll('pre code').forEach(function(codeBlock) {
    if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
    codeBlock.parentElement.setAttribute('data-copy-added', 'true');
    var btn = document.createElement('button');
    btn.textContent = 'Copy';
    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;';
    btn.onmouseover = function() { this.style.opacity = '1'; };
    btn.onmouseout = function() { this.style.opacity = '0.7'; };
    btn.onclick = function() {
    navigator.clipboard.writeText(codeBlock.textContent).then(function() {
    btn.textContent = 'Copied!';
    setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
    });
    };
    codeBlock.parentElement.style.position = 'relative';
    codeBlock.parentElement.appendChild(btn);
    });
    }
    addCopyButtons();
    // Re-run on dynamic content
    var observer = new MutationObserver(addCopyButtons);
    observer.observe(document.body, { childList: true, subtree: true });
    })();
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
    Skip to content

    [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

    Description

    @claude

    Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

    Measured on origin/main @ 71627f7b4e.

    What I found

    indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

    packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

    6657 const lookup = async (t: string) => { ... [lexically encloses the call]
    6717 const lookup = async (t: string) => { ...
    7129 const lookup = async (t: string) => { ... [what the index returns]
    

    (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

    The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

    Why the shape check cannot catch it

    contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

    • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
    • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

    The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

    Direction of the error, and why it costs nothing today

    Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

    The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

    Blast radius scales with the depth bound

    Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

    Sibling, not a duplicate

    #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

    Dedupe performed

    ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


    Generated by Claude Code

    Metadata

    Metadata

    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)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
      Skip to content

      [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

      Description

      @claude

      Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

      Measured on origin/main @ 71627f7b4e.

      What I found

      indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

      packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

      6657 const lookup = async (t: string) => { ... [lexically encloses the call]
      6717 const lookup = async (t: string) => { ...
      7129 const lookup = async (t: string) => { ... [what the index returns]
      

      (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

      The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

      Why the shape check cannot catch it

      contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

      • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
      • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

      The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

      Direction of the error, and why it costs nothing today

      Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

      The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

      Blast radius scales with the depth bound

      Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

      Sibling, not a duplicate

      #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

      Dedupe performed

      ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


      Generated by Claude Code

      Metadata

      Metadata

      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)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
        Skip to content

        [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

        Description

        @claude

        Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

        Measured on origin/main @ 71627f7b4e.

        What I found

        indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

        packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

        6657 const lookup = async (t: string) => { ... [lexically encloses the call]
        6717 const lookup = async (t: string) => { ...
        7129 const lookup = async (t: string) => { ... [what the index returns]
        

        (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

        The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

        Why the shape check cannot catch it

        contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

        • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
        • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

        The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

        Direction of the error, and why it costs nothing today

        Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

        The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

        Blast radius scales with the depth bound

        Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

        Sibling, not a duplicate

        #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

        Dedupe performed

        ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


        Generated by Claude Code

        Metadata

        Metadata

        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)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
          Skip to content

          [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

          Description

          @claude

          Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

          Measured on origin/main @ 71627f7b4e.

          What I found

          indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

          packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

          6657 const lookup = async (t: string) => { ... [lexically encloses the call]
          6717 const lookup = async (t: string) => { ...
          7129 const lookup = async (t: string) => { ... [what the index returns]
          

          (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

          The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

          Why the shape check cannot catch it

          contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

          • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
          • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

          The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

          Direction of the error, and why it costs nothing today

          Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

          The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

          Blast radius scales with the depth bound

          Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

          Sibling, not a duplicate

          #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

          Dedupe performed

          ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


          Generated by Claude Code

          Metadata

          Metadata

          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)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
            Skip to content

            [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

            Description

            @claude

            Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

            Measured on origin/main @ 71627f7b4e.

            What I found

            indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

            packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

            6657 const lookup = async (t: string) => { ... [lexically encloses the call]
            6717 const lookup = async (t: string) => { ...
            7129 const lookup = async (t: string) => { ... [what the index returns]
            

            (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

            The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

            Why the shape check cannot catch it

            contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

            • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
            • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

            The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

            Direction of the error, and why it costs nothing today

            Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

            The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

            Blast radius scales with the depth bound

            Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

            Sibling, not a duplicate

            #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

            Dedupe performed

            ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


            Generated by Claude Code

            Metadata

            Metadata

            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)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
              Skip to content

              [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

              Description

              @claude

              Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

              Measured on origin/main @ 71627f7b4e.

              What I found

              indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

              packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

              6657 const lookup = async (t: string) => { ... [lexically encloses the call]
              6717 const lookup = async (t: string) => { ...
              7129 const lookup = async (t: string) => { ... [what the index returns]
              

              (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

              The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

              Why the shape check cannot catch it

              contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

              • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
              • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

              The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

              Direction of the error, and why it costs nothing today

              Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

              The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

              Blast radius scales with the depth bound

              Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

              Sibling, not a duplicate

              #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

              Dedupe performed

              ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


              Generated by Claude Code

              Metadata

              Metadata

              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)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today · Issue #13474 · objectstack-ai/objectstack · GitHub
                Skip to content

                [finding] the read-seam wrapper hop resolves a bare name through a flat LAST-WINS file index — protocol.ts picks the third of three same-named lookup bodies, 0 seams affected today #13474

                Description

                @claude

                Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while verifying the six depth-admitted seams #12360 asked for (PR #13472); deliberately not fixed there — that card's declared scope is the depth bound, and this is a resolution defect the bound merely limits the blast radius of.

                Measured on origin/main @ 71627f7b4e.

                What I found

                indexFunctionBodies in scripts/check-durability-degradation-log-level.mjs builds a flat, file-scoped index keyed by bare name, and it is last-winsbyName.set(name, body) with no scope information. isReadCall's wrapper hop resolves a callee name through that index.

                packages/metadata-protocol/src/protocol.ts declares lookup three times, all near-identical single-parameter async arrows:

                6657 const lookup = async (t: string) => { ... [lexically encloses the call]
                6717 const lookup = async (t: string) => { ...
                7129 const lookup = async (t: string) => { ... [what the index returns]
                

                (Return-type annotations elided; all three are single-parameter async arrows, which is the only property the resolution turns on.)

                The call at protocol.ts:6674const rec = await lookup(request.type);, inside findDraft, whose own enclosing lookup is the one at 6657 — is resolved by the hop to the body at 7129. That is the third declaration, in a different method entirely, chosen only because it is last in the file.

                Why the shape check cannot catch it

                contradictsWrapperResolution (added by PR #13444 for #12358) asks two questions of a hop, receiver and required-parameter count. Both pass here, and correctly so:

                • the callee is a bare identifier, which that predicate admits deliberately (its docblock says so: const self = this; is how the live file reaches its own members from a closure);
                • all three declarations take exactly one required parameter, so the arity clause has nothing to refute.

                The guard is doing its job. Its job is name collisions across receivers, not name collisions between same-named bodies in one file, and no strengthening of either clause reaches this case as long as the colliding declarations are near-copies.

                Direction of the error, and why it costs nothing today

                Zero cost on this tree, measured, not assumed. All three lookup bodies read sys_metadata through this.engine.findOne, so the two seams that hop through this call (protocol.ts:10497getMetaItemCached and :13874saveMetaItem, both admitted at depth 3) are genuine read seams under any of the three resolutions. The verdict is right — by luck rather than by construction.

                The mechanism itself has no safe direction, which is why it is worth a record. A collision where only some of the same-named bodies read would either invent a seam (the unsafe direction — a fake member of the denominator #5186, #6451, #9165, #8845 and #8901 are quoted against) or drop a real one, and nothing in the output distinguishes either case from a correct resolution.

                Blast radius scales with the depth bound

                Each additional wrapper hop is another name that has to be unique for the chain to stay correct. MAX_READ_WRAPPER_DEPTH is 2 today; this collision already appears at hop 3, i.e. it is reachable only in the depth-probe population. That is a measured argument against raising the bound, and it is recorded as such in the gate's header by PR #13472 — this card is the standalone record so it does not live only inside a comment about a different subject.

                Sibling, not a duplicate

                #13456 records the same defect class in the sibling instrument: scripts/measure-durability-swallow-family.mjs resolves a bare identifier against a whole-file body index and reaches same-named class methods, and it notes the last-wins collision property in passing. Different file, different measurement, different member population — but very likely the same remedy shape, and they should be read together. That card's suggested remedy (resolve against the lexical scope chain at the call site rather than the flat index, then pin it with a regression control) applies here unchanged.

                Dedupe performed

                ⚠️The REST search endpoint is unavailable from this seat and this is declared rather than papered over: GET /search/issues returns HTTP 403 for both a targeted query and a known-hit control term, so search was not used and no zero from it was trusted. Repo-scoped REST reads and writes are live (HTTP 200), so dedupe ran through a bounded repo-scoped list of the 31 open finding issues — a non-empty control — plus a local keyword grep over their titles and bodies for functionBodies, last-wins, name collision, indexFunctionBodies, wrapper resolution and lookup. Two hits: #13456, the sibling named above, and #13433, unrelated. Nothing addresses the flat index in this gate.


                Generated by Claude Code

                Metadata

                Metadata

                Type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions