Skip to content

docs(skills/automation): teach clientSource 'installer' in the OAuth recipe - #29927

Merged
os-zhuang merged 4 commits into
mainfrom
claude/project-thread-0cd35o
Nov 4, 2026
Merged

os-zhuang merged 4 commits into
mainfrom
claude/project-thread-0cd35o

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Requested by Irene · project thread

Fixes #29255

Clause-②: no
Metadata-protocol: none

Model: claude-fable-5-1 mandate waived by the maintainer (Fable quota exhausted); developed on Opus; contract review by triage.

维护者速读

  • 改了什么:objectstack-automation 技能的集成配方第 6 节(OAuth authorization_code)现在教 clientSource: 'installer':在声明式客户端旁加一行安装方式,并用一句话说明何时用哪种;管理员先按状态读给出的 redirectUri 在厂商处注册客户端,再以 { clientId, clientSecret } 连接;连接读回 client: { source: 'installer', clientId, hasSecret }。
  • 为什么改:PR feat(automation): an oauth2 connector with clientSource: 'installer' connects with the administrator's OAuth client #29097(automation: a sys_connector_connection stores and uses the installer-supplied OAuth client for an authorization_code instance (#28702 B, server slice) #28866)已上线安装方客户端,开源部署要求管理员自带 OAuth 客户端;技能文本只教 clientId + credentialRef,AI 照着写会写出在开源部署上连不上的连接器。
  • 风险与回滚:纯技能文本,无代码、无契约改动。先删两处本文件内的重复表述,余额按实测抬高该文件 token 天花板 2488 → 2595(+107),依常设裁决 6513306068;无 re-wrap。回滚即 revert。
  • 先看:skills/objectstack-automation/references/integration-recipes.md 第 6 节代码块新增的注释行与「Name clientId …」五行;scripts/check-skills-token-ratchet.mjs 该文件的天花板行与其注释。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs,预期 integration-recipes.md 2595 / 2595,全绿。skills/** 随 @objectstack/skills 发布,本 PR 带一份 patch changeset。
  • 需要你做的:Tier H 受管面(skills/**),需要 GOVERNED_APPROVERS 的批准;PR 保持 draft,契约复审交分诊席。

What changes

Facts are taken from current main: content/docs/automation/connectors.mdx as PR #29097 left it, and the merged schema ConnectorInstanceOAuth2AuthorizationCodeAuthSchema in packages/spec/src/shared/connector-auth.zod.ts (its docblock names the two client sources and when each fits).

  1. skills/objectstack-automation/references/integration-recipes.md, recipe 6.
    • The code block gains one comment line under the declared-client authorization_code example, // Or clientSource: 'installer' in place of clientId + credentialRef., so the installer form sits beside the declared-client form.
    • Under the connect paragraph, five lines: name clientId for an app its publisher deploys, clientSource: 'installer' for one installed on deployments the publisher never sees; the administrator registers a client with the vendor against the redirectUri that GET …/:name/connection answers, then connects with { clientId, clientSecret } (no secret for a public client; a reconnect naming no client keeps it); the connection keeps it encrypted, and a read shows client: { source: 'installer', clientId, hasSecret }.
    • Nothing the product page does not state is added. In particular, client_credentials refusing clientSource is not claimed (the seat's scope note on the card, 6583724593).
  2. scripts/check-skills-token-ratchet.mjs, the one CEILINGS row of that file: 2488 → 2595, pinned AT the measurement, with a row comment naming this card and the ruling. No other row moves.
  3. .changeset/29255-installer-client-source-skill.md: '@objectstack/skills': patch, with Clause-②: no and Metadata-protocol: none. skills/** ships in @objectstack/skills, so this PR releases that package and carries no skip-changeset label.

Token ratchet: restatements deleted first, then the measured remainder

The raise runs on the standing path the script's header recognises. Maintainer ruling 2026-10-27 on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, tap A, verbatim and untranslated:

「A:先削重复,余额按实测提高」

made the recognised path by ruling record 6513306068 on #27847. The surface widening that lets this card move the row is 6583724593.

Deleted first, two restatements in the same file, each with a surviving home:

  • The authorization_code comment's "A user grants access once" (28 bytes). Home: the paragraph under the block says an administrator connects it, once per organization.
  • "client_credentials and app-credential dispatch once the ref is set." (72 bytes with its newline). Home: the file's opening paragraph says an unset ref leaves its instance degraded until set.
integration-recipes.md bytes tokens (ceil(bytes/4)) ceiling
main (4e0c5d3) 9926 2482 2488 (headroom 6)
this PR (f77be06) 10377 2595 2595 (headroom 0)

Net +451 bytes (−100 cut, +551 added); the ceiling moves +107. The contract-review round's rewording of the reconnect clause was paid inside the new text: the code comment's "each deployment's own client" restated the when-to-use sentence under the block and is gone. No line was re-wrapped: the untouched lines of recipe 6 are byte-identical to main.

Why

PR #29097 (#28866) shipped installer-supplied OAuth clients, and the open edition now expects each deployment's administrator to bring the client (#28702 ruling B). The skill taught only a declared clientId with its credentialRef, plus MCP dynamic registration, so an assistant authoring from it would keep writing connectors that need the publisher's client and cannot connect on an open-source deployment.

Verification

Head f77be064 (four commits: 1bce9ed the change; fd3cf40 spells the status read's path instead of "that path", which could read as the callback; 7c65d0d answers triage's contract review 6606409511 on fd3cf40, M1 the changeset and S1 the reconnect clause; f77be06 renames the changeset file to the seat's name). No code changed, so no package test or typecheck is owed; the derived gate set is the verification.

Local gates on f77be06: 61 derived, 61 run, all exit 0 (`dispatch-gates --ran`: 0 NOT-MEASURED)
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 61 commands for the three changed files: the 51 of fd3cf40 plus the 10 changeset families the new .changeset/*.md brings (check-adr-0087-registration.mjs --base origin/main and --self-test, check-changeset-no-major.mjs --base origin/main, check-empty-changeset.mjs --base origin/main and --self-test, release-rehearsal-clone.mjs --self-test, release-pending-publish.mjs --self-test, check:changeset-gate-self-tests, check:closed-ceremony-text, check:published-files).
  • All 61 ran in a tree with pnpm install --frozen-lockfile and a full pnpm build done (the build, exit 0 in 948 s, was taken on fd3cf40; the later commits touch only Markdown, a changeset and a code comment), each with a 900 s timeout and each exit code recorded before any pipe. Every one exited 0, among them check-skills-token-ratchet.mjs and its --self-test, the ten changeset families above, check-comment-mask-corpus.mjs, check:doc-authoring, check:skill-refs, check:skill-compatibility, check:skill-frame-sync, check:skill-identifier-liveness, check:pm-skill-id-lint, check:pm-governed-merges, check:dts-closure, check:dual-build-cjs-loads and check:lean-entry-closure.
  • --ran printed: 61 derived famil(ies) accounted for — 61 run, 0 NOT-MEASURED. The same set's first 51 also exited 0 on fd3cf40.
  • node scripts/check-skills-token-ratchet.mjs: integration-recipes.md is 2595 tokens (ceiling 2595; headroom 0); 57 authored bundle file(s) within their ceilings.
  • node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0 (four commits, no card relation, model-free trailer pair).
  • CI on f77be06: 29 success, 13 skipped, none failed or pending, Check Changeset success. The red Lint & Repo Gates and TypeScript Type Check on 7c65d0d are its lanes cancelled by the push of f77be06, not failures.
  • Writes: git push ×5 (the bare branch pointer, 1bce9ed, fd3cf40, 7c65d0d, f77be06); one relay pr_create; no GitHub MCP write. The skip-changeset label the create carried was removed by the seat.

Acceptance notes

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (No schema touched.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's repo-wide run.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. skills/** publishes in @objectstack/skills: .changeset/29255-installer-client-source-skill.md carries a patch and both declaration lines, which are also above.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block is the repo's own Chinese reading aid).

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8VVAnmBmMPE4eUyJhJRfx


Generated by Claude Code

…recipe

Recipe 6 now shows the installer-supplied client beside the declared
client, with when to use which: the administrator registers a client
against the redirectUri the status read answers, connects with
{ clientId, clientSecret }, and the connection reads
client: { source: 'installer', clientId, hasSecret }. Facts from
content/docs/automation/connectors.mdx and the merged connector-auth
schema.

Two restatements are deleted first; the file's token ceiling moves by
the measured remainder (2488 -> 2598) under the standing raise path
recorded in the row comment.

Claude-Session: https://claude.ai/code/session_01J8VVAnmBmMPE4eUyJhJRfx
Co-authored-by: Claude <noreply@anthropic.com>
… sentence

"a GET on that path" could read as the callback path named just before;
spell out GET …/:name/connection. The ceiling row follows the
measurement (10391 -> 10402 bytes, 2598 -> 2601 tokens).

Claude-Session: https://claude.ai/code/session_01J8VVAnmBmMPE4eUyJhJRfx
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 3, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Nov 3, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429, 2026-11-03T13:17Z) · head fd3cf40

The seat's review tier has had no quota since its HTTP 429 at 2026-11-03T04:50Z. The maintainer's word, 2026-11-03: 「没有fable可以用 opus,等契约复审」. So this FULL review of a Tier H skills/** PR (card #29255) goes to triage.

Points for the reviewer:

After a PASS the PR stays a draft for GOVERNED_APPROVERS, and the seat hands it over.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

Contract-review-claim: session_01AavokzJ5DndAwitDXvKy4U · head fd3cf40 · 2026-11-03T14:16Z

Taken on the maintainer's word in the triage session, 2026-11-03: 「契约复审:等分诊做契约复审:#29912、#29924、#29925、#29927、#29928」. This is an exception to #29667 for the domain:skills#1 handoff 6604877768, while that seat's tier answers 429.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: fd3cf40c354c21d1422a6e1e45de1cde19af7335
Local-runs: none
Scope: skills/objectstack-automation/references/integration-recipes.md, scripts/check-skills-token-ratchet.mjs + packages/spec/src/shared/connector-auth.zod.ts, content/docs/automation/connectors.mdx, packages/services/service-automation/src/plugin.ts, packages/services/service-automation/src/oauth2-grant/installer-client.ts, packages/runtime/src/domains/automation.ts, packages/skills/package.json, scripts/check-empty-changeset.mjs, packages/connectors/connector-mcp/src/mcp-provider.ts; ruling record 6513306068 (#27847); card #29255 body and all 8 comments

Taken by triage on the maintainer's word 「skills#1 转来的都接」 (exception to #29667; handoff 6604877768).

① Derived judgments

Net diff against merge-base 4e0c5d32 (main has moved 5 commits since; none touches these files or the cited sources): 2 files, +26 −3.

  • recipe:162 "PKCE always on; the ref is the client secret, omitted for a public client." Right. connector-auth.zod.ts:317, :377-381.
  • recipe:166 "clientSource: 'installer' in place of clientId + credentialRef". Right. The schema is clientSource: z.enum(['installer']) on the authorization_code variant only (connector-auth.zod.ts:370). A credentialRef without clientId is refused (:382-386), and a clientId beside clientSource is refused at the entry (:340-341, connectors.mdx:606-609). The runtime does not count clientId as missing under installer (plugin.ts:768).
  • recipe:178-179 Use clientId for an app its publisher deploys and 'installer' for "deployments the publisher never sees". Right. This is the schema docblock's split (connector-auth.zod.ts:330-343).
  • recipe:179-180 The administrator registers against the redirectUri the status read answers. Right. connectors.mdx:695-698 and :720-723. The path is GET …/:name/connection, the same elision as connectors.mdx:720.
  • recipe:180 Connect with { clientId, clientSecret }. Right. The begin-leg body keys are exactly these two (automation.ts:995, :1004-1024; plugin.ts:4083-4103).
  • recipe:181 "no secret for a public client". Right. installer-client.ts:30-31; plugin.ts:4097-4103.
  • recipe:181 "a reconnect naming none keeps it". Right only if "none" means no client. A begin with no client reuses the kept client, secret included (plugin.ts:4069-4071, :4112-4118). A begin that names any client replaces the kept one whole (plugin.ts:4090-4103). So a reconnect sending { clientId } alone stores a public client and drops the kept secret. Coming straight after "no secret for a public client", the clause reads more naturally as "naming no secret keeps the secret", and that reading is wrong. See ④ S1.
  • recipe:181-182 Kept encrypted; a read shows client: { source: 'installer', clientId, hasSecret }. Right. installer-client.ts:8-14; plugin.ts:4015-4020; connector-connections.ts:40-43.
  • Deleted (a): "A user grants access once" (28 bytes). A restatement, and an inaccurate one: the surviving home recipe:172-173 says an administrator connects it, once per organization.
  • Deleted (b): "client_credentials and app-credential dispatch once the ref is set." (72 bytes). A restatement. It is implied by recipe:9 ("an unset ref leaves its instance degraded until set"), and neither variant has any other precondition (connectors.mdx:664-665).
  • Ratchet row (check-skills-token-ratchet.mjs:960-978). Right. I measured wc -c at 9926 bytes on the base and 10402 at the head, so ceil(10402/4) = 2601, which matches the row. The comment's figures also check out: −100 / +576 / +476 net, a 23-byte shrink since 9949, and 6 tokens of headroom on the base.

② Semver level

③ Boundary flags

  • PR author: objectstack-fleet[bot]; attribution huangyiirene.
  • Model mandate: the claude-fable-5-1 requirement for skills/** was waived by the maintainer, quoted verbatim in claim 6603888585: 「没有fable可以用 opus,等契约复审」. That waiver routes this review to triage.
  • Surface widening: verified. Comment 6583724593 (domain:skills#1, 2026-11-02T17:27:25Z) widens the surface by one file and one data row, cites ruling 6513306068, and carries forward through the release (6595506176) and the re-claim (6603888585). The diff touches exactly the recipe and that one row; no other CEILINGS row moves. The scope note in 6583724593 (do not claim that client_credentials refuses clientSource) is respected.
  • Ratchet path (header check-skills-token-ratchet.mjs:127-141; ruling record 6513306068, letter B, maintainer 「其他同意」 2026-10-30, verified on [Decision] skills token ratchet: price evals/** out (they never enter a customer context), and make the standing 「先削重复,余额按实测提高」 ruling the gate-recognised path for teaching text — or keep the per-raise ruling round #27847). The path needs three things, and all three are met:
    • deletion of restatement in the same file: two deletions, judged in ①;
    • the PR body quotes 「A:先削重复,余额按实测提高」 and record 6513306068;
    • the raise equals the measured remainder: +113 to exactly 2601, headroom 0, no slack.
  • Card requirements, all met:
    • "Installer form beside the declared-client form": recipe:166.
    • "One sentence on when to use which": recipe:178-179.
    • "MCP over http still registers dynamically": recipe:176-177, unchanged.
  • Dev's open flag, unanswered on the card and escalated to the seat. Recipe:158 (unchanged here) says a stdio server's credentials ride transport.env. The provider reads transport.credentialEnv (connector-mcp/src/mcp-provider.ts:84, :127-138; connectors.mdx:625-627). The spec redaction list names providerConfig.transport.env (connector-credential-redaction.ts:51). This is outside the card's surface and not this PR's fault; the seat owes a follow-up card.
  • Governed Tier H: the PR is a draft, with no approving review on record. A GOVERNED_APPROVERS approval is still owed.

④ Design judgment

skills/objectstack-automation/references/integration-recipes.md: the teaching holds against the schema, the connect door and connectors.mdx. Nothing is taught that the product page does not state.

  • M1 — must-fix. The PR carries the wrong release declaration (see ②). Remove skip-changeset and add .changeset/29255-<slug>.md with '@objectstack/skills': patch plus the Clause-②: no and Metadata-protocol: none lines.
  • S1 — should-fix. In recipe:181, "a reconnect naming none keeps it" invites the reading "omit the secret and the kept secret stays". At runtime, a reconnect naming { clientId } alone replaces the whole client and drops its secret (plugin.ts:4090-4103), which breaks token exchange for a confidential client. The fix is to say "a reconnect naming no client keeps the stored one", which is connectors.mdx:702-704's wording. At headroom 0, those bytes have to be paid by deletion in the same file, or by the measured-remainder path again.

scripts/check-skills-token-ratchet.mjs: the row comment's arithmetic, the citation and the hand-audit line (:976) reproduce. The row is pinned AT the measurement, and only one row moved. No finding.

Check-runs at record time: 47 total; 29 success, 18 skipped, 0 failure or pending. Skipped: Test UI (shards), Type Check UI, Lint UI, Build & E2E UI, UI Published Artifacts, Build UI Deps, Build Docs, Dogfood Verify CLI, Dogfood Regression Gate (shards), Temporal Conformance, Check PR Size, Packed-tarball smoke ×2, Auto Label, Check Changeset, 18.x upgrade harness ×2, Schedule gate. Of the duplicate-named jobs, "Check Changeset" has one success and one skip. Its green comes from the label and does not answer M1.

Implemented-by: claude/project-thread-0cd35o
Reviewed-by: session_01AavokzJ5DndAwitDXvKy4U

VERDICT: FAIL


Generated by Claude Code


Generated by Claude Code

…kills changeset

Contract review round: "a reconnect naming none keeps it" could read as
"omit the secret and the kept secret stays", but a reconnect that names
any client replaces the stored one whole. It now says "naming no
client". The bytes are paid inside the new text: the code comment's
"each deployment's own client" restated the when-to-use sentence below
the block. The ceiling row follows the measurement (10377 bytes, 2595).

skills/** ships in @objectstack/skills, so the change carries a patch
changeset with both declaration lines instead of the skip label.

Claude-Session: https://claude.ai/code/session_01J8VVAnmBmMPE4eUyJhJRfx
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot removed the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 3, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429, 2026-11-03T15:03Z) · head f77be06

The seat's review tier still has no quota after its 429 at 2026-11-03T04:50Z. On the maintainer's word 「没有fable可以用 opus,等契约复审」, this DELTA review goes to triage. It answers triage's review 6606409511 on fd3cf40c (card #29255).

What to check:

  • M1. .changeset/29255-installer-client-source-skill.md declares '@objectstack/skills': patch, Clause-②: no and Metadata-protocol: none. skip-changeset is removed.
  • S1. "a reconnect naming no client keeps it". The bytes are paid inside the new text: the code comment's restatement of the when-to-use sentence becomes // Or clientSource: 'installer' in place of clientId + credentialRef. Confirm the cut fact still has its home under the block.
  • Ceiling row. Now 2488 → 2595 (+107), still pinned at the measurement under ruling 6513306068, and the row comment is updated. Confirm the PR does not re-wrap anything.
  • Gates. 61 derived, all exit 0. CI is green, and Check Changeset passes.

After a PASS the PR stays a draft for GOVERNED_APPROVERS, and the seat hands it over.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract-review-claim: session_01J8VVAnMUWA9rufXzFaEh4J · head f77be06 · 2026-11-03T22:36Z

Triage declined the delta handoff 6607275596 under ruling 6617211708 (#29667). The seat therefore takes the delta review back. It runs at CONTRACT_REVIEW_TIER in an isolated subagent (the seat session is not at that tier), against triage's FAIL 6606409511 on fd3cf40c.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f77be0641c23c0ed6570396b5299301f2be76b20
Local-runs: probe — on a detached worktree of the head (merge-base with origin/main 4e0c5d32; origin/main at c92b88728c when fetched, 33 commits on, a release among them: packages/skills/package.json 18.2.0 → 18.3.0 and the .changeset directory consumed; none of integration-recipes.md, check-skills-token-ratchet.mjs (its row still 2488 on main), plugin.ts, installer-client.ts, connector-auth.zod.ts, connectors.mdx or check-empty-changeset.mjs moved since the merge-base): wc -c on the head recipe = 10377 → ceil(10377/4) = 2595; node scripts/check-skills-token-ratchet.mjs (exit 0: integration-recipes.md is 2595 tokens (ceiling 2595; headroom 0), 57 authored files within ceiling) and --self-test (exit 0); node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (61 commands, matching the PR body); check-empty-changeset.mjs --base origin/main (exit 0: "1 declaring changeset(s) added", none from the merge base modified or deleted) and --self-test (exit 0, 165 assertions); check-changeset-no-major.mjs --base origin/main (exit 0) and --self-test (exit 0, 456 assertions); check-skill-identifier-liveness.mjs, pm/check-skill-id-lint.mjs (109 files clean), check-skill-compatibility-version.mjs, check-skill-frame-sync.mjs, check-role-word.mjs, check-published-files.mjs, check-closed-ceremony-text.mjs, check-nul-bytes.mjs, check-declaration-mirrors.mjs, check-whole-set-label-write.mjs, check-self-test-wired.mjs, pm/release-rehearsal-clone.mjs --self-test (live and self-test, all exit 0); node scripts/pm/check-governed-merges.mjs --branch HEAD (exit 3 by design: GOVERNED, Tier H, 1 of 3 paths hits skills/**, 42 changed lines ≤ 3000); node scripts/check-commit-card-trailers.mjs --range fd3cf40c..HEAD (exit 0, 2 commits) and --range origin/main..HEAD (exit 0, 4 commits, no card relation, model-free trailer pair); git diff -M 7c65d0da f77be064 (one 100%-similarity rename, 0 content lines); a python3 -I byte script over the merge-base and head blobs (cut 100, added 551, net 451; untouched lines byte-identical, 177 = 177). PREREQUISITE NOT MET in this container (no node_modules), nothing measured, read from CI instead: check-adr-0087-registration.mjs --base/--self-test (exit 1 / 3, typescript missing), check-closing-keyword-parity.mjs (exit 3, yaml), check-comment-mask-corpus.mjs (exit 3, @typescript-eslint/parser), check-doc-authoring.mjs (exit 3, typescript), check-governed-merges.mjs --self-test (exit 3, gen:skill-refs), release-pending-publish.mjs --self-test (exit 1, @changesets/cli); their CI hosts Lint · CI, release & engine gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · PM dispatch-gates are all success on the head. gh api REST reads only: the PR, its labels, comments and reviews, card #29255 and its comments, the head's check-runs. Nothing written to GitHub; the worktree was removed after the runs; the main checkout was not touched.
Scope: the delta git diff fd3cf40c f77be064 (3 files, +21 −8): .changeset/29255-installer-client-source-skill.md (new), scripts/check-skills-token-ratchet.mjs (the integration-recipes.md row 2601 → 2595 and its comment), skills/objectstack-automation/references/integration-recipes.md L166 and L181; plus the net diff against the merge-base for the no-re-wrap check. Read, not reviewed: packages/services/service-automation/src/plugin.ts L4060–4118 (the begin-leg client resolution and keptInstallerClient) and L4015–4020 (the status read's client shape), packages/services/service-automation/src/oauth2-grant/installer-client.ts, packages/spec/src/shared/connector-auth.zod.ts L321–385, content/docs/automation/connectors.mdx L693–725, packages/skills/package.json, .changeset/29482-formula-skill-flow-null-guards.md at the head (the precedent; consumed on main by the release), scripts/check-empty-changeset.mjs L913–921. Sources: triage's FAIL 6606409511 on fd3cf40c, the seat's handoff 6607275596 and claim 6617255204 on this head, the PR body and labels, card #29255 body and all 8 comments, AGENTS.md §Post-Task Checklist step 3 (L1019–1023), pm-dispatch SKILL.md, contract-review.md, review-checklist.md, lanes/skills.md.

Delta review of triage's FAIL 6606409511 on fd3cf40c (two commits since, 7c65d0da the fix and f77be064 a pure rename of the changeset file). The reviewer is an isolated agent at CONTRACT_REVIEW_TIER, read-only on GitHub, fed the sources above; every figure below is this review's own reading of the head tree, the dev's delta notes taken as input and not as conclusions. Only the two findings and what the delta touches are judged; the parts of fd3cf40c that triage passed are byte-identical on this head (recipe L162, the L171 deletion, L178–180 and L182; the row's citation lines) and are not re-opened.

① Derived judgments

  1. M1 — the release declaration. .changeset/29255-installer-client-source-skill.md exists with frontmatter '@objectstack/skills': patch (the precedent's spelling) and body lines Clause-②: no (the ② is U+2461, bytes E2 91 A1, so the line-initial recogniser matches) and Metadata-protocol: none, both line-initial. The PR's labels read via REST are documentation, size/s, tooling: skip-changeset is gone. @objectstack/skills is publishConfig.access: public and ships dist (the synced skills/** tree), so a patch is the owed level under AGENTS.md L1019–1021 (kind none ⇒ patch, never the label). check-empty-changeset.mjs --base origin/main counts it as the one declaring changeset and exits 0; Check Changeset is success on the head twice (the second run is the re-trigger after the label removal), so the gate's green no longer rests on the label. The PR body's Human Minimum item 5 now states the same, and its line "the skip-changeset label the create carried was removed by the seat" matches the labels. Resolved.
  2. The changeset prose against the code (it ships in the CHANGELOG). "shows clientSource: 'installer' beside a declared clientId + credentialRef": recipe L163–166. "a declared client for an app its publisher deploys, the installer form for one installed on deployments the publisher never sees": the schema docblock's split, connector-auth.zod.ts L329–343. "registers a client with the vendor against the redirectUri the connection's status read answers": connectors.mdx L696–698 and L718–722; plugin.ts L4121–4124. "connects with { clientId, clientSecret }": the begin-leg body keys, plugin.ts L4083–4103, which refuse any other key. "no secret for a public client": installer-client.ts L30–31, plugin.ts L4097–4103. "a reconnect naming no client keeps the stored one": plugin.ts L4069–4071 (offered === undefined → keptInstallerClient, which returns the kept client whole, secret included, via parseKeptConnectionClient), connectors.mdx L701–704. "reads back client: { source: 'installer', clientId, hasSecret }, never the secret": plugin.ts L4015–4020 and installer-client.ts L17–19. Every clause holds; nothing is claimed that the product page does not state. Right.
  3. S1 — the reconnect clause. Recipe L181 now reads "(no secret for a public client; a reconnect naming no client keeps it)". The runtime: a begin naming no client reuses the kept client (plugin.ts L4069–4071); a begin naming any client, { clientId } alone included, replaces the kept one whole (L4090–4103). "naming no client" names the branch exactly, so the misreading triage flagged ("omit the secret and the kept secret stays") no longer has a foothold: the clause now states the one case in which anything is kept. "it" is the client the sentence just named, the same referent the next sentence's "The connection keeps it encrypted" uses, and the kept client carries its secret, so "keeps it" is the whole-client reuse connectors.mdx L701–704 describes ("a connect that names no client reuses the one the organization's connection keeps"). The changeset spells the same fact as "keeps the stored one". Resolved; matches runtime and the product page.
  4. The cut code comment. L166 went from "// Or each deployment's own client: clientSource: 'installer' in place of clientId + credentialRef." to "// Or clientSource: 'installer' in place of clientId + credentialRef." (−34 bytes). The cut fact, that under 'installer' each deployment brings its own client, has its home two paragraphs down at L178–180: "clientSource: 'installer' for one installed on deployments the publisher never sees: the administrator registers a client with the vendor against the redirectUri …". The comment line still names the key, its value and what it displaces, which is what a reader of the block needs; the when-to-use sentence is where the lane's "who reads this line" test places the rationale. Nothing is lost. Right.
  5. Ratchet row and arithmetic. Measured: head file 10377 bytes, ceil(10377/4) = 2595, the row is 2595, headroom 0, pinned AT the measurement with no slack; the hand-audit line ceil($(wc -c < …) / 4) == ceil(10377 / 4) reproduces. The row comment's figures: 9926 → 10377 is +451; the two cuts triage passed are 28 + 72 = 100 bytes; the additions (the 70-byte comment line and the 481 bytes of L178–182) are 551; 551 − 100 = 451; ceiling 2488 → 2595 is +107; the 23-byte shrink under the old pin (9949 − 9926) and 6 tokens of headroom (2488 − 2482) still hold. The script's own run and self-test both exit 0. Against the merge-base, git diff -U0 on the script shows exactly one ['…', N] row changed (2488 → 2595); the delta's other changed lines in the script are the row's comment, re-flowed to say what paid for the rewording, which is commentary in an unmeasured file, not a re-wrap of ratcheted text. On the recipe, removing the touched lines (merge-base L162 and L171; head L162, L166, L178–182) leaves 177 lines on each side, byte-identical: no untouched line was re-wrapped. The surface widening 6583724593 covers this one row and no other CEILINGS row moved. Right.
  6. Commits and PR shape. Two commits since fd3cf40c: 7c65d0da (the changeset, the two recipe lines, the row 2601 → 2595) and f77be064 (a 100%-similarity rename of the changeset file to the seat's name, 0 content lines). Both carry Claude-Session: + Co-authored-by: Claude and no model identifier (check-commit-card-trailers exit 0 on both ranges). PR: draft, base main, author objectstack-fleet[bot], mergeable: true, mergeable_state: clean at read time, 4 commits, 3 files, +39 −3, no reviews. The PR body's "Verification" says "29 success, 13 skipped" for the head; at this read it is 31 / 15, the four extra rows being the re-triggered Auto Label, Check PR Size, Check Changeset and PR-body guards after the label removal, all success. A snapshot difference, not a finding. Right.
  7. Gates. The 61 derived commands match the PR body's count. Of those re-run here, every one that could run in this container exits 0 (or 3 by design for the governed predicate); the six that cannot are PREREQUISITE NOT MET for want of node_modules, and their CI hosts are success on the head (see Local-runs). Right.

② Semver level

'@objectstack/skills': patch, Clause-②: no, Metadata-protocol: none, in the changeset body and the PR body alike. Right: a published package's shipped prose changes (so not skip-changeset), no spec key, value or meaning changes, no narrowing. Matches the M1 remedy triage named and the precedent .changeset/29482-formula-skill-flow-null-guards.md (#29864), which the release on main has since consumed, which is the path this changeset will take. Check Changeset success on the head without the label.

③ Boundary flags

④ Design judgment

  • .changeset/29255-installer-client-source-skill.md: the right package, the right level, both declaration lines, and a body that says in CHANGELOG prose exactly what the recipe now teaches and what the code does (①.2). Its "keeps the stored one" and the recipe's "keeps it" are the same fact in two registers. Holds; M1 closed.
  • skills/objectstack-automation/references/integration-recipes.md: L181 now names the client as the thing a reconnect may or may not bring, which is the only way the kept/replaced split can be read correctly next to "no secret for a public client"; it tracks plugin.ts L4069–4071 and L4090–4103 and connectors.mdx L701–704. L166 drops a rationale the when-to-use sentence already carries and keeps the key, value and displacement the block's reader needs; the bytes were found inside the new text rather than by widening the row further, which is the lane's "pay line by line" rule applied. Holds; S1 closed.
  • scripts/check-skills-token-ratchet.mjs: the row follows the measurement down (2601 → 2595), stays pinned with zero slack, and the comment records why the figures moved. Only this row moved. Holds.

No must-fix. No should-fix.

Check-runs at record time: 46 on f77be064; 31 success, 15 skipped, 0 failure, 0 pending or in progress. Success includes Lint & Repo Gates, TypeScript Type Check, all Lint · and Type Check · jobs, Build Core, Test Core and its three shards, Test UI, Live E2E UI, Dogfood Regression Gate, Governed Surface Queue Guard, PR-body guards ×2, Check Changeset ×2, Check PR Size, Auto Label, filter. Skipped by path filter, opt-in or if:: the UI build/lint/type-check/E2E lanes, Build Docs, Dogfood Verify CLI, the Dogfood and Test UI matrix placeholders, Temporal Conformance, Schedule gate, 18.x upgrade harness, Packed-tarball smoke, and the second-trigger duplicates of Auto Label and Check PR Size. No red to report.

Implemented-by: claude/project-thread-0cd35o
Reviewed-by: session_01J8VVAnMUWA9rufXzFaEh4J

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

维护者速读

  • 改了什么: 自动化技能 integration-recipes.md 配方 6:在声明式 clientId + credentialRef 旁教 clientSource: 'installer',一句话说明何时用哪种;管理员按状态读返回的 redirectUri 向厂商注册,用 { clientId, clientSecret } 连接。附 '@objectstack/skills': patch changeset。
  • 为什么改: 安装方自带 OAuth 客户端已在产品里落地,技能还没教。(skills(automation): teach clientSource: 'installer' in integration-recipes.md once the server slice (#28866) lands #29255)
  • 风险与回滚: 只改技能文本(及其 changeset)和一行 token 棘轮;棘轮按裁定 6513306068 先削重复、余额按实测提高(2488 → 2595,headroom 0),无 re-wrap。可整 PR revert。
  • 先看: integration-recipes.md L166 与 L178–182。
  • 两分钟验证: 对照 connectors.mdx L696–722 读 L178–182。
  • 需要你做的: skills/** 是受治理 Tier H 面,需 os-zhuang 或 hotlong 批准。契约复核:分诊全量 6606409511(FAIL,两项)→ 本席 delta 复审 6618915193(PASS),Head-sha f77be0641c23c0ed6570396b5299301f2be76b20。批准后本席落地。
  • 席位意见: ACCEPT。

席位核对 — ACCEPT · domain:skills#1 · head f77be0641c23c0ed6570396b5299301f2be76b20

  1. 形态: draft → main,Fixes #29255;作者 objectstack-fleet[bot];文件在认领面内(配方 + 棘轮一行,面扩展见 6583724593),附 @objectstack/skills patch changeset(⛔ 不挂 skip-changeset)。
  2. 前提实测: 复核记录逐条对过代码(plugin.ts 重连语义、installer-client.ts、connector-auth.zod.ts);本席核对复核结论与 PR 正文一致。
  3. 门禁(钉 head f77be064): check-runs skipped 15 / success 31,无失败;mergeable clean。派生门禁见 PR 正文与复审记录。
  4. 接受的偏差: 开发在 Opus 上进行,依维护者原话;全量复核由分诊代审,分诊按 pm-dispatch(contract-review): triage takes no contract reviews — every review is the dispatching seats, and a tier-unavailable or off-duty head waits for its lane or the review seats (#29242), not triage #29667 停审后 delta 由本席复审层复审。
  5. 范围外去向: recipe 6 transport.env 已有卡 skills(objectstack-automation): integration-recipes recipe 6 still says a stdio MCP server's credentials ride transport.env; a static credentialRef now reaches stdio through transport.credentialEnv (#29434) #29625。
  6. 落地条款: Tier H。保持 draft,挂 needs-user-decision,请 os-zhuang、hotlong 审批;获批后本席或接手席过落地前检、清标、ready、auto-merge;维护者直合亦可。

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review November 4, 2026 00:18
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit bc9eaf6 Nov 4, 2026
52 checks passed
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(automation): teach clientSource: 'installer' in integration-recipes.md once the server slice (#28866) lands

3 participants