Skip to content

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

Closed

Description

@objectstack-fleet

epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

Filing gate: a follow-up owed by landed work. PR #28515 (merged as 76b4ae446, Fixes #27401) added the mcp provider's providerConfig.toolsSnapshot: a sha256 pin per tool, where a changed definition degrades through CONNECTOR_UPSTREAM_CHANGED. It documented the pin in content/docs/automation/connectors.mdx and deliberately left skills/** alone, because that surface is governed (Tier H). The dev's report says so: "Skills-docs: follow-up owed — skills/** not edited (Tier H)". Child of #27293 (E3, author recipes). ⛔ Not a claim.

Work

Decide whether the integration recipe in skills/objectstack-automation/references/integration-recipes.md (the mcp recipe, near the include: ['search_issues'] example at :82, read at origin/main 76b4ae446) should teach the pin. If it should, add one short paragraph or bullet covering three things:

  • what toolsSnapshot pins, and that every pinned name must also be listed in include;
  • where the digests come from: computeMcpToolsSnapshot, or the digest the degraded reason prints;
  • what an author sees when a pin no longer matches.

Link to /docs/automation/connectors for the rest. The paragraph is paid for under the skills token ratchet. If the skills seat judges the pin too niche for a recipe, record that judgement on this card and close it as not planned.

Business reason

An app-authoring agent reads the skills first. Without the pin in the recipe, the GitHub connector app (and every MCP app after it) is authored with no protection against a server silently changing what a tool means. That is the exposure #27401 was opened to close.

Reader

The skills seat (domain:skills). Triage grades and routes it.

Dedupe

The 500 most recent issues and PRs (read 2026-11-01T06:21Z), titles grepped for toolsSnapshot|tool snapshot|tool-snapshot: 1 hit, PR #28515 itself. Control skills on the same set: 35 hits.

Activity

  1. added
    documentationImprovements or additions to documentation
    pm:epicReserved by a dedicated epic PM, parent or sub-issue; other PMs never take it; never with pm:queue
    on Nov 1, 2026
  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 写给 AI 的文档与 skills 说错一句,等于产品缺陷 | none | P①

    Triage: p2 · domain:skills · area:automation · pm:epic kept · 2026-11-01T06:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    Claim: PM loop round 4
    Session: session_017xRBcVBKAFk1ntXSjvPt7U
    Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-28582-skills-tools-snapshot
    Worktree: objectstack-issue-28582
    Domain: domain:skills
    Seat: epic:#27293#1
    File surface: skills/objectstack-automation/references/integration-recipes.md (the mcp recipe; one short paragraph or bullet on providerConfig.toolsSnapshot, linking /docs/automation/connectors), and only what the skills token ratchet and skills gates require beside it (stop on breach; explain in the report). Or no edit at all: if the seat judges the pin too niche for a recipe, the report records that judgement and the card closes not planned
    Container & model: S, mode:subagent, model: fable (MANDATORY — dispatch-gates --tier --repo objectstack-ai/objectstack this fire: skills/** clause ①, no one-line exit), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6554667567
    Premise: holds (read at origin/main cd065d36 2026-11-01T07:11Z: the recipe's mcp example is at integration-recipes.md:82 (include: ['search_issues']); toolsSnapshot 0 hits under skills/; PR #28515 merged as 76b4ae446)
    Serial constraints cleared: none — none of the 60 most recent open PRs touches skills/objectstack-automation/** (files read 2026-11-01T07:11Z). Landing: skills/** is governed (Tier H) — the PR waits on the maintainer.

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
    os-dev-report

    {
      "issue": 28582,
      "status": "done",
      "branch": "claude/issue-28582-skills-tools-snapshot",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28597",
      "session": "session_017xRBcVBKAFk1ntXSjvPt7U",
      "premise_still_valid": true,
      "summary": "Judgement: the pin is not too niche for the recipe — it is one key beside the `include` the recipe already shows, and an app author has a no-code route to the digests (a 64-hex placeholder pin, then the served digest the degraded reason prints on `GET /api/v1/automation/connectors`). Added one paragraph under recipe 2 (remote MCP) of `skills/objectstack-automation/references/integration-recipes.md`: what `toolsSnapshot` pins and that a pinned name `include` leaves out is refused at boot; digests via `computeMcpToolsSnapshot(tools)` or the degraded reason; a pinned tool served differently degrades the instance with no actions (`CONNECTOR_UPSTREAM_CHANGED`), one no longer listed too, the reason naming each tool and the served digest; link to the connectors page pin section. Every clause read off `mcp-provider.ts` / `tool-snapshot.ts` at base `cd065d36`. Paid under the skills token ratchet (file was 2488/2488) by deleting same-file restatements with a surviving home (SKILL.md `connector_action` row and Signature bullet, objectstack-platform `requires` rule, connectors page, recipe 1's own comment); lands 2487/2488, no ceiling moved. Changeset `@objectstack/skills` patch. Draft PR #28597 on head 64882e22; `skills/**` is Tier H so it waits for the maintainer.",
      "skills_readings": "integration-recipes.md lines 176 -> 178, bytes 9949 -> 9946, ratchet tokens 2488 -> 2487 (ceiling 2488, headroom 0 -> 1); whole skills/** tracked lines 19546 -> 19548; all 11 SKILL.md lines 4587 -> 4587 (untouched); bundle total tokens 221928 -> 221927",
      "tests": "No package touched: closure ① empty, no package test/typecheck owed, no tested behaviour changed, no ablation. Ratchet read in both directions on this tree: intermediate red `integration-recipes.md is 2496 tokens; the ratchet ceiling is 2488 (over by 8)` exit 1, final green `integration-recipes.md is 2487 tokens (ceiling 2488; headroom 1)` + `57 authored bundle file(s) within their ceilings` exit 0. Control-char scan `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` on the two edited files: no match (exit 1). Build under lock for gate 19's prerequisite: `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` → `os-verify-lock: VERDICT command-exit 0 · held the lock 2s · waited 0s`.",
      "gates": "Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on head 64882e22 (2 paths vs merge base cd065d36): 44 commands, each run with exit captured before any pipe into ran.list; `--ran` verdict: `✓ dispatch-gates --ran: 44 derived famil(ies) accounted for — 40 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3).` 0 UNRUN. All 40 run exit 0, among them check-skills-token-ratchet, check:skill-identifier-liveness, check:skill-frame-sync, check:skill-compatibility, 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, check:published-files, check:pm-governed-merges; lint check:doc-formula-expressions exit 3 first (dist absent), exit 0 after the formula+lint build. NOT MEASURED (exit 3 PREREQUISITE NOT MET, each needs the whole 129-package closure built, 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. Not run locally by rule: pnpm lint, test:repo, the repo-wide farm. PR check-runs: in_progress at report time (PR opened moments before this report; read them off #28597).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no MCP GitHub calls (reads via `gh api` GET: issue 28582 + comments once, pull 28597 once)",
      "api_writes": "2 — relay strokes as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (pr_create, request fw-20261101T073228Z-f1c956, run 41285191571, PR #28597, draft, no labels, no assignees); POST /repos/objectstack-ai/objectstack/issues/28582/comments (this os-dev-report via post-stamped.mjs). Plus 2 `git push` to origin/claude/issue-28582-skills-tools-snapshot (empty probe branch, then 64882e22) — git, not REST.",
      "deviations": [
        "Commit trailer: the harness attribution reminder's `Co-Authored-By: Claude Fable 5.1` was refused by the pre-push hook (check:commit-card-trailers, model identifier); the unpublished tip was amended to the AGENTS.md model-free pair (`Claude-Session:` + `Co-authored-by: Claude`) before any push — no published history rewritten.",
        "4 derived families NOT MEASURED locally (whole-closure dist prerequisite; listed in gates); declared to CI.",
        "No labels sent on pr_create: the dispatch named none and `skip-changeset` does not apply (the skills/** tree publishes as @objectstack/skills, so a patch changeset is included)."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed (observation, not a contract violation): `content/docs/automation/connectors.mdx` failure-mode table row for the pin folds the 'pinned tool no longer listed' case under CONNECTOR_UPSTREAM_CHANGED, while its own prose and `mcp-provider.ts` route that case to the credential-rejected path (403, `pinnedToolsHiddenError`) when the instance's credential reached the server; the prose is right, the row is a summary. Dedupe words: toolsSnapshot table row, pinnedToolsHiddenError, credential path, connectors.mdx failure modes.",
        "carrier: none · noted, not filed (no CLI prints an MCP server's tool digests; the docs page states the code route and the placeholder-pin route is what the runtime delivers, so this is a convenience gap, not a defect): an `os` subcommand that lists a server's tools with their `mcpToolDigest` would remove the need to boot once. Dedupe words: mcpToolDigest CLI, tools/list digest, computeMcpToolsSnapshot command."
      ]
    }
  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
    os-dev-report

    {
      "issue": 28582,
      "status": "done",
      "delta_of": "os-dev-report comment 6555022020 (head 64882e22) — review round: two must-fixes in the skill text plus the connectors.mdx table-row addendum",
      "branch": "claude/issue-28582-skills-tools-snapshot",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28597",
      "head": "7a8da47c (pushed to the same branch; PR body not edited)",
      "session": "session_017xRBcVBKAFk1ntXSjvPt7U",
      "premise_still_valid": true,
      "summary": "Must-fix 1: the recipe-2 paragraph now states both missing-pin outcomes off `credentialSent` in `mcp-provider.ts`: a pinned tool served differently is `CONNECTOR_UPSTREAM_CHANGED` with the digest it now serves (review, re-pin); one no longer listed is the credential path when the instance's credential reached the server, as recipe 2's `bearer` does — the stored credential marked `rejected`: fix the credential and set it again, or update the pin — and `CONNECTOR_UPSTREAM_CHANGED` otherwise. Must-fix 2: restored `Keep automation in requires whenever a connector is declared.` in the recipe file's intro (reading for the record: objectstack-platform SKILL.md:381 also carries `Keep automation whenever plugins: lists a connector`, framed on plugins:, not on a connectors: declaration; the sentence is restored here as ruled). Addendum: `content/docs/automation/connectors.mdx` failure-mode table row for the pin now names the same two cases (its left cell scopes the UPSTREAM_CHANGED outcome for a missing tool to an instance whose credential did not reach the server; the right cell adds the credential-row outcome for one whose credential did), one row, nothing else on the page. Paid under the ratchet by same-file cuts with a surviving home: recipe 6's vendor-redirect clause and the agent/API-key aside (connectors page), recipe 3's `defaultHeaders` and the auth bullet's `X-API-Key` default (connectors page), recipe 2's stdio comment shortened and recipe 4's door sentence tightened (SKILL.md:414 and the connectors table), recipe 1's `$ref` sentence tightened, and the `Not yet` section folded into the Holds `auth` bullet (WeChat Pay: mark blocked, write no plugin — SKILL.md § Integrations says the same). Every other deletion from round 1 kept.",
      "skills_readings": "integration-recipes.md lines 176 (base) -> 177, bytes 9949 -> 9951, ratchet tokens 2488 -> 2488 (ceiling 2488, headroom now 0); whole skills/** tracked lines 19546 -> 19547; all 11 SKILL.md lines 4587 (untouched); bundle total tokens 221928 -> 221928. Diff vs base cd065d36: 3 files, +50/-37.",
      "tests": "Ratchet on head 7a8da47c: `✓ check-skills-token-ratchet: skills/objectstack-automation/references/integration-recipes.md is 2488 tokens (ceiling 2488; headroom 0).` exit 0 (an intermediate state read `2527 tokens; ceiling 2488 (over by 39)` exit 1 before the cuts). Control-char scan on the two edited files: no match (exit 1). No package code touched; no ablation. Builds under os-verify-lock for gate prerequisites only, all `VERDICT command-exit 0`: spec+formula+lint via turbo (FULL TURBO cache), `pnpm --filter @objectstack/spec build` direct (61s; `git status` clean after — no generated artifact moved), client+client-react closure (38 tasks, 126s).",
      "gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on head 7a8da47c (3 paths vs merge base cd065d36): 68 commands (the docs page adds 24 docs families), each run with the exit captured before any pipe; `--ran` verdict: `✓ dispatch-gates --ran: 68 derived famil(ies) accounted for — 64 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3).` 0 UNRUN. 64 run exit 0, including check-skills-token-ratchet, check:skill-identifier-liveness, check:skill-frame-sync, check:skill-compatibility, spec check:skill-refs / check:docs / check:skill-examples / check:liveness / check:empty-state / check:variant-docs / check:yaml-examples / check:strictness-ledger, lint check:doc-formula-expressions / check:doc-security-posture, check:doc-anchors, check:doc-frontmatter, check:docs-single-h1, check:docs-redirects, check:docs-spec-enumerations, check:docs-transcript-drift, check:docs-audit-scope, check:adr-links, check:docs-section-name, check:section-landing-index, check:published-readme-links, 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, check:published-files, check:pm-governed-merges. Five first answered exit 3 on the fresh worktree's missing dist (doc-formula-expressions, doc-security-posture, spec check:docs [exit 1, 'generate the tree first'], skill-examples, docs-transcript-drift) and re-ran exit 0 after the builds above. NOT MEASURED, 4 (exit 3 PREREQUISITE NOT MET; each reads the whole 129-package closure's dist/, untouched by this diff): check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content — CI's. PR check-runs on 7a8da47c: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no MCP GitHub calls",
      "api_writes": "1 this round — relay stroke as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/28582/comments (this delta via post-stamped.mjs). Plus 1 `git push` (7a8da47c) — git, not REST. Cumulative: 3 relay writes (pr_create, report, delta), 3 pushes. PR body untouched (no PATCH).",
      "deviations": [
        "The worktree had been removed at round-1 cleanup; it was re-created from origin/claude/issue-28582-skills-tools-snapshot@64882e22 (Resume-from shape), `pnpm install`, and the gate prerequisites rebuilt under the lock.",
        "integration-recipes.md now sits at headroom 0 (2488/2488): any further sentence in that file must be paid for again.",
        "The changeset text was not reworded for the docs-row fix (content/docs is not a published package surface); the changeset still describes the skills change accurately."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed (convenience gap): no `os` subcommand prints an MCP server's tools with their `mcpToolDigest`; an author without code boots once with a placeholder pin to read the served digests. Dedupe words: mcpToolDigest CLI, tools/list digest, computeMcpToolsSnapshot command."
      ]
    }
  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
    os-dev-report

    {
      "issue": 28582,
      "status": "done",
      "delta_of": "os-dev-report comments 6555022020 (head 64882e22) and 6555246752 (head 7a8da47c) — review round 2: restore the two recipe-6 guardrails and pay only with skills/-homed text",
      "branch": "claude/issue-28582-skills-tools-snapshot",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28597",
      "head": "71213196 (pushed to the same branch; PR body not edited)",
      "session": "session_017xRBcVBKAFk1ntXSjvPt7U",
      "premise_still_valid": true,
      "summary": "Restored in recipe 6, verbatim as at base: `(an agent or API key is refused)` and `the vendor redirects to GET …/connectors/oauth/callback` (the eval integrations-declared.json:7 expectation). Paid under the ratchet only with text restated elsewhere in skills/ (git grep on this branch): recipe 1's `// a scheduled run has no trigger user` (examples-flows.md:23 and :88 carry it verbatim); recipe 1's `// multi-tenant: pin the organization too` (SKILL.md:167, `A runAs: 'system' sweep must pin its organization`); the WeChat aside's `mark it blocked, write no plugin` half (SKILL.md § Integrations are declared, not coded — the clause now reads `WeChat Pay has no scheme yet: blocked`); and one wording tightening in the toolsSnapshot paragraph that drops no fact (`the reason on GET … naming each tool` → `the GET … reason names each tool`). No other text cut; the file is UNDER the ceiling, so no ceiling question for the maintainer. Of the smaller round-1 losses the PM listed, `(organization admins by default)`, the `X-API-Key` default, `GET reads the status; DELETE revokes` and recipe 3's `defaultHeaders` stay cut: each has a home only on the connectors page, and restoring all four (≈150 bytes) would put the file over the ceiling again — flagged here as the trade, not decided.",
      "skills_readings": "integration-recipes.md lines 176 (base) -> 178, bytes 9949 -> 9926, ratchet tokens 2488 -> 2482 (ceiling 2488, headroom 6); whole skills/** tracked lines 19546 -> 19548; all 11 SKILL.md lines 4587 (untouched); bundle total tokens 221928 -> 221922. Diff vs base cd065d36: 3 files (+53/-39): the recipe file, the connectors.mdx table row, the changeset.",
      "tests": "Ratchet on head 71213196: `✓ check-skills-token-ratchet: skills/objectstack-automation/references/integration-recipes.md is 2482 tokens (ceiling 2488; headroom 6).` exit 0 (intermediate, before the organization-comment cut: `2492 tokens; … over by 4` exit 1). Control-char scan: no match (exit 1). `git grep -c` on the branch: `oauth/callback` and `an agent or API key is refused` both present in the recipe file (2 hits). No package code touched; no ablation. No eval fixture edited; no `check:*eval*` script exists in root or packages/spec package.json (the eval-adjacent gates are in the derived list below and ran green).",
      "gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on head 71213196 (3 paths vs merge base cd065d36): 68 commands, each run with the exit captured before any pipe; `--ran` verdict: `✓ dispatch-gates --ran: 68 derived famil(ies) accounted for — 67 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).` 0 UNRUN. 67 exit 0 on this head — the dist/ built last round under os-verify-lock (spec direct, formula, lint, client, client-react) stayed in place, so check:dts-closure, check:lean-entry-closure, check:sourcemap-no-sources-content, spec check:docs / check:skill-examples / check:skill-refs / check:liveness / check:empty-state / check:variant-docs / check:yaml-examples, lint check:doc-formula-expressions / check:doc-security-posture, check:docs-transcript-drift, check-skills-token-ratchet (+ --self-test), check:skill-identifier-liveness, check:skill-frame-sync, check:skill-compatibility, the docs gates (doc-anchors, doc-frontmatter, docs-single-h1, docs-redirects, docs-spec-enumerations, docs-audit-scope, adr-links, docs-section-name, section-landing-index, published-readme-links), 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, check:published-files, check:pm-governed-merges all measured green. NOT MEASURED, 1: check:dual-build-cjs-loads (exit 3 PREREQUISITE NOT MET — it needs every one of the 129 packages built; CI's). PR check-runs on 71213196: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no MCP GitHub calls",
      "api_writes": "1 this round — relay stroke as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/28582/comments (this delta via post-stamped.mjs). Plus 1 `git push` (71213196) — git, not REST. Cumulative: 4 relay writes (pr_create, report, delta, delta 2), 4 pushes. PR body untouched (no PATCH).",
      "deviations": [
        "Round-1 cuts with a docs-page-only home that remain cut (listed in summary) — restoring them is a ceiling question for the maintainer on this Tier H PR; headroom today is 6 tokens (≈24 bytes)."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed (convenience gap): no `os` subcommand prints an MCP server's tools with their `mcpToolDigest`; an author without code boots once with a placeholder pin to read the served digests. Dedupe words: mcpToolDigest CLI, tools/list digest, computeMcpToolsSnapshot command."
      ]
    }
  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    MERGED → PR #28597 through the merge queue (merge commit 28f2e99b8, queued by os-zhuang) · 2026-11-01T10:23Z. Closed completed by its Fixes #28582. pm:dispatched is removed in this act; pm:epic is kept. skills/objectstack-automation/references/integration-recipes.md now teaches providerConfig.toolsSnapshot on the MCP recipe: the pin, its digests, and the two mismatch outcomes split on whether the instance's credential reached the server. The connectors page's failure-mode row agrees with it. This closes the Skills-docs follow-up PR #28515 owed. The two optional nits in the seat record 6555464359 (64 lowercase hex; the DELETE revokes clause that eval 1 names) were not taken.

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

Metadata

Metadata

Assignees

Labels

area:automationdocumentationImprovements or additions to documentationdomain:skillsDomain lane — seat card indexed by label:pm:seatpm:epicReserved by a dedicated epic PM, parent or sub-issue; other PMs never take it; never with pm:queuepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions