Skip to content

docs(skills): the automation mcp recipe teaches the providerConfig.toolsSnapshot pin - #28597

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-28582-skills-tools-snapshot
Nov 1, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/issue-28582-skills-tools-snapshot

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #28582
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:skills/objectstack-automation/references/integration-recipes.md 的 mcp 配方(第 2 则,GitHub 远程 MCP)新增一段,教 providerConfig.toolsSnapshot 钉住工具定义:钉的是什么、钉名必须在 include 里、摘要从哪来(computeMcpToolsSnapshot,或占位钉后读降级原因里打印的实际摘要)、钉不匹配时作者看到什么,并链接 connectors 文档的 pin 小节;配套一个 @objectstack/skills 的 patch changeset。
  • 为什么改:PR feat(connector-mcp,spec): toolsSnapshot pins each MCP tool; a mismatch degrades through CONNECTOR_UPSTREAM_CHANGED #28515 落地了 pin 但刻意没动 skills/**(Tier H);写应用的 agent 先读 skills,配方里没有 pin 就等于每个 MCP 应用都不设防,服务端悄悄改一个工具的含义不会被发现。
  • 风险与回滚:只改一份已发布的技能参考文件与一个 changeset,不改代码、schema、键或行为;回滚即 revert 这一个 commit。教学内容逐句对照 packages/connectors/connector-mcp/src/mcp-provider.ts 与 tool-snapshot.ts 在本基点的实现写成,没有运行时不兑现的键。
  • 先看:① integration-recipes.md 第 2 则代码块后的新段(唯一的新增内容);② 同文件为付 token 棘轮而删掉的几处重复(Holds 的 input 条、第 4 则的签名格式句、第 6 则的连接细节、WeChat 条的括号)——每处在 SKILL.md、objectstack-platform 或 connectors 文档页另有原文;③ .changeset/28582-skills-mcp-tools-snapshot.md。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs,预期看到 integration-recipes.md is 2487 tokens (ceiling 2488; headroom 1),且结尾 57 authored bundle file(s) within their ceilings。
  • 需要你做的:skills/** 是 Tier H,本 PR 等待维护者批准或合入;无其他动作。

What changes

  • skills/objectstack-automation/references/integration-recipes.md, recipe 2 (remote MCP server): one paragraph after the code block teaching providerConfig.toolsSnapshot — tool name → sha256 of the tool's tools/list definition; a pinned name include leaves out is refused at boot; digests from computeMcpToolsSnapshot(tools) (@objectstack/connector-mcp) or, with a 64-hex placeholder pin, from the served digest the degraded reason prints; a pinned tool served differently degrades the instance with no actions (CONNECTOR_UPSTREAM_CHANGED), one no longer listed too, with the reason on GET /api/v1/automation/connectors naming each tool and the digest it now serves; link to the connectors page's pin section. Every clause is read off packages/connectors/connector-mcp/src/mcp-provider.ts (parseToolsSnapshot, the include-coverage refusal, compareToolsSnapshot, toolsSnapshotDriftError, pinnedToolsHiddenError) and tool-snapshot.ts at the base commit cd065d36; no example block is added.
  • Paid for under the skills token ratchet (the file was at 2488/2488, headroom 0) by deleting restatements in the same file, each with a surviving home: the Holds input bullet's {…}-token refusal and "os validate does not judge the inputSchema fit yet" (verbatim in SKILL.md's connector_action row); recipe 4's x-objectstack-signature format (SKILL.md § Inbound webhook, Signature; the recipe now points there); the intro's plugins: / requires reminder (objectstack-platform SKILL.md, the requires table and its "Keep automation whenever plugins: lists a connector" bullet); recipe 6's "(organization admins by default)", "for the admin to open" and "GET reads the status; DELETE revokes" (the connectors page); recipe 2's "folded into the request headers" aside and recipe 4's // no trigger user (recipe 1's own comment); the WeChat bullet's alipay-v3 aside (the Holds auth list). The file lands at 2487 tokens against its 2488 ceiling; no ceiling moves.
  • .changeset/28582-skills-mcp-tools-snapshot.md: @objectstack/skills patch (the skills/** tree ships as that package), carrying Clause-②: no and Metadata-protocol: none.

Skills readings (skills/** diff — line and token counts, before → after)

Reading Before (cd065d36) After (64882e22)
integration-recipes.md, lines 176 178
integration-recipes.md, bytes / ratchet tokens 9949 / 2488 (ceiling 2488, headroom 0) 9946 / 2487 (ceiling 2488, headroom 1)
Whole package skills/**, lines (every tracked file) 19546 19548
All SKILL.md files, lines (sum of 11) 4587 4587 (untouched)
Whole shipped bundle, ratchet tokens (check-skills-token-ratchet bundle total) 221928 221927

Net content is a small deletion (−3 bytes, −1 token); the two added lines are wrap, not growth.

Tests

  • No package code changes: the dependency closure (①) is empty and no package test or typecheck is owed (②). No tested behaviour changed, so no ablation.
  • The skills token ratchet measured this edit in both directions on this tree: at an intermediate state it was red — integration-recipes.md is 2496 tokens; the ratchet ceiling is 2488 (over by 8), exit 1 — and after the last cut it is green at 2487/2488, exit 0 (log below). That red→green is the reading that the gate prices this file.
  • Control-character scan of the two edited files: grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' → no match (exit 1).

Acceptance notes

  • Judgement on the card's open question ("too niche for a recipe?"): not too niche. The pin is one key beside include, the recipe already shows include, and an app author has a no-code path to the digests — pin a 64-hex placeholder, boot, and read the served digest off the degraded reason on GET /api/v1/automation/connectors (toolsSnapshotDriftError prints tool 'X' changed (it now hashes to …)). computeMcpToolsSnapshot(tools) is exported for anyone with a tool list in code; there is no CLI command that prints a server's digests today (a finding, not a defect: the docs page says the same and the placeholder route is what the runtime delivers).
  • Deliberately not taught in the recipe (docs-only detail, same file budget): the canonical-JSON definition of the digest, the retry backoff on which a degraded instance recovers, and the credential-path nuance for a pinned tool the server no longer lists on an instance whose auth reached the server (pinnedToolsHiddenError, a 403 naming both causes). The recipe says such a tool "degrades it too" without naming the code, which is true on both paths; the linked pin section carries the rest.
  • Observation, noted and not filed (carrier: none): connectors.mdx's failure-mode table row for the pin folds the "no longer listed" case under CONNECTOR_UPSTREAM_CHANGED, while the prose above it and mcp-provider.ts route that case through the credential-rejected path when the instance's credential reached the server; the prose is correct and the row is a summary, so this is read as a precision note, not a contract violation.
  • Skills-docs: line: not owed (Clause-②: no, Metadata-protocol: none).

Verification

Final head 64882e22 (git rev-parse --short HEAD at the time of the sweep; the working tree had no further edits). Gate list derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on this diff (2 paths vs merge base cd065d36), every command run with its exit captured before any pipe, then reconciled with --ran.

  • Reconciliation verdict: ✓ dispatch-gates --ran: 44 derived famil(ies) accounted for — 40 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3). — 0 UNRUN.
  • 40 run, all exit 0, including the skills gates: check-skills-token-ratchet (check-skills-token-ratchet: skills/objectstack-automation/references/integration-recipes.md is 2487 tokens (ceiling 2488; headroom 1).), check:skill-identifier-liveness, check:skill-frame-sync, check:skill-compatibility, @objectstack/spec check:skill-refs, check:nul-bytes, check:doc-authoring, check:pm-skill-id-lint, check:empty-changeset, check:changeset-no-major, check:adr-0087-registration, check:closing-keyword-parity. @objectstack/lint check:doc-formula-expressions first answered exit 3 (its @objectstack/formula / @objectstack/lint dist absent in a fresh worktree); after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under os-verify-lock.sh (VERDICT command-exit 0) it re-ran green, exit 0.
  • NOT MEASURED locally, 4 (exit 3, PREREQUISITE NOT MET — each reads the dist/ of the whole 129-package closure, which this diff does not touch): check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content. CI runs them after its build; read them off this PR's check-runs.
  • The intermediate ratchet red that proves the gate prices this file: integration-recipes.md is 2496 tokens; the ratchet ceiling is 2488 (over by 8) (exit 1), then the final green above (exit 0).
  • Not run locally, by rule: pnpm lint, test:repo and the rest of the repo-wide farm (CI's Lint & Repo Gates, Test Core); no package test or typecheck is owed by a diff that touches no package.
  • Local-only families (check:dev-prereqs, check:skill-frame-freshness): the derivation did not name them and the diff touches no four-axis frame file or packages/spec build, so they were not run.
Run record (`ran.list`, the input to `--ran`): 44 commands with exit codes
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-skills-token-ratchet.mjs :: exit 0
node scripts/check-skills-token-ratchet.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/spec run check:skill-refs :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 3
pnpm check:dual-build-cjs-loads :: exit 3
pnpm check:gitlink-declared :: exit 0
pnpm check:lean-entry-closure :: exit 3
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:published-files :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-compatibility :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 3
pnpm check:watch-hint-literal :: exit 0
`check-skills-token-ratchet` final lines on `64882e22`
✓ check-skills-token-ratchet: skills/objectstack-automation/references/integration-recipes.md is 2487 tokens (ceiling 2488; headroom 1).
✓ check-skills-token-ratchet: 57 authored bundle file(s) within their ceilings; 10 generator-owned file(s) and 29 eval fixture(s) measured, not ratcheted.

Generated by Claude Code

…olsSnapshot pin

One paragraph under recipe 2 (remote MCP): what toolsSnapshot pins and that a
pinned name include leaves out is refused at boot; where the digests come from
(computeMcpToolsSnapshot, or the served digest the degraded reason prints); what
an author sees when a pin no longer matches; the link to the connectors page.
Paid for under the skills token ratchet by deleting restatements in the same
file that keep a home elsewhere; the file lands at 2487/2488 tokens.

Claude-Session: https://claude.ai/code/session_017xRBcVBKAFk1ntXSjvPt7U
Co-authored-by: Claude <noreply@anthropic.com>
…quires rule, fix the docs table row

Review round on the mcp recipe's toolsSnapshot paragraph: a pinned tool the
server no longer lists takes the credential path when the instance's credential
reached the server (recipe 2's bearer over http does) and CONNECTOR_UPSTREAM_CHANGED
otherwise, read off credentialSent in mcp-provider.ts; the "keep automation in
requires whenever a connector is declared" rule is restored; the connectors page's
failure-mode row for the pin now says the same two cases as its prose and the
code. Paid under the skills token ratchet by same-file cuts with a surviving
home; the file lands at 2488/2488 tokens.

Claude-Session: https://claude.ai/code/session_017xRBcVBKAFk1ntXSjvPt7U
Co-authored-by: Claude <noreply@anthropic.com>
…ith skills-homed restatements

Review round 2: "(an agent or API key is refused)" and the vendor redirect to
GET .../connectors/oauth/callback return to recipe 6 (the eval expects the
latter). Paid under the skills token ratchet only with text restated elsewhere
in skills/: the scheduled-run trigger-user comment (examples-flows.md), the
organization-pinning comment (SKILL.md's runAs system rule), the WeChat aside's
"write no plugin" half (SKILL.md § Integrations), and a wording tightening in the
toolsSnapshot paragraph that drops no fact.

Claude-Session: https://claude.ai/code/session_017xRBcVBKAFk1ntXSjvPt7U
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 71213196fed0d0a49f13f635d354b9c1bc9309b3
Local-runs: none
Scope: skills/objectstack-automation/references/integration-recipes.md + packages/connectors/connector-mcp/src/mcp-provider.ts, packages/connectors/connector-mcp/src/tool-snapshot.ts, packages/services/service-automation/src/plugin.ts, packages/services/service-automation/src/engine.ts, content/docs/automation/connectors.mdx, skills/objectstack-automation/SKILL.md, skills/objectstack-platform/SKILL.md, skills/objectstack-automation/evals/integrations-declared.json, scripts/check-skills-token-ratchet.mjs, .changeset/28582-skills-mcp-tools-snapshot.md

Isolated full review ①–④ at the skills/** tier (clause ①), read at 2026-11-01T08:19Z: the whole diff of head 71213196 against merge base cd065d36 (3 files, +53/−39), the card and its five comments (triage 6554667567, claim 6554820845, dev reports 6555022020 / 6555246752 / 6555380014), the base code the paragraph cites, and the head's check-runs (every required context success; Governed Surface Queue Guard success). Nothing built, run or re-run.

① Derived judgments

Accuracy of the toolsSnapshot paragraph (Prime Directive #10), clause by clause against the base:

  • "tool name → sha256 of its tools/list definition" — tool-snapshot.ts McpToolsSnapshot / mcpToolDigest (sha256 of the canonical JSON of { name, description, inputSchema }). Holds.
  • "a pinned name include leaves out is refused at boot" — mcp-provider.ts reads parseToolsSnapshot before connecting and throws a plain Error naming the unexposed pins; a plain throw from the factory is a configuration fault, fatal at boot. Holds.
  • "Digests: computeMcpToolsSnapshot(tools) (@objectstack/connector-mcp)" — exported from tool-snapshot.ts, same digest function the check uses. Holds.
  • "or a 64-hex placeholder pin, then the served digest from the degraded reason" — a well-formed placeholder reaches compareToolsSnapshot, lands in drift.changed with served, and toolsSnapshotDriftError prints tool 'X' changed (it now hashes to …); plugin.ts stores (thrown as Error).message as the husk's degradedReason, which engine.ts listConnectors returns, so the digest does reach GET /api/v1/automation/connectors. Holds, with one imprecision: parseToolsSnapshot accepts only 64 lowercase hex (SHA256_HEX), and the paragraph says "64-hex" — see should-fix 1.
  • "The instance degrades with no actions" — degradeConnectorInstance registers the degraded husk (instance registered degraded (no actions)). Holds.
  • "a pinned tool served differently is CONNECTOR_UPSTREAM_CHANGED with the digest it now serves" — toolsSnapshotDriftError throws ConnectorUpstreamChangedError; plugin.ts routes it with fault: 'changed'. Holds.
  • "one no longer listed is the credential path when the instance's credential reached the server, as this bearer does — the stored credential marked rejected … and CONNECTOR_UPSTREAM_CHANGED otherwise" — credentialSent = transport.kind === 'http' && sendsInstanceAuth(ctx.auth) (bearer over http qualifies; only api-key with paramName is excluded); credentialSent && drift.missing.length > 0 throws pinnedToolsHiddenError (ConnectorCredentialRejectedError, 403, both causes named); otherwise toolsSnapshotDriftError. holdConnectorForRejectedCredential marks a credential whose source === 'object' rejected via markRejected and holds the instance; an env or vault value retries on the backoff instead — the paragraph says "the stored credential", which is the right scope. Holds.
  • The link anchor #pinning-tools-toolssnapshot matches the page's #### Pinning tools: \toolsSnapshot`` heading. Holds.

The edited connectors.mdx table row now states the same two outcomes as the page's own prose in the pin section (the "When the instance's own credential reached the server (its auth over http) …" sentence) and as the credential row directly above it. The row matches the code's split on credentialSent and no longer folds the missing-tool case under CONNECTOR_UPSTREAM_CHANGED unconditionally — the out-of-scope precision note from dev report 6555022020, repaired in the same PR. Holds.

Losses — every deleted or shortened line of the recipe file, with its home on this branch (git grep at 71213196):

  • Intro "Scaffolded apps list the three executors in plugins:" — skills/objectstack-platform/SKILL.md:180 and :255. Homed in skills. "Keep automation in requires" restored verbatim. OK.
  • Holds input bullet: the {…}-token refusal, required/type/properties/items, VALIDATION_ERROR (fault-routable), "os validate does not judge the inputSchema fit yet" — skills/objectstack-automation/SKILL.md:87 (connector_action row), verbatim; the bullet now points at that row and keeps nullable, null-as-absent and the cast guardrail. OK.
  • auth bullet: api-key default X-API-Key — only on the docs page (connectors.mdx:120, :393). Docs-only loss (weighed below).
  • "Not yet" section: WeChat Pay blocked — folded into the auth bullet ("WeChat Pay has no scheme yet: blocked"); "write no plugin" is SKILL.md § Integrations are declared, not coded. The aside that alipay-v3 also verifies responses is now nowhere in skills/ — reference detail about a scheme the author names by string; acceptable.
  • Recipe 1: // a scheduled run has no trigger user — references/examples-flows.md:23, :88; // multi-tenant: pin the organization too — SKILL.md:167; $ref sentence tightened, fact intact. OK.
  • Recipe 2: stdio comment shortened to "needs the host's allowlist" — the opt-in itself is skills/objectstack-ai/SKILL.md:188 and the connectors page callout; "folded into the request headers" aside dropped — no fact an author types. OK.
  • Recipe 3: defaultHeaders: { Accept: 'application/json' } — only on the docs page (connectors.mdx:112, :769). Docs-only loss (weighed below).
  • Recipe 4: signature format — SKILL.md:355 (Signature bullet), verbatim, and the recipe now names it; "the door has no unsigned form" — SKILL.md:353 (secretRef / secret, one required). OK.
  • Recipe 6: (organization admins by default) and "GET reads the status; DELETE revokes" — only on the docs page (connectors.mdx:629, :652). Docs-only losses (weighed below). "for the admin to open" — no fact. https:// endpoints kept in a tighter sentence. OK.

The two restored guardrails are present at head: integration-recipes.md:174 (an agent or API key is refused) and :176 the vendor redirects to \GET …/connectors/oauth/callback``, both byte-identical to base.

Weighing the four docs-only losses (does losing it from the skill make an AI-authored app more likely to be wrong?):

  1. (organization admins by default) — who holds a capability by default is operator reference; the guardrail an author must respect (manage_connector_connections, signed-in session, agent or API key refused) stays. Not a correctness risk; accept.
  2. api-key default X-API-Key — a default an author could rely on by omitting headerName, but omitting it yields the correct default and the recipe's own example sets headerName explicitly, so no copied app is wrong either way. Accept.
  3. "GET reads the status; DELETE revokes" — an administrator's API, not something the app author types; accept as a skill fact, except that eval 1's expected_output in evals/integrations-declared.json:7 still names "DELETE revokes", and that clause is now taught nowhere in the bundle. The eval's must_contain (/connection and nine others) is still satisfiable from the recipe, so the eval stays teachable; the one clause is a grader-rubric gap. See should-fix 2.
  4. Recipe 3 defaultHeaders — an optional providerConfig key; an author who never sees it writes a working connector without it, and the key lives on the docs page the recipe links. Accept.

② Semver level

@objectstack/skills patch is right: packages/skills publishes the skills/** tree (sync-catalog.mjs), a prose-only change to a published reference file, no schema, key or behaviour change; Clause-②: no and Metadata-protocol: none on both the changeset and the PR body, consistent with a none kind at patch. The changeset body carries no model identifier. The content/docs row is not a published-package surface and rightly has no changeset line of its own.

③ Boundary flags

  • Governed surface: skills/** (Tier H). The landing stays the maintainer's; this record is the tier-clause-① review the epic PM seat owes before handing over, not an approval, and arms nothing.
  • Ratchet (scripts/check-skills-token-ratchet.mjs, unchanged in the diff): the gate counts ceil(utf8 bytes / 4) on every authored bundle file; the row ['skills/objectstack-automation/references/integration-recipes.md', 2488] is identical at base and head. The file is 9949 bytes at base (ceil(9949/4) = 2488, headroom 0) and 9926 bytes at head (ceil(9926/4) = 2482, headroom 6), reproduced from git show and wc -c without running the script. No ceiling moved; the paragraph is paid by same-file deletion, which is the only path the ratchet's header allows without a ruling. Holds.
  • No Tier S paths, no .claude/**, no workflow, no ADR touched. No fork head.
  • The PR body (last written at head 64882e22) is stale against 71213196: its 两分钟验证 line expects 2487 tokens (ceiling 2488; headroom 1) and its readings table and acceptance note ("the recipe says such a tool 'degrades it too' without naming the code") describe round 1. The maintainer running the two-minute check today reads 2482 … headroom 6. See should-fix 3.

④ Design judgment

Against the card's own test — "would an app-authoring agent reading the skills first author an MCP connector app with no protection against a server silently changing what a tool means?" — the paragraph now closes that exposure in the one place the recipe already shows include, with a no-code route to the digests and the exact outcome the author will see on the connectors listing, including the credential/pin ambiguity that recipe 2's own bearer triggers. It teaches no key the runtime does not deliver (toolsSnapshot, computeMcpToolsSnapshot, CONNECTOR_UPSTREAM_CHANGED, the rejected mark are all read off the base code). The dev's "not too niche" judgment is sound: the pin is one key beside include and the GitHub connector app is the first consumer. The payments are restatements homed in SKILL.md, a sibling skill or the linked page, the two OAuth guardrails the PM asked back are restored verbatim, and the file lands under its ceiling with headroom left. The row fix on the docs page brings the table in line with the prose and the code rather than leaving a summary that contradicts both.

Must-fix: none.

Should-fix (none blocks the hand-off; each fits the 6-token / 24-byte headroom on its own, not all together — pick or let the maintainer pick):

  1. should-fix — integration-recipes.md:91: "64-hex placeholder pin" → "64 lowercase hex": parseToolsSnapshot refuses an uppercase digest at boot, and this is the no-code route the paragraph recommends (+10 bytes).
  2. should-fix — either restore "; DELETE revokes" at integration-recipes.md:176 (+18 bytes) so eval 1's expected_output clause has a home in the bundle, or trim that clause from evals/integrations-declared.json:7 in the same PR; today the rubric names a fact the skill no longer teaches.
  3. should-fix — refresh the PR body for head 71213196: the 两分钟验证 expected line (2482 tokens (ceiling 2488; headroom 6)), the readings table (bytes 9926, lines 178, bundle 221922), and the acceptance note on the missing-tool case, which the paragraph now states on both paths.

Implemented-by: claude/issue-28582-skills-tools-snapshot
Reviewed-by: session_017xRBcVBKAFk1ntXSjvPt7U

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

席位核对

ACCEPT at head 71213196 · Implemented-by: claude/issue-28582-skills-tools-snapshot · Reviewed-by: this seat (lane ACCEPT at TIER_DEFAULT) + the isolated skills/**-tier record PASS 6555451576 on this same head (Served-tier CONTRACT_REVIEW_TIER, no must-fix). Governed (Tier H): a human merge is the review record.

Check Result
Shape Draft, base main. First line is Fixes #28582, the only closing keyword. Changeset: @objectstack/skills patch.
Scope 3 files, +53/−39: skills/objectstack-automation/references/integration-recipes.md, one row of content/docs/automation/connectors.mdx (a surface addendum ordered by the seat: it now agrees with the page's prose and with mcp-provider.ts), and the changeset.
Rounds Round 0 added the paragraph. Round 1 (seat review): the pinned-tool-missing case is stated on both paths, because recipe 2's bearer takes the credential path; the requires line is restored; the docs row is fixed. Round 2 (seat review): two trimmed guardrails are restored, "(an agent or API key is refused)" and the GET …/connectors/oauth/callback redirect that eval 1 expects.
Ratchet integration-recipes.md 2482 of 2488 tokens. No ceiling moved. Every cut is restated elsewhere in skills/ except four facts now documented only on the docs page (below).
Gates 68 derived, 67 run, 1 not measured (check:dual-build-cjs-loads, which CI runs). CI on the head: none red.

维护者速读

  • 改了什么:在 skills 的 MCP 集成配方里加了一段,教 providerConfig.toolsSnapshot 工具锁定:锁什么、摘要怎么拿到,以及工具变了或不见了时实例会怎样(带凭证的实例按凭证失效处理)。连接器文档的故障表里同步改了一行。
  • 为什么改:[Decision] connector-mcp tool-snapshot pin (#26709 item 3(c)): one aggregate toolsSnapshotSha256, or a per-tool pin record that can name the tool a server rewrote #27401(PR feat(connector-mcp,spec): toolsSnapshot pins each MCP tool; a mismatch degrades through CONNECTOR_UPSTREAM_CHANGED #28515)上线了工具锁定,但 skills 里没有,写应用的 AI 读 skills 时不会知道这个功能。
  • 风险与回滚:只改文字,不涉及代码,回滚就是 revert 这一个 PR。为了守住 token 上限,删掉了一些在 skills 别处有原文的重复句子。另有 4 处细节现在只在文档站上有:默认组织管理员才能连接、api-key 默认请求头 X-API-Key、GET 查状态 / DELETE 撤销、recipe 3 的 defaultHeaders。
  • 先看:integration-recipes.md 里 recipe 2 末尾那段,以及 recipe 6 恢复的两句。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs 应输出 integration-recipes.md is 2482 tokens (ceiling 2488; headroom 6)。PR 正文里写的 2487 是第一轮的数字,已经过时。
  • 需要你做的:批准即可合并(契约评审 PASS 6555451576,Head-sha 71213196fed0d0a49f13f635d354b9c1bc9309b3)。另外有两个可选的小改动,剩余预算只够做其中一个:① 把 "64-hex" 改成 "64 lowercase hex"(大写的摘要在启动时会被拒);② 把 "; DELETE revokes" 加回来,或者从 eval 1 的 expected_output 里去掉这一句。

席位意见:建议按现状批准。这一段讲的每一句都和代码对得上,评审员逐句核对过。两个可选改动都不影响正确性:大写摘要会在启动时直接报错,不会悄悄失效;DELETE 那句属于管理员 API,不是应用作者要写的代码。

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/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills: teach the mcp provider's providerConfig.toolsSnapshot pin in skills/objectstack-automation, the Skills-docs follow-up PR #28515 owes

2 participants