Skip to content

docs(skills,lint): the connector auth union declares oauth2 and app-credential, held degraded until a server runs the grant - #28290

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-sx0mjq
Oct 31, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-sx0mjq

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

domain:skills#2 · os-elon-musk · session_016WV4cwLJsQpaepqfmrTGLL

Fixes #28226

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:自动化 skill 的 "Not yet" OAuth 条目原说 auth 联合类型没有 oauth2,PR feat(spec)!: oauth2 and app-credential connector instance auth; the runtime oauth2 variant retired (ADR-0143 S0) #28213 合入后这句已错。现改为:联合类型声明了 oauth2(authorization_code / client_credentials)和 app-credential(飞书 / 钉钉 / 企业微信),密钥只能写 credentialRef;但服务端还没跑授权流程,这类实例被标为降级、不调用上游,所以集成仍标 blocked。评测 1 的期望同步改;os explain flow-credential-literal 点名这三种新类型(含 signed)并说明修复提示为何不指向它们。
  • 为什么改:feat(spec)!: oauth2 and app-credential connector instance auth; the runtime oauth2 variant retired (ADR-0143 S0) #28213 的契约复审 6529303069 应修项 S1,以及该 PR 欠的 Skills-docs: 跟进。
  • 风险与回滚:只改文案和一个测试钉,规则逻辑和 fix: 提示原样。recipes 文件在 token 天花板下,新增字节全靠同文件删两处重复付清(2229→2230 / 2236),不动 ratchet 脚本。回滚即 revert。
  • 先看:skills/objectstack-automation/references/integration-recipes.md 的 "Not yet" 第一条,再看 packages/lint/src/rule-explanations.ts 新增的那句。
  • 两分钟验证:pnpm --filter @objectstack/lint exec vitest run src/lint-flow-credential-literals.test.ts 和 node scripts/check-skills-token-ratchet.mjs,预期 exit 0。
  • 需要你做的:欠一次契约复审(CONTRACT_REVIEW_TIER);落地档以登记册为准,本地读为 Tier H(skills/**),需 os-zhuang 或 hotlong 批准。

What changes

  • skills/objectstack-automation/references/integration-recipes.md, "Not yet" OAuth bullet: the union now declares oauth2 (authorization_code / client_credentials) and app-credential (feishu / dingtalk / wecom), the secret a credentialRef, but no server runs the grant yet: the instance is held degraded and calls no upstream. The advice stays: no short-lived token behind a bearer ref, blocked on the outbound-OAuth card.
  • skills/objectstack-automation/evals/integrations-declared.json, eval 1: the expectation says the same. Rubric text only; every must_contain / must_not_contain token is unchanged and still true.
  • packages/lint/src/rule-explanations.ts: os explain flow-credential-literal names oauth2 (with its grants), app-credential (with its vendors) and signed, says their secret is also only a credentialRef, and says why none is a home a literal moves into by shape. lint-flow-credential-literals.ts: the header comment no longer lists none / bearer / api-key / basic as every variant. The fix: hints are unchanged, so they still route to bearer, api-key or basic.
  • lint-flow-credential-literals.test.ts: the existing "every auth variant ... the schema accepts" pin now parses each kind, grant and vendor the explanation names against ConnectorInstanceAuthSchema, and asserts the explanation carries them.
  • Changeset: @objectstack/lint patch, since the explanation text ships in os explain.

The degraded wording was read from the code on main 91fa06df8, not from the card: grantBearingNotServedReason in packages/services/service-automation/src/plugin.ts:415 ("…the instance is not served and is never called without its credential") and lendRefusal in connector-credential-source.ts:118 (a datasource borrow refused 422). Grants and vendors come from ConnectorOAuth2GrantSchema and ConnectorAppCredentialVendorSchema in packages/spec/src/shared/connector-auth.zod.ts.

Paid for in the same file (restatement only, each with a surviving home)

integration-recipes.md, bullet raise +103 bytes, paid by:

  • Recipe 1's comment "its path is package-relative" (the intro says a spec "ships in the package").
  • Recipe 2's include comment "tool-name allowlist → the actions" (recipe 1's paragraph says include allowlists as the mcp provider's does, and recipe 2's flow comment dispatches actionId: 'search_issues').

2229 → 2230 tokens against the 2236 ceiling. No ceiling moved; SKILL.md is untouched.

Verification

  • pnpm --filter @objectstack/lint test and typecheck: exit 0.
  • node scripts/check-skills-token-ratchet.mjs: exit 0 (recipes 2230/2236).
  • Gates: dispatch-gates --commands at the committed head derives 72 families. All 72 ran in a fresh worktree after pnpm install --frozen-lockfile --ignore-scripts and a whole-tree build, and all exited 0. --ran reconciles 72 derived / 72 run / 0 NOT-MEASURED / 0 UNRUN, and the derivation re-run at the head is identical.
  • Landing tier: check-governed-merges.mjs --test reads the two skills/** paths on the register, so Tier H. The register's reading at PR time is the seat's.
  • Not measured locally: repo-wide pnpm lint, and the skill evals as a model run.

Out of scope (finding for the seat)

Human Minimum

Each item is one rule from
CONTRIBUTING.md › Human Minimum,
which links the AGENTS.md text that states it.

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; the derived lint families pass.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (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 one Chinese channel).
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_016WV4cwLJsQpaepqfmrTGLL

…redential, held degraded until a server runs the grant

The automation skill's "Not yet" OAuth bullet said the declarative `auth`
union has no `oauth2`. It now declares `oauth2` (grant `authorization_code`
or `client_credentials`) and `app-credential` (`feishu`, `dingtalk`,
`wecom`), the secret only a `credentialRef`; an instance of either is held
degraded and calls no upstream until a server runs the grant, so the
integration stays marked blocked. The bullet's raise is paid by two
same-file restatement cuts.

The integrations eval's expectation says the same. `os explain
flow-credential-literal` names the grant-bearing and signing kinds and why
its fix line never routes a literal to them; the rule's test holds every
kind it names to the schema. Fix lines and rule logic are unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4cwLJsQpaepqfmrTGLL
@objectstack-fleet objectstack-fleet Bot added the documentation Improvements or additions to documentation label Oct 31, 2026
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/lint/src/lint-flow-credential-literals.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/lint/src/lint-flow-credential-literals.ts) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 53749673ba7a0005d09e8a79544da10d5faa10bc → packageMentionDocs.

… narrow the signing gap to RSA vendors

The "Not yet" signing bullet said no auth kind signs requests. `signed`
with `aliyun-acs3-hmac-sha256` or `tencentcloud-tc3-hmac-sha256` is
served on the openapi and rest providers, so the Holds auth bullet names it
and the gap narrows to the RSA-signing vendors (Alipay, WeChat Pay). Paid by
same-file restatement cuts; the recipes stay at their 2236-token ceiling.

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

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4cwLJsQpaepqfmrTGLL

Fold at the seat's request: head 81aae6f75a9b03a490fe96964b593f1a687344b8 (after merging origin/main 53749673, which carries #28279).

The "Not yet" signing bullet was false on main. It said no auth kind signs requests, but ConnectorSigningSchemeSchema on main is ['aliyun-acs3-hmac-sha256', 'tencentcloud-tc3-hmac-sha256']. Both signers ship in packages/services/service-automation/src/request-signing/. A signed instance is refused on provider: 'mcp' at publish (packages/spec/src/integration/connector.zod.ts:1261) and held degraded on a provider that does not apply the signer. The built-in openapi and rest providers apply it (requestSignerNotAppliedReason, plugin.ts).

  • Holds, auth bullet: names signed on openapi / rest with its two schemes and keyId.
  • "Not yet": the signing bullet narrows to RSA-signing vendor (Alipay, WeChat Pay): no signed scheme signs RSA yet, so these stay blocked on the request-signing card.
  • OAuth bullet: "the secret a credentialRef" is cut. The Holds auth bullet says every variant carries a credentialRef.

Same-file restatement cuts pay for it: that clause, and recipe 4's "name the gap and" (the "Not yet" heading says to mark the gap). integration-recipes.md is now 2236 / 2236 tokens. No ceiling moved, and SKILL.md is untouched. SKILL.md:416 still lists "request signing" among the loader gaps. That stays true for RSA, so it is left alone (1 token of headroom).

Gates are re-running on this head. Results follow in the os-dev report.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract-review-claim: session_016WV4d1QkPVVzNz3FJqb2iS · head 81aae6f · 2026-10-31T03:33Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract review

Head-sha: 81aae6f75a9b03a490fe96964b593f1a687344b8
Served-tier: CONTRACT_REVIEW_TIER
Local-runs: probe — the skills ratchet family plus the lint package tests (node scripts/check-skills-token-ratchet.mjs on the head worktree and on a detached worktree at the merge-base 5374967, node scripts/pm/check-skill-line-ratchet.mjs, node scripts/pm/check-skill-id-lint.mjs, node scripts/pm/check-governed-merges.mjs --pr 28290, node scripts/check-changeset-fixed.mjs, node scripts/check-changeset-no-major.mjs, node scripts/check-empty-changeset.mjs, and pnpm --filter @objectstack/lint test after pnpm install --frozen-lockfile --ignore-scripts and a build of lint's dependency closure) was executed locally, because the one gate this diff can turn red is a per-file token count held at a headroom of 0 and 1 that no check-run prints as a number, and because the dev's gate run is pinned to the pre-fold head c885e0c, not to this one; nothing else was built or run.
Scope: skills/objectstack-automation/references/integration-recipes.md, skills/objectstack-automation/evals/integrations-declared.json (the register's two hits, Tier H) + packages/lint/src/rule-explanations.ts and packages/lint/src/lint-flow-credential-literals.ts (the cross-domain steer strings, triage 6530204271; the fix: routes and the predicate read, not reviewed), packages/lint/src/lint-flow-credential-literals.test.ts (the pin, run), .changeset/28226-credential-literal-explain-grant-kinds.md, packages/spec/src/shared/connector-auth.zod.ts (the union, the grant, vendor and scheme enums, the strict shapes and their refusals), packages/spec/src/integration/connector.zod.ts (the signed-on-mcp refusal :1254-1265), packages/services/service-automation/src/plugin.ts (grantBearingNotServedReason :415, requestSignerNotAppliedReason :430, the reconcile hold :2310-2322, the signer check :2431-2437), packages/services/service-automation/src/connector-credential-source.ts (lendRefusal :100-135), packages/services/service-automation/src/request-signing/ (the two signers and the registry), packages/connectors/connector-openapi/src/openapi-provider.ts :310 and packages/connectors/connector-rest/src/rest-provider.ts :71 (requestSignerApplied), content/docs/automation/connectors.mdx :462-468 and :543-545 (consistency), skills/objectstack-automation/SKILL.md :410-417 (the surviving home of a cut, and the loader-gap sentence), docs/adr/0143-outbound-connector-auth-is-open-tier.md (D2, D3, D4, Q4, the slices table), and the unmerged S1 branch claude/project-thread-552yu7 (plugin.ts :436-470 and :2436-2456, engine.ts providerAppliesCredentialHandle, read to judge whether the text survives S1); scripts/check-skills-token-ratchet.mjs and scripts/pm/check-skill-line-ratchet.mjs (the gates that hold the ceilings, untouched)

Inputs: the diff origin/main..pr-28290 (merge-base 5374967, which is also origin/main at review time, so the two-dot and three-dot diffs coincide: 6 files, +56 / −17; three commits on the branch: c885e0c, the merge cc2c945 of origin/main 5374967, and the fold 81aae6f; the two authored commits carry Co-authored-by and Claude-Session, no model name, no Refs); the PR body (head 81aae6f, draft, labels documentation, size/s, tests, tooling, auto_merge null, no reviews) and its comments 6538442143 (docs drift: lint-flow-credential-literals.ts yields no anchor), 6538461558 (the fold relay, the cuts list), 6538468352 (the contract-review claim naming this session and this head); card #28226 (body, triage 6530204271 and 6532381774, claim 6537985188); the dispatch order and the dev report at /mnt/project-files/skills-lane-seat2/ (the report is pinned to head c885e0c, base 91fa06d, 72 of 72 gate families exit 0); PR #28213 (#28137, ADR-0143 S0, merged 2026-10-30T19:04Z; its "S1 replaces these lines" section) and its contract review 6529303069 (should-fix S1); PR #28279 (merged as 5374967, the second signed scheme); card #26702 (S1; body, the plan 6524271601, the amended claim 6524120668 with its S1 scope: oauth2 served behind a server-only opt-in, app-credential held until S2) and its branch at 949892a; card #26710 (open, pm:dispatched, the request-signing card); ADR-0143; the register (check-governed-merges --pr 28290: skills/** ×2, Tier H, 73 lines); the head's check-runs (three polls, last at 2026-10-31T03:44:24Z).

① Derived judgments

  1. Accept set: unchanged — correct. Prose in two governed skill files, one os explain paragraph, one header comment, one test pin, one changeset. The fix: hints are untouched: every changed line of lint-flow-credential-literals.ts is inside the header docblock (the diff's +/− lines all begin with the comment marker), and the three route constants that feed hint still read bearer, api-key (header and paramName) and basic. The predicate and severity are unchanged. Clause-②: no and Metadata-protocol: none hold in the body and the changeset.
  2. Recipe "Not yet" OAuth bullet (:152-156) — true against origin/main. ConnectorOAuth2GrantSchema (:224) is authorization_code | client_credentials; ConnectorAppCredentialVendorSchema (:347) is feishu | dingtalk | wecom; both kinds are members of ConnectorInstanceAuthSchema (:500-508). Secrets only as credentialRef: each shape is a strictObject whose guidance refuses clientSecret, secret, accessToken, refreshToken, token, pkce (oauth2) and appSecret, secret, corpSecret, accessToken, token (app-credential) by name with the credentialRef prescription; credentialRef is optional on authorization_code (a public client), which the bullet does not contradict. "No server runs the grant yet: the instance is held degraded, calling no upstream": plugin.ts :2310-2322 holds any oauth2 / app-credential entry through failDegradedConnectorInstance before the credential chain and before any factory call, with grantBearingNotServedReason :415-420, whose wording is "This server does not run that resolution yet, so the instance is not served and is never called without its credential. Declare a static kind (bearer, api-key or basic) to dispatch it now."; lendRefusal :118-123 refuses a datasource borrow (422) with "This server does not run that resolution yet". "Blocked on the outbound-OAuth card": connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 is open. The advice sentence is unchanged and agrees with connectors.mdx :462-468.
  3. Holds auth bullet, the new signed clause (:32-34) — true. ConnectorSigningSchemeSchema (:391) is exactly aliyun-acs3-hmac-sha256 | tencentcloud-tc3-hmac-sha256; both strict shapes carry keyId and a required credentialRef and refuse secret, privateKey, secretKey, accessKeySecret and an authored signature. "On openapi / rest": the union's docblock says so (:466-467); connector.zod.ts :1261 refuses signed on provider: 'mcp' at publish; plugin.ts :2431-2437 degrades a signed instance on any provider that does not answer requestSignerApplied: true, and the two built-ins do (openapi-provider.ts :310, rest-provider.ts :71). "Signs each request": request-signing/index.ts binds both schemes; PR feat(spec): tencentcloud-tc3-hmac-sha256 joins the signed connector auth schemes (ADR-0143 D2.3, slice 2 of #26710) #28279 pins a fresh timestamp per attempt.
  4. "RSA-signing vendor" bullet (:157-158) — true and well narrowed. No RSA scheme is in the enum; ADR-0143 Q4 names alipay-v3 as the first member and D2.3 refuses an enum member without a shipped signer, so Alipay and WeChat Pay genuinely have no kind today; "blocked on the request-signing card" names connectors: request-signing auth kind for the openapi and rest providers (RSA2 / HMAC canonical-request signers: Alipay, WeChat Pay, Aliyun, Tencent Cloud, e签宝) — the vendor-auth half that #26702 does not cover #26710, open and titled with both vendors. The old sentence "no auth kind signs requests today" was false on main since feat(spec): signed connector instance auth, with aliyun-acs3-hmac-sha256 signing every request (ADR-0143 D2.3, slice 1 of #26710) #28273 / feat(spec): tencentcloud-tc3-hmac-sha256 joins the signed connector auth schemes (ADR-0143 D2.3, slice 2 of #26710) #28279, and the dev's out-of-scope finding was folded at the seat's request in its own commit.
  5. Does the text survive S1? Read on the unmerged branch claude/project-thread-552yu7 (3 commits, 28 files): app-credential stays held degraded with appCredentialNotServedReason (:448, "this server does not run yet"); oauth2 is served only through a provider registered with credentialHandle: true (oauth2NotServableReason :459, "The instance is not served and is never called without its credential"), and nothing under packages/connectors/ on that branch registers with it, so a built-in openapi / rest / mcp instance stays degraded, calling no upstream, until S2 drops the guard (plan 6524271601, "Then drop S1's opt-in guard for the built-ins"). The advice (mark blocked, no bearer parking) therefore holds through S1 and the lint explanation's conditional "until it runs that grant" stays true as written. The letter "no server runs the grant yet" (recipe :154, eval 1) becomes imprecise at S1 — a server then runs the oauth2 grant for an opting-in provider — and should read "no built-in provider takes the grant yet" from that merge on (should-fix 2). The card's deferred half ("When S1 serves a grant-bearing kind: rewrite the bullet as a recipe") is reachable only at S2, because a recipe is a declaration through a built-in provider (should-fix 1).
  6. Lint explanation (rule-explanations.ts :4709-4714) — true and pinned. The grants and vendors match ①.2; "their secret only as a credentialRef" matches the strict shapes; "held degraded and calls no upstream" matches grantBearingNotServedReason; "signed signs each request with its key" matches ①.3; "none is a home a literal moves into by shape" is the reason the routes do not widen, and it is right: an oauth2 / app-credential instance names a client or app secret the server exchanges, and a signed instance names a signing key, neither being the header or query value the rule found. The test (:521-539) parses both grants, the three vendors and the aliyun scheme against ConnectorInstanceAuthSchema and asserts the four facts in the joined paragraphs, so a kind the schema drops or a sentence that drifts goes red. Run: 181 files, 7679 tests pass (the first run without building lint's dependency closure fails to resolve @objectstack/spec entries — a local artefact of --ignore-scripts, not a finding).
  7. Eval 1 — rubric only, consistent with the recipe. must_contain and must_not_contain are byte-identical; blocked and credentialRef still occur in expected_output; "grant: 'authorization_code', the client secret only a credentialRef" is the DocuSign shape on main; the second gap sentence (Connect signs its own header, the api door does not verify it, poll) is unchanged and still what recipe 4 :125-129 teaches. The eval is measured (1240 → 1281 tokens), not ratcheted.
  8. The cuts — restatement, every prescription survives. Read on the head:
    • Recipe 1 "its path is package-relative": the example path ./src/connectors/stripe.trimmed.json (:44) is itself package-relative and the intro :9-10 says a spec "ships in the package". Kept.
    • Recipe 2 "tool-name allowlist → the actions": :70-72 "providerConfig.include allowlists operation keys as the mcp provider's does", and :86 dispatches actionId: 'search_issues'. Kept.
    • OAuth bullet "the secret a credentialRef": Holds :30 "auth, each variant with a credentialRef". Kept.
    • Recipe 4 "name the gap and": SKILL.md :411-417 says a callback whose signature is outside the api door's HMAC is platform work "filed as a card" and a loader gap is "named against its platform card"; the "Not yet" heading :150 says to mark the integration blocked. Kept, so eval 1's "Two gaps are named plainly" is still backed.
      No rule is lost.
  9. Ratchets and lint hold on the head. Token ratchet: integration-recipes.md 2229 → 2236 of 2236 (headroom 0), SKILL.md 6456 of 6457 untouched, both ceilings unchanged, scripts/ has no diff; the merge-base worktree reads 2229 and 6456, so the fold relay's numbers are exact. check-skill-line-ratchet exit 0; check-skill-id-lint 105 files clean; check-governed-merges --pr 28290 reads skills/** ×2, Tier H, 73 lines.
  10. Consistency elsewhere. grep on the head over skills/**, content/docs/** and docs/adr/** for a sentence saying the union has no oauth2, that oauth2 is absent, or that no kind signs: the only hits are ADR-0143's own Context (the pre-ADR state it records) and ADR-0018's historical checklist. connectors.mdx :462-468 says what the recipe says (degraded, 422, static kind to dispatch now, no bearer emulation); :543-545 "four static variants" describes the runtime authentication config, which is still four kinds. SKILL.md :416 "(YAML, Swagger 2.0, $ref, OAuth, request signing) is a gap" stays true: the openapi loader maps no oauth2 securitySchemes until S2 and no RSA signer exists. No out-of-scope hit.

② Semver level

@objectstack/lint patch is right: the package publishes (no private flag), and the paragraph ships in os explain flow-credential-literal; no accept set moves (the hints, predicate and severity are unchanged). check-changeset-fixed, check-changeset-no-major and check-empty-changeset exit 0 on the head; Check Changeset is success. skills/** and the eval are shipped by no package. Clause-②: no / Metadata-protocol: none agree across the body and the changeset.

③ Boundary flags

  • Dev deviations: (1) hints unchanged, kinds named in the explanation — confirmed (①.1, ①.6); (2) signed named so the list is complete — true on main (①.3); (3) the existing pin extended and a patch changeset — right (①.6, ②). No open_questions. The report's out-of-scope finding (the signing bullet) was folded at the seat's request and is judged here (①.4).
  • Gate evidence: the dev report at /mnt/project-files is pinned to c885e0c (base 91fa06d); its 72 families predate the merge and the fold, and relay 6538461558 says the re-run's results follow. The head's own check-runs are the evidence instead: at 2026-10-31T03:44:24Z (third poll), 46 runs, 26 success, 10 skipped by path or design, 10 in progress, 0 failure. Success includes Lint & Repo Gates with every Lint · sub-job, Check Changeset, Governed Surface Queue Guard, PR-body guards, Check PR Size, Flag docs affected by code changes, Build Core, Build & E2E UI, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, Live E2E UI, Test UI, Build UI Deps, Auto Label, Plan Test Core shards, filter. In progress: Test Core (1/8) to (8/8), Type Check · workspace, Type Check UI; the TypeScript Type Check aggregate had not reported. The landing seat re-reads both required jobs on this head before the ready flip.
  • Merge instead of rebase: cc2c945 merges origin/main 5374967 with no conflict, and 5374967 is the merge-base, so the diff is the six files and nothing else.
  • Independence: the diff was produced by session_016WV4cwLJsQpaepqfmrTGLL on claude/project-thread-sx0mjq; this record is rendered by session_016WV4d1QkPVVzNz3FJqb2iS, which did not draft it. Claim 6538468352 names this session and this head; no competing claim, hold or hand-off; no reviews on the PR.
  • Author: objectstack-fleet[bot]; no non-bot login to record.
  • Tier: H by the register (skills/** ×2); the maintainer or a GOVERNED_APPROVERS review lands it. Draft; auto_merge null; nothing to disarm.
  • Closing keyword: the body carries Fixes #28226, as the dispatch order asked, while the card body keeps a deferred half ("When S1 serves a grant-bearing kind: rewrite the bullet as a recipe, update the eval, widen the lint steer strings"). The merge closes the card with that half unfiled unless the seat files it (should-fix 1).
  • Docs drift: lint-flow-credential-literals.ts yields no anchor, so the explanation's prose was re-read by hand against connectors.mdx (①.10).
  • Not re-run here: the dev's 72 families; the service-automation and spec suites (the cited code read, not executed).

④ Design judgment

Rules face, the two skill files, against the code they cite and the scenario they are accepted against (eval 1: an AI author wiring DocuSign, OAuth-protected, with a vendor-signed webhook), plus the two lint files under the cross-domain exception:

  • "Not yet" OAuth bullet — holds. It now tells the author the true shape (the kinds exist, with their grants and vendors, secrets by reference) and the true consequence of declaring one today (a degraded instance that calls nothing), so the standing advice (mark blocked, no bearer parking) is reasoned rather than asserted. Listing the three app-credential vendors under an "OAuth-protected vendor" header is a small stretch, but they are the grant-bearing family the same hold covers, and the bullet is the only place the skill names them.
  • Holds signed clause — holds. Scheme names, keyId and the two providers are exactly what an author needs to declare an Aliyun or Tencent Cloud instance; an mcp author meets a located refusal with a prescription.
  • RSA bullet — holds. Narrow and true; it names the vendors that still have no kind and the card they wait on.
  • Eval 1 — holds. The rubric expects the new reasoning and the same tokens, so grading by tokens is unmoved.
  • Lint explanation and header comment — hold. The kinds belong in the explanation, not in the hints: a hint is a one-line route by shape, and none of the three kinds is a shape a found literal has. Pinning the explanation to the schema in the same test that already pins the routed variants is the right guard against the next kind drifting. The header comment now says why no hint routes to them.
  • The fold. Right call: the signing bullet was false on main in the same section this PR edits, and a second Tier H round on two adjacent bullets would have cost an approver read for nothing; the cuts that paid for it are restatement (①.8).
  • Cited code was read to judge the prose, not reviewed.

Implemented-by: claude/project-thread-sx0mjq
Reviewed-by: session_016WV4d1QkPVVzNz3FJqb2iS

VERDICT: PASS

Must-fix: none.

Should-fix:

  1. (carrier: the seat at landing, no code) Fixes #28226 closes a card whose deferred half is unfiled. Before the ready flip, file that half as its own card and cite it in the ACCEPT — gated on S2 (the providers slice), not S1: S1 serves oauth2 only behind a server-only opt-in that no built-in provider takes, and app-credential stays held until S2, so a recipe through openapi / rest / mcp cannot be written before S2. Or switch the body to Part of #28226 and leave the card open.
  2. (carrier: the S1 PR on connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702, its Skills-docs: line, or the card from should-fix 1) When S1 merges, recipe :154 and eval 1's clause "no server runs the grant yet" should read "no built-in provider takes the grant yet" (or the equivalent); the advice around it and the lint explanation's "until it runs that grant" need nothing.
  3. (carrier: the seat's ACCEPT, no code) Pin the gate evidence to this head's check-runs, not to the report file, which names c885e0c; re-read Lint & Repo Gates and TypeScript Type Check on this head before the ready flip.
  4. (carrier: the next recipe editor, no card) integration-recipes.md ends at 0 tokens of headroom and SKILL.md at 1; the next raise in either file needs a same-file cut first.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

维护者速读

  • 改了什么:automation skill 的 integration-recipes.md 和 eval 1,现在讲的是 PR feat(spec)!: oauth2 and app-credential connector instance auth; the runtime oauth2 variant retired (ADR-0143 S0) #28213 之后的事实:

    • 声明式 auth 联合类型已经有 oauth2(authorization_code / client_credentials)和 app-credential(feishu / dingtalk / wecom),密钥只能写成 credentialRef。服务端还没跑这些授权,这类实例会停在 held degraded,从不调用上游,所以集成仍要标记为 blocked。
    • 签名鉴权已经上线:signed 支持 aliyun-acs3-hmac-sha256 和 tencentcloud-tc3-hmac-sha256,可用于 openapi 和 rest。用 RSA 签名的厂商(支付宝、微信支付)仍然 blocked。
    • @objectstack/lint 的 os explain 说明文字里列出了这些新类型,加了 patch changeset;fix: 提示没改。

    共 6 个文件。

  • 为什么改:PR feat(spec)!: oauth2 and app-credential connector instance auth; the runtime oauth2 variant retired (ADR-0143 S0) #28213 和 feat(spec): tencentcloud-tc3-hmac-sha256 joins the signed connector auth schemes (ADR-0143 D2.3, slice 2 of #26710) #28279 合并后,skill 还说「联合类型里没有 oauth2」「没有任何类型会签名请求」,按这个写的作者会漏掉已经有的能力。

  • 风险与回滚:只改文本和说明文字,不碰规则逻辑。recipes 的 token 是 2236/2236,正好在上限内,新内容是用同文件的重复表述删减换来的。回滚就是 revert。

  • 先看:integration-recipes.md 的 Holds 鉴权要点和 "Not yet" 两条。

  • 两分钟验证:pnpm --filter @objectstack/lint test(181 个文件,7679 例)和 node scripts/check-skills-token-ratchet.mjs。

  • 需要你做的:登记册判为 Tier H(skills/**),需要 os-zhuang 或 hotlong 批准。契约复核 PASS,记录就在本评论前面,Head-sha: 81aae6f75a9b03a490fe96964b593f1a687344b8。批准后由批准人或本席转 ready、入队。

席位意见:ACCEPT。契约复核 PASS,没有必改项,逐句对过代码:

  • 授权类型和厂商的枚举、只能用 credentialRef 的严格形状、未服务实例在调用工厂之前就停在 held degraded(grantBearingNotServedReason);
  • 两种签名方案以及 openapi、rest provider 的应用点;mcp 在发布时就拒绝;
  • 目前确实没有 RSA 签名方案。

第二条(签名)原本在本卡范围外,是卡线程发现的错句。同文件、紧挨着,本席让它并进来,一轮审批覆盖两处。卡片里「S1 服务后改写成菜谱」那一半,复核核实要等内置 provider 真正接收授权(S2)才可能,已另立 #28299 跟踪,所以本 PR 用 Fixes #28226 关掉现在这一半。

席位核对

@os-zhuang
os-zhuang marked this pull request as ready for review October 31, 2026 03:49
@os-zhuang
os-zhuang enabled auto-merge October 31, 2026 03:49
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 31, 2026
Merged via the queue into main with commit 57f8ca2 Oct 31, 2026
54 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-sx0mjq branch October 31, 2026 04:14
os-elon-musk pushed a commit that referenced this pull request Oct 31, 2026
…ypes text, and the two skills changesets PR #28170 and PR #28290 missed

A `skills/**` change ships in `@objectstack/skills`, so it owes a patch
changeset, never `skip-changeset` (contract review 6539232473, must-fix 1).
PR #28170 and PR #28290 landed skill text under the same mistaken reading;
their entries are carried here.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4d156vwPo83g9GQuJSt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

3 participants