Skip to content

fix(runtime): route POST /api/v1/mcp/skill to the dispatcher's own 405 branch - #7790

Merged
os-help merged 2 commits into
mainfrom
claude/issue-7649-mcp-skill-405-envelope
Aug 11, 2026
Merged

fix(runtime): route POST /api/v1/mcp/skill to the dispatcher's own 405 branch#7790
os-help merged 2 commits into
mainfrom
claude/issue-7649-mcp-skill-405-envelope

Conversation

@os-help

@os-help os-help commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7649

Symptom

POST /api/v1/mcp/skill answered 405 with a body no other error on this API returns:

{ "error": "Method Not Allowed", "code": "METHOD_NOT_ALLOWED",
  "message": "POST is not supported for /api/v1/mcp/skill. Allowed: GET.",
  "method": "POST", "path": "/api/v1/mcp/skill", "allowed": ["GET"] }

instead of the standard {success:false, error:{code, message, httpStatus}} envelope
carrying the documented message "Method not allowed — use GET". A client branching on
error.code read undefined, because error was a string.

Root cause — the 405 branch was never missing

handleMcpSkillRequest (packages/runtime/src/domains/mcp.ts) has had a 405 branch since
#3842 routed it through buildApiError. The defect was one layer above it:
createDispatcherPlugin mounted ${prefix}/mcp/skill for GET only.

Since GET is the only method this route serves, a GET-only mount reads as correct. But an
unmounted verb never reaches the dispatcher at all — Hono sends it to notFound, where the
adapter's unmatchedResponse() re-matches the path across verbs and answers 405 with its own
shape. The domain's branch was dead code on this adapter, and the API carried two different
405 envelopes depending on which route you hit.

The fix

Mount /mcp/skill for the same verb set as its sibling /mcp (GET + POST + DELETE), so the
mismatch reaches the branch that already exists. No second 405 implementation is added
this PR stops bypassing the first one.

The method set tracks /mcp's deliberately: server.get/post/delete are also the three verbs
the plugin's observability Proxy instruments, so a PUT/PATCH mount here would be both wider
than the sibling route and silently un-instrumented. PUT/PATCH therefore stay adapter-owned,
which is correct — a route that does not exist under a verb is unmatchedResponse()'s job.
That boundary is pinned by a test rather than left implicit.

Behaviour change to note

The Allow header now reads GET — the domain branch's own literal — where the adapter
previously derived GET, HEAD from its route table (Hono registers HEAD implicitly beside
every GET). HEAD /api/v1/mcp/skill is still served either way. The method, path and
allowed body keys are gone from this route's 405, and error is now an object.

GET /api/v1/mcp/skill is untouched: same 200, same text/markdown, same
cache-control: no-store.

Tests

New: packages/runtime/src/mcp-skill-method-not-allowed.hono.integration.test.ts — a real
Hono server
driven over real fetch, asserting the envelope field by field.

Shaped that way on purpose. The existing coverage
(http-dispatcher.mcp.test.ts, "405s non-GET with an Allow header") calls
dispatcher.handleMcpSkill('POST', …) directly, so it cannot observe a defect that lives
in the HTTP mount — and it asserts only status + Allow. Both were already green while the
bug shipped. A status-only assertion passes in both worlds, since the status was always
405; only the body differed.

Also added: a registration assertion in dispatcher-plugin.routes.test.ts, beside the
existing /mcp one.

Reverse verification

Reverting only the source fix and keeping the tests, with the expected direction stated first:

Test Predicted Observed
POST envelope fields red red — body.success is undefined
POST is not unmatchedResponse()'s shape red red — typeof body.error is 'string'
DELETE envelope fields red red — body.success is undefined
route registration red red — 54 routes, no POST /api/v1/mcp/skill
Allow header unchanged redGET, HEAD vs GET (see below)
GET happy path green green
PUT falls to the adapter green green

The Allow row is the one prediction that was wrong, and it is reported rather than
smoothed over: the header does not merely survive the fix, it changes value. Pre-fix the
adapter derived GET, HEAD from its route table; post-fix the domain branch's literal GET
answers. The test name and the changeset were corrected to state that transition instead of
claiming the header is untouched.

Checks

  • pnpm --filter @objectstack/runtime test130 files, 2036 tests passed
  • pnpm --filter @objectstack/http-conformance test4 files, 72 tests passed (the
    cross-adapter IHttpServer unmatched-request contract)
  • pnpm --filter @objectstack/runtime typecheck — clean (tsc --noEmit)
  • eslint --no-inline-config on the three changed files — clean
  • node scripts/check-nul-bytes.mjs (+ --self-test) — clean

A changeset is included (@objectstack/runtime, patch); content/docs/releases/ is untouched.


Generated by Claude Code

#7649)

`POST /api/v1/mcp/skill` answered 405 with the hono adapter's hand-rolled
`{error, code, message, method, path, allowed}` body instead of the standard
`{success:false, error:{code, message, httpStatus}}` envelope carrying
"Method not allowed — use GET".

The 405 branch was not missing. `handleMcpSkillRequest` has had one since
#3842 routed it through `buildApiError`. The defect was one layer above:
`createDispatcherPlugin` mounted `${prefix}/mcp/skill` for GET only, so a
non-GET request matched no route, Hono sent it to `notFound`, and the
adapter's `unmatchedResponse()` answered first — leaving the domain branch
dead code on this adapter.

Mount `/mcp/skill` for the same verb set as its sibling `/mcp`
(GET + POST + DELETE) so the mismatch reaches the branch that already
exists. No second 405 implementation is added, and the GET happy path is
untouched.

Tests: a real-Hono integration suite pinning the envelope field by field
(a status-only assertion passes in both worlds, which is why this defect
survived the existing direct-call unit test), plus a registration
assertion alongside the sibling /mcp one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158ZQo7LiHSxGWpYKuPq1wu
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 11, 2026 3:44pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/runtime.

20 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via packages/runtime)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/permissions/system-context.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)

2 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)
  • content/docs/releases/v17.mdx (via @objectstack/runtime)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

os-help commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

PM review note (dispatching seat, #6024). Two things checked so the next reader does not have to repeat them.

Docs-drift advisory: resolved, no doc change needed. The bot listed 20 hand-written pages via @objectstack/runtime. The only ones that could plausibly pin a 405 envelope are protocol/kernel/http-protocol.mdx and api/wire-format.mdx; neither documents this route's 405 shape (http-protocol.mdx's only 405 is OBJECT_API_METHOD_NOT_ALLOWED, an unrelated enable.apiMethods branch). The generated code-listing pages carry code names without statuses. Nothing goes stale from this PR.

The Allow header change is accepted, but it is load-bearing and worth stating explicitly. content/docs/api/error-catalog.mdx documents METHOD_NOT_ALLOWED as:

Fix: Use the method named in the response's Allow header.

So Allow is the documented client remedy for this exact error, not decoration. This PR narrows it from GET, HEAD to GET on this route. That is accepted here — the documented guidance stays accurate (a client following it reaches for GET and succeeds), HEAD is still served, and envelope consistency across the API is the larger win. But per RFC 9110 the field advertises the methods the resource supports, and HEAD is one of them, so this is a small accuracy loss, not a neutral swap.

Recording it rather than leaving it in the PR body alone, because the reverse-verification table shows this was the one prediction that came back wrong — the header does not survive the fix unchanged, it changes value. Good catch reporting that instead of smoothing it over; that is exactly the failure mode a "predicted green, observed green" table is prone to hiding. If a follow-up wants Allow: GET, HEAD, the fix is in the domain branch's literal, and it should come with the reasoning above rather than as a drive-by.

No changes requested. Leaving this to finish CI.


Generated by Claude Code

@os-help
os-help marked this pull request as ready for review August 11, 2026 15:08
@os-help
os-help enabled auto-merge August 11, 2026 15:08
…e-check-debt

The new test file added +11 raw tsc errors to `@objectstack/runtime`'s
TEST_DEBT measurement (227 -> 238). `packages/runtime/tsconfig.json`
excludes `**/*.test.ts`, so `pnpm --filter @objectstack/runtime typecheck`
never compiled the file; only `check:type-check-debt --re-measure`, which
re-runs tsc with that exclusion dropped, can see the test layer. The ledger
is a shrink-only ratchet (#5278), so the fix is the file, not the number.

The 11 split two ways:

- 10x TS18046 `'body' is of type 'unknown'` — `Response.json()` returns
  `unknown`. Reads now go through one `call()` helper that casts once to an
  open record. Deliberately NOT a narrow interface: this suite exists
  because two different body shapes can arrive on this path, and one case
  asserts keys that must NOT exist, so a type admitting only the correct
  envelope would encode the conclusion under test.
- 1x TS2353 `'requireAuth' does not exist in type 'DispatcherPluginConfig'`
  — copied from a sibling suite. The key is dead: nothing reads it (the
  deployment-wide gate was removed), it was silently ignored, and the route
  under test is public anyway. Dropped rather than cast away.

No assertion changed. Every envelope check is still a runtime assertion on
the same field, and the reverse verification still goes red in the same
places. Also dropped a no-op `.replace('http://', 'http://')` in the GET
control.

Measured after: 227, equal to the recorded ledger entry, 0 from these files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158ZQo7LiHSxGWpYKuPq1wu

os-help commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed 5f069e6cd — fixes the red TypeScript Type Check gate (check:type-check-debt --re-measure), which measured @objectstack/runtime at 238 against a recorded TEST_DEBT of 227.

Why the PR's own typecheck line was clean and still wrong. packages/runtime/tsconfig.json excludes **/*.test.ts, so pnpm --filter @objectstack/runtime typecheck never compiled the new file. The gate re-runs tsc with that exclusion dropped. My check line was true but measured a layer that structurally could not contain the new test.

The +11, all from the new file (the dispatcher-plugin.routes.test.ts edit contributed 0):

Count Code What
10 TS18046 'body' is of type 'unknown'Response.json() returns unknown
1 TS2353 'requireAuth' does not exist in type 'DispatcherPluginConfig'

The requireAuth: false was copied from a sibling suite and is a dead key: nothing reads it (the deployment-wide gate was removed — dispatcher-plugin.ts:209, and http-dispatcher.requireauth.test.ts:56 states "There is no requireAuth: false any more"). It was silently ignored, so dropping it is a no-op; the GET positive control still passes, which is the proof.

No assertion was weakened. The 10 unknown reads now go through one call() helper that casts once to an open record — deliberately not a narrow interface, because this suite exists precisely because two different body shapes can arrive on this path, and one case asserts keys that must not exist. A type admitting only the correct envelope would encode the conclusion under test and make the negative case unwritable. Every envelope check remains a runtime assertion on the same field.

Reverse verification re-run after the refactor — byte-identical to before: 5 failed / 16 passed, same cases, same messages (expected undefined to be false, expected 'string' not to be 'string', expected 'GET, HEAD' to be 'GET', expected [ …(54) ] to include 'POST /api/v1/mcp/skill'), GET and PUT-boundary still green.

Verification of the fix round (full workspace closure built first, exactly as lint.yml does):

  • pnpm check:type-check-debt--self-test OK, then --re-measure: OK — 33 ledger entries re-measured, none above its recorded number. @objectstack/runtime measures 227, equal to the ledger; it is absent from the "can be lowered" hints.
  • pnpm --filter @objectstack/runtime test → 130 files, 2036 tests passed
  • eslint --no-inline-config on the changed file → exit 0

The TEST_DEBT entry was not raised. Also dropped a no-op .replace('http://', 'http://') in the GET control — same string either way.


Generated by Claude Code


Generated by Claude Code

@os-help
os-help added this pull request to the merge queue Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31509570177 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/data/api-methods-batch-conformance.test.ts�[2m > �[22mapiMethods conformance — single-record writes imply batch (#3026)�[2m > �[22mgrants bulk wherever it grants create /
    

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 18 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31511209233 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/data/api-methods-batch-conformance.test.ts�[2m > �[22mapiMethods conformance — single-record writes imply batch (#3026)�[2m > �[22mgrants bulk wherever it grants create /
    

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 25 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

os-help commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Auto-merge temporarily disabled — deliberately, to stop this PR burning queue rebuilds it cannot pass. Blocked on #7802 / #7818, not on anything in this diff.

Two queue builds have now failed here (31509570177, 31511209233), both on the same test in a package this PR never touches:

FAIL packages/spec/src/data/api-methods-batch-conformance.test.ts
  > grants bulk wherever it grants create / update / delete

That is #7802: main is red because #7769 gave sys_api_key update without bulk. The fix is #7818, which is green on the shard that carries this test and is waiting to merge.

Answering the triage bot's history signal directly, since it is pointing at the wrong conclusion: it flags "failed twice in 24h with unchanged content ⇒ suspect a flaky test". It is not flaky here. It is clause 2 of the same checklist — a failure in a package this PR does not touch — and the cause is identified, reproducible and already fixed in an open PR. Re-queueing cannot help until #7818 lands, and each attempt rebuilds every PR behind it in the batch.

Why disable rather than just not re-queue. Something is re-adding this PR to the queue on its own, so "I will not re-queue it" was not sufficient — it went back in and burned a second full build without my touching it. Disabling auto-merge is the only lever that actually stops the cycle. It will be re-enabled the moment #7818 is on main.

A note for anyone reading this PR's own CI history: this PR's PR-side checks are green, because the affected-subset filter never runs packages/spec for a diff confined to packages/runtime. The queue runs the full suite, which is where a red main reaches every PR regardless of what it touches. I said earlier in this round that this PR was "not affected by #7802 because it does not touch spec" — that was wrong, and this is the correction: that reasoning only ever held for the PR-side gate.

Nothing is requested of this diff. The TEST_DEBT type errors that failed the earlier TypeScript Type Check were fixed and pushed; that gate is green now.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31512044884 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/data/api-methods-batch-conformance.test.ts�[2m > �[22mapiMethods conformance — single-record writes imply batch (#3026)�[2m > �[22mgrants bulk wherever it grants create /
    

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 2 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 31 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31512974833 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/data/api-methods-batch-conformance.test.ts�[2m > �[22mapiMethods conformance — single-record writes imply batch (#3026)�[2m > �[22mgrants bulk wherever it grants create /
    

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 3 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 35 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@os-help
os-help marked this pull request as draft August 11, 2026 16:42

os-help commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Converted back to draft — deliberately and temporarily. Nothing is wrong with this diff; it will be marked ready again the moment #7818 is on main.

Escalating as stated: one comment ago I said that if a fourth queue failure arrived, disabling auto-merge had not been enough to get this PR out of the queue and I would remove it rather than explain again. 31512974833 is the fourth. Draft conversion drops both queue membership and auto-merge, and nothing can re-add it automatically — that is the only lever left that actually holds.

The reason this became urgent rather than merely wasteful. The queue tests the merged result. While this PR sits ahead of #7818 in the queue, GitHub is testing main + #7790 — a combination that does not contain the fix for #7802 and therefore fails the conformance test every single time, by construction. So this PR was not just burning full-suite rebuilds for everything behind it; it was repeatedly failing batches in front of the one PR that unblocks the queue for everyone. Pulling it out clears the path for its own unblocker.

To the triage bot's escalating signal (now "failed 3 times in 24h, unchanged content ⇒ strongly suspect flaky"): the count is right, the inference is still wrong, and it will keep climbing for as long as this PR is in the queue. Not flaky, not a semantic conflict with a co-queued PR — clause 2, a failure in packages/spec, which this diff does not touch. Cause identified, deterministic, fix open at #7818.

Restore checklist, for whoever gets here first:

  1. fix(spec,platform-objects): register sys_api_key's deliberate no-batch decision, unblocking every spec PR (#7802) #7818 merges → main green.
  2. Mark this PR ready for review.
  3. Re-enable auto-merge (squash).

No changes to the diff are needed at any point. PR-side CI was green before this, including the TypeScript Type Check that the TEST_DEBT fix addressed.


Generated by Claude Code

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31513730782 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/data/api-methods-batch-conformance.test.ts�[2m > �[22mapiMethods conformance — single-record writes imply batch (#3026)�[2m > �[22mgrants bulk wherever it grants create /
    

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 4 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 40 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@os-help
os-help marked this pull request as ready for review August 11, 2026 18:04
@os-help
os-help added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 591f675 Aug 11, 2026
26 checks passed
@os-help
os-help deleted the claude/issue-7649-mcp-skill-405-envelope branch August 11, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mcp-http-surface (a): POST /api/v1/mcp/skill returns a hand-rolled 405 envelope, not the standard API error shape

1 participant