Skip to content

[finding] platform-readings.md misses the measured facts of the 2026-08-16 quota/credential incident — "reads go REST" is not executable from an MCP-only session; mid-session credential rotation kills the GitHub MCP server #8953

Description

@claude

Category

平台事实变化 → one-line rows for .claude/skills/pm-dispatch/references/platform-readings.md (the third type accepted by the shift-report rule).

Measured facts (2026-08-16, remote cloud PM session)

  1. "读与评论一律走 REST" is not executable from an MCP-only session. MCP list_issues / search_issues are GraphQL-backed server-side with no REST alternative, and direct REST is gated by a per-session GitHub grant (403 "GitHub access is not enabled for this session") snapshotted at session start; the egress proxy additionally rejects non-repo-scoped paths (/search/*, /rate_limit excepted) with "sessions are bound to their configured repositories". A seat that hits a drained GraphQL pool therefore has no list path at all until reset. The facts table currently states the REST rule as if it were a choice the seat can make.
  2. Mid-session credential rotation kills the GitHub MCP server unrecoverably. After the maintainer re-authenticated (fleet identity switched to a different GitHub user), every mcp__github__* call returned Streamable HTTP error: invalid session — including tools that had worked minutes earlier. Not recoverable in-session; a fresh session re-binds. Advise the maintainer accordingly before rotating credentials while seats are running: in-flight seats lose their GitHub channel, not just their quota state. Corollary: quota pools are per-identity, so an identity switch also resets the burn — but shared-identity structure is unchanged.
  3. search_issues fans out per-issue GraphQL calls for Project field_values (observed failure: failed to fetch issue field values). Omit field_values via the fields parameter in every list/search call; no pm code path reads it.
  4. After an org-side auth change, repo access propagates gradually — the same endpoint returned 403, then 200, within minutes. A 403 error object saved to a file parses as JSON, and a list-expecting script can silently report a false "0 issues". Zero-hit discipline applies to list reads too: reverse-check an empty lane against the repo's open_issues_count before believing it.
  5. (documented, not measured) REST conditional requests answered 304 Not Modified do not count against the core pool — relevant only if a direct-REST read path is ever authorized for seats.

Proposed change

Add the facts above as rows in the API-quota / MCP-traps sections of platform-readings.md. Adjacent existing rows to reconcile, not duplicate: the list_issues no-assignees row, the multi-label-OR row, and the HTML-escaped-body row.

Constraints

Fix lands in .claude/skills/pm-dispatch/references/** → domain:skills; claude-fable-5 mandatory; human review + human merge (skills are ADR-class).

Provenance

Filed at the maintainer's direction in the 2026-08-16 PM session (「给 skills 席位写 issue」). Sibling card filed in the same batch: pre-round API-quota gate for pm-dispatch.


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 18, 2026
  2. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    Contributor

    Triage (skills-lane self-triage, first-touch grading): promoted — measured facts from a real incident, named landing spot (platform-readings.md), no open question. Grading and claim collapsed into one label write (finding → pm:dispatched). This dispatch also lands #9031's fact row (same facts-table sections); the PR will carry Fixes #8953 and Fixes #9031.

    Claim: PM loop round 1 (skills seat, maintainer-present session)
    Session: session_01Rn7aaamsR99FXRqLcpL99q
    Branch: claude/issue-8953-platform-readings-incident-facts
    Worktree: objectstack-issue-8953
    Domain: domain:skills
    File surface: .claude/skills/pm-dispatch/references/platform-readings.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: fable — dispatch-gates output this run: "Model tier — MANDATORY: claude-fable-5 (derived from the file surface, not recalled) ⇢ '.claude/skills/pm-dispatch/**' — clause ①"
    Clause-②: no
    Serial constraints cleared: no open PR and no live claim touches platform-readings.md; sibling card #8952 shares this file and is deliberately held out of this batch (follow-up dispatch after this one lands); #9038 stays open — only its addendum fact (write-layer angle-bracket loss) is consumed here as reconciliation input for #9031's row.


    Generated by Claude Code

  3. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    Contributor
    {
      "issue": 8953,
      "status": "done",
      "branch": "claude/issue-8953-platform-readings-incident-facts",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9485",
      "premise_still_valid": true,
      "bundled_issue": 9031,
      "files_changed": [".claude/skills/pm-dispatch/references/platform-readings.md"],
      "line_budget": "134/134 (ceiling from scripts/pm/check-skill-line-ratchet.mjs; was 133; new facts paid by in-place compression, no re-wrap-only savings)",
      "gates": {
        "head": "dbe1c8e13",
        "pnpm check:doc-authoring": "pass",
        "pnpm check:pm-skill-id-lint": "pass",
        "pnpm check:pm-skill-ratchet": "pass (134/134)",
        "pnpm check:skill-frame-sync": "pass",
        "pnpm --filter @objectstack/lint run check:doc-formula-expressions": "pass (after building the lint dependency closure)",
        "node scripts/check-nul-bytes.mjs": "pass",
        "node scripts/check-adr-merge-approval.mjs": "not locally runnable (direct REST answers 401 Bad credentials in this container); CI-owned; expected red on this PR until a maintainer approval exists, by design",
        "rederivation": "node scripts/pm/dispatch-gates.mjs on the actual diff returned exactly the six dispatched families; no missed family"
      },
      "deviations": [
        "Parked candidate 'auto-merge first arm can silently not enqueue; flip after churn heals' was NOT added as a new row - already covered by the existing enable-verification-sequence row; made explicit there at zero line cost. Candidate 'REST PR files endpoint can transiently 404 (git-first)' was missing and was merged into the git-first row.",
        "One fact fragment dropped for line budget and recorded in the PR body: the egress-proxy rejection string 'sessions are bound to their configured repositories' (the 403 grant string was kept as the diagnostic signature).",
        "create_pull_request appended a duplicate session-form footer to the PR body; left as-is (known platform write-path behavior, not another actor)."
      ],
      "summary": "Both cards' premises verified against origin/main (file, sections and the three adjacent rows named for reconciliation all present). The 2026-08-16 incident facts, the 2026-08-18 famine readings (field_values fan-out, WebFetch degraded path, git transport) and the read-layer/write-layer body-entity reconciliation landed as merged rows in platform-readings.md; read-layer escaping and the WebFetch path were cheaply re-corroborated this session. Draft PR opened, skills surface: awaiting a human merge, no ready flip or auto-merge.",
      "tests": "Gate union re-run at final head dbe1c8e13 (tree clean): all six runnable gates green as listed in gates; skip-changeset label applied via read-modify-write union and read back as ['size/m','skip-changeset'].",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    Contributor

    ACCEPT — PR #9485 (lands this card and #9031), reviewer of record: skills seat, session session_01Rn7aaamsR99FXRqLcpL99q.

    Verified against GitHub: single file .claude/skills/pm-dispatch/references/platform-readings.md, +67/−66, ratchet 134/134 — every new fact paid by in-place compression, no re-wrap-only savings observed in the diff. Spot-checks: ① the read-layer/write-layer reconciliation landed as ONE row pair with the boundary stated (read-side entity escaping is reversible; write-side stripping of short angle-bracket fragments is real storage loss; the two are explicitly not merged into "the API mutates bodies"; entity attribution and &-class marked unmeasured) — exactly the #9038-addendum conflict resolution the dispatch required; ② this session's famine readings landed (field_values fan-out kills minimal-field reads too, with the diagnostic error string; WebFetch public-repo degraded path with its three caveats; git-first extended to PR file reads); ③ both parked seat-post candidates were handled with a documented deviation — merged into existing rows rather than duplicated, at zero line cost. Gates green at dbe1c8e13 per report, re-derivation matched the six dispatched families; the ADR maintainer approval red is the human-review gate working as designed.

    ⛔ Accepted, NOT landed — skills root, ADR-class: PR stays draft, awaiting the maintainer. #9031 closes with it (Fixes both). Follow-on: #8952 stays held until this PR merges (same file).


    Generated by Claude Code

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