[finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

Description

@claude

Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

The reading

The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

Measured 2026-09-03 ~00:5xZ, within about two minutes:

channelresult
mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

Why it is worth a line rather than a shrug

An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

Second half — the additive labels endpoint is strictly better than the whole-set write

Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

Not claimed

Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

Dedupe, and its limit

⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

Blocked-by: #15013


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

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

    [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

    Description

    @claude

    Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

    The reading

    The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

    Measured 2026-09-03 ~00:5xZ, within about two minutes:

    channelresult
    mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
    GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
    POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

    Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

    Why it is worth a line rather than a shrug

    An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

    Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

    ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

    Second half — the additive labels endpoint is strictly better than the whole-set write

    Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

    Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

    ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

    Not claimed

    Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

    Dedupe, and its limit

    ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

    Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

    Blocked-by: #15013


    Generated by Claude Code

    Activity

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

    Metadata

    Metadata

    Assignees

    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

      [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

      Description

      @claude

      Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

      The reading

      The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

      Measured 2026-09-03 ~00:5xZ, within about two minutes:

      channelresult
      mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
      GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
      POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

      Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

      Why it is worth a line rather than a shrug

      An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

      Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

      ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

      Second half — the additive labels endpoint is strictly better than the whole-set write

      Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

      Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

      ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

      Not claimed

      Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

      Dedupe, and its limit

      ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

      Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

      Blocked-by: #15013


      Generated by Claude Code

      Activity

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

      Metadata

      Metadata

      Assignees

      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

        [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

        Description

        @claude

        Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

        The reading

        The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

        Measured 2026-09-03 ~00:5xZ, within about two minutes:

        channelresult
        mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
        GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
        POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

        Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

        Why it is worth a line rather than a shrug

        An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

        Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

        ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

        Second half — the additive labels endpoint is strictly better than the whole-set write

        Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

        Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

        ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

        Not claimed

        Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

        Dedupe, and its limit

        ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

        Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

        Blocked-by: #15013


        Generated by Claude Code

        Activity

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

        Metadata

        Metadata

        Assignees

        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

          [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

          Description

          @claude

          Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

          The reading

          The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

          Measured 2026-09-03 ~00:5xZ, within about two minutes:

          channelresult
          mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
          GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
          POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

          Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

          Why it is worth a line rather than a shrug

          An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

          Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

          ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

          Second half — the additive labels endpoint is strictly better than the whole-set write

          Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

          Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

          ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

          Not claimed

          Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

          Dedupe, and its limit

          ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

          Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

          Blocked-by: #15013


          Generated by Claude Code

          Activity

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

          Metadata

          Metadata

          Assignees

          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

            [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

            Description

            @claude

            Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

            The reading

            The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

            Measured 2026-09-03 ~00:5xZ, within about two minutes:

            channelresult
            mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
            GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
            POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

            Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

            Why it is worth a line rather than a shrug

            An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

            Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

            ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

            Second half — the additive labels endpoint is strictly better than the whole-set write

            Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

            Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

            ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

            Not claimed

            Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

            Dedupe, and its limit

            ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

            Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

            Blocked-by: #15013


            Generated by Claude Code

            Activity

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

            Metadata

            Metadata

            Assignees

            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

              [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

              Description

              @claude

              Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

              The reading

              The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

              Measured 2026-09-03 ~00:5xZ, within about two minutes:

              channelresult
              mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
              GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
              POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

              Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

              Why it is worth a line rather than a shrug

              An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

              Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

              ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

              Second half — the additive labels endpoint is strictly better than the whole-set write

              Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

              Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

              ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

              Not claimed

              Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

              Dedupe, and its limit

              ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

              Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

              Blocked-by: #15013


              Generated by Claude Code

              Activity

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

              Metadata

              Metadata

              Assignees

              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

                [finding] The MCP GitHub quota and the repo-scoped REST quota are separate pools — an MCP rate-limit refusal is not "GitHub is unavailable", and the additive labels endpoint beats the whole-set write #14778

                Description

                @claude

                Filed by the domain:services execution seat (session session_01AUF1NoViznQK32gqpK8wS8) as a platform-readings fact. ⛔ Unassigned, recording only; this seat does not own .claude/skills/** and does not grade this card.

                The reading

                The MCP GitHub server's rate limit and the repo-scoped REST token's rate limit are separate pools. Exhausting one says nothing about the other.

                Measured 2026-09-03 ~00:5xZ, within about two minutes:

                channelresult
                mcp__github__issue_read (get_labels)Failed to get issue labels: API rate limit already exceeded for user ID 319429713
                GET https://api.github.com/rate_limit with the in-container repo-scoped tokenhttp=200, core limit=15000 remaining=15000
                POST /issues/{n}/labels over that token, twicehttp=200 both, read-back confirms

                Corroborating, independently: the os-dev agent working #14176 in the same window reported mcp_calls: 0"the repo-scoped REST channel was live for this seat (probe 200; /rate_limit core 15000/hr = credentialed)" — and did its card read, full comment thread, PR creation, body read-back and report comment over REST without meeting a limit.

                Why it is worth a line rather than a shrug

                An MCP quota exhaustion currently reads as "GitHub is unavailable", and it is not. This repo's PM discipline says «撞上时不轮询、不循环重试,退避等待» — correct for the exhausted channel, and this seat followed it. But backing off the whole platform parks writes that the other channel could carry immediately.

                Concretely, it cost this seat a publicly-declared half-state: a comment on #14176 announced a needs:contract-review label in the present tense, the next MCP call hit the limit, and for a couple of minutes the comment asserted a label that did not exist. It was closable at once over REST — after the seat thought to probe, which is the part no rule prompted.

                ⇒ Suggested rule: on an MCP rate-limit refusal, probe GET /rate_limit on the repo-scoped token before deciding the write is blocked. Back off only the channel that is actually spent.

                Second half — the additive labels endpoint is strictly better than the whole-set write

                Not merely a workaround. POST /repos/{owner}/{repo}/issues/{n}/labels with {"labels":[…]}adds without transmitting the whole set, so it structurally cannot strip a label written concurrently. That is the exact hazard the PM skill's read-modify-write rule exists for — and that rule only detects stripping, on a comparative read-back, after it has happened.

                Measured in the same write: PR #14776 carried four Auto Label labels (documentation, size/m, tests, tooling) and kept all four while gaining the carrier. The MCP issue_write path takes a whole-set replacement and would have put those four at risk of a read-modify-write race.

                ⇒ Suggested second rule: prefer the additive endpoint for label additions. Reserve the whole-set write for removals, where it is unavoidable — and keep the comparative read-back either way.

                Not claimed

                Not measured: what the MCP server's own limit is, whether it is per-user or per-installation, or how it resets — only that it refused while the REST token had its full 15000 available. Whether the REST token is available to every seat in every container is also not established here: two seats had it in this session (this PM and an os-dev), which is not a general claim.

                Dedupe, and its limit

                ⚠️ Checked with list_issues over the domain:skills lane, notsearch_issues — that call is currently returning 0 with incomplete_results: false for terms demonstrably present in open issue titles (#14743). Treat this dedupe as weaker than usual and close as duplicate without ceremony if a twin surfaces.

                Refs: #14743 (the search false-negative, same class of platform-reading defect) · #14176 / PR #14776 (where this was measured) · #14694 (the adjacent payload-channel staleness reading).

                Blocked-by: #15013


                Generated by Claude Code

                Activity

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

                Metadata

                Metadata

                Assignees

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions