Skip to content

feat(lint): warn on a credential-shaped literal in a connector's header or env map - #29424

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-2sk293
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-2sk293

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #29341

Clause-②: yes (widening)
Three new exports on the @objectstack/lint entry and a new advisory on the connector save door; nothing is refused or narrowed.
Metadata-protocol: none

维护者速读

  • 改了什么:连接器四个请求头/环境变量映射(providerConfig.headers、defaultHeaders、transport.headers、transport.env)里写死的疑似凭据,os validate / os build / os lint 与连接器保存都会给出警告,指向 auth.credentialRef。
  • 为什么改:执行 [Decision] connector credential follow-ups after #28596: header-value advisory, legacy auth keys at rest, whole-map withholding #28640 裁决 ①A(记录 6566912252):这些映射读取时整块隐去,但写死的密钥仍存在元数据里;作者在写的时候就该被提醒。
  • 风险与回滚:只是警告,任何保存都不会被拒;判定沿用流程规则那套启发式,误报只多一行提示。回滚即撤销本 PR。
  • 先看:packages/lint/src/lint-connector-credential-literals.ts(规则与措辞,尤其 stdio 那一句)、packages/lint/src/authoring-rules.ts 新条目、packages/lint/src/runtime-gate.ts 新增的 connector 映射行。
  • 两分钟验证:pnpm --filter @objectstack/lint exec vitest run src/lint-connector-credential-literals.test.ts,预期 16 个用例全绿。
  • 需要你做的:无,席位落地。

What changes

  • New advisory rule connector-credential-literal (packages/lint/src/lint-connector-credential-literals.ts). It asks the existing isCredentialShapedLiteral predicate (credential-literal.ts, unchanged, no second name list) over each declarative connector entry's four maps: providerConfig.headers, providerConfig.defaultHeaders, providerConfig.transport.headers, providerConfig.transport.env. One warning per credential-shaped literal, located by path (connectors[i].providerConfig.defaultHeaders["X-Api-Key"]), never echoing the value.
  • Wording. Header maps: header 'NAME' in MAP holds a credential-shaped literal, kept in metadata, not the secrets layer; move it to the connector's auth.credentialRef, with a fix line naming the bearer / api-key auth variants. The transport.env map gets a different steer, because a stdio MCP server takes no auth (see Acceptance notes): … a stdio server takes no auth; auth.credentialRef reaches it only over http.
  • Registry entry in AUTHORING_RULES: tier: 'advisory', all three commands (validate, build, lint), surfaces: CLI_AND_RUNTIME, runtimeTypes: ['connector'].
  • Save door. TYPE_TO_STACK_KEY gains connector: 'connectors', so a PUT /meta/connector/:name publish runs the rule through the existing runtime authoring gate and the findings ride the save response's advisories (the channel flow-credential-literal already uses). No new channel was built.
  • os explain connector-credential-literal entry in rule-explanations.ts: the four maps, why withholding on read does not move the value out of metadata, the auth variants, the stdio limit, why it only warns.
  • Barrel exports lintConnectorCredentialLiterals, CONNECTOR_CREDENTIAL_LITERAL, ConnectorCredentialLiteralFinding.
  • Changeset .changeset/29341-connector-credential-literal.md (@objectstack/lint patch).

Forced edits (not tests): the four CLI transcripts that print Running author-time rules (N) go 60 → 61 (content/docs/deployment/cli.mdx, deployment/validating-metadata.mdx, getting-started/build-with-claude-code.mdx, ui/react-pages.mdx), because the registry gained one entry (check:docs-transcript-drift). No existing test was edited.

Not touched: the connector redactor (connector-credential-redaction.ts), the package export path (#29342), credential-literal.ts, anything in packages/spec.

Tests

  • packages/lint/src/lint-connector-credential-literals.test.ts (16): a Bearer … literal in each of the four maps warns at its own path; a credential name alone warns; Accept: application/json, an auth.credentialRef-routed connector, a template, a blank and a non-string value draw nothing; values outside the four maps are not this rule's; malformed stacks never throw; the four maps equal the connector redactor's withheld maps, read through the public getMetadataTypeRedactor('connector'); registry entry shape; CLI commands and runtime gate report warnings only; stackKeyForType('connector') === 'connectors'; barrel; os explain names every map.
  • packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts, new block (2), through the real saveMetaItem: LIT saves of a rest, an mcp http and an mcp stdio connector each land (rows stored, literal at rest unchanged) and carry one warning advisory per map on the 2xx, with no sentinel in the response; DARK (credentialRef-routed, Accept only) carries none.
  • packages/cli/test/connector-credential-literal-doors.e2e.test.ts (2, nightly integration tier like its flow sibling): os validate --json and os lint --json exit 0 on LIT with the four warnings, and print none on DARK.

Acceptance notes

  • The stdio steer departs from the ruling's phrasing on purpose, and stays inside its letter. ①A says the warning names "the literal and the auth.credentialRef route". Measured: the MCP provider folds a resolved auth into an http transport's headers only (connector-mcp/src/mcp-provider.ts applyAuthToHeaders, "Not applied to stdio transports"), the stdio client receives transport.env as its environment, and the connector guide says "Credentials for a stdio server ride transport.env, not auth". A plain "move it to auth.credentialRef" on an env entry would point at a route the runtime does not deliver for stdio. So the env warning names auth.credentialRef with its condition (an http transport). Flagged to the seat as an open question.
  • A TypeScript config that writes env: { TOKEN: process.env.TOKEN } for a stdio server is evaluated to a literal before the rule reads it, so it warns at os validate too. That is the heuristic's accepted false-positive cost (a line of reading); nothing is refused.
  • The rule's four-map list is a mirror of the spec's CONNECTOR_CREDENTIAL_MAP_PATHS, which the spec does not export (ruling ③A keeps it off the spec export contract). The equality is pinned by test through the public redactor API instead of an import.
  • A save of the served form (maps withheld) carries the maps forward after the gate runs, so a round trip re-warns nothing; only a map the author actually sends is judged.

Verification

All readings on head 28b45f8e (this branch with origin/main merged), container-local.

Tests
  • pnpm --filter @objectstack/lint test: Test Files 190 passed (190), Tests 7846 passed (7846).
  • pnpm --filter @objectstack/metadata-protocol test: Test Files 304 passed, 4 skipped (308); Tests 22155 passed, 26 skipped.
  • pnpm --filter @objectstack/lint typecheck and pnpm --filter @objectstack/metadata-protocol typecheck: exit 0.
  • pnpm --filter @objectstack/cli exec vitest run --project unit test/explain-rule-id.test.ts: 14/14 (every os explain entry, the new one included).
  • OS_TEST_TIERS=nightly … --project integration test/connector-credential-literal-doors.e2e.test.ts test/flow-credential-literal-doors.e2e.test.ts: 2 files, 4/4.
  • pnpm --filter @objectstack/spec check:generated: all 14 generated artifacts up to date.
  • pnpm lint: exit 0.
Ablation (each leg: mutate through scripts/ablation-replace.mjs, rebuild lint, dist pre-flight, run, restore, rebuild, pre-flight --absent)
  • A1, nothing is refused. Rule severity mutated to error. Lint unit: 3 red (warning assertions; runtime gate "never errors"). Save door: LIT red with connector/vendor_api failed author-time validation: 2 issues — … [connector-credential-literal], the 422 the pin forbids. Restored: blob == HEAD, dist marker absent.
  • A2, a non-credential header draws nothing. The predicate call replaced with "any string". Lint unit: 6 red (Accept and routed connector now warn, LIT paths 8 instead of 4). Save door: LIT and DARK red. Restored.
  • A3, the save door is wired. The connector: 'connectors' row renamed. Lint unit: 2 red (stackKeyForType null, rule not run at the gate). Save door: LIT red (expected [] to deeply equal [ …(4) ]). Restored.
Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 90 families on 28b45f8e; all 90 ran, all exit 0. Five first answered exit 3 (prerequisite not met: a shallow-clone pinned commit, client-react and full package dists, and one queued behind my own build) and were re-run green after git fetch of the pinned commit and a full turbo run build --filter=./packages/**. --ran reconciliation: 90 derived, 90 run, 0 NOT-MEASURED, 0 UNRUN.

Dogfood battery: not owed (no ! in the title, no (narrowing) arm).


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01ADHkmPZY72rbsdkcLx2ZoH

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint, touching 24 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/lint/src/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/connectors.mdx (via defaultHeaders (literal, a string literal in JUDGED_MAPS), providerConfig (literal, a string literal in JUDGED_MAPS), /meta/connector/:name (route, a path literal in a comment in AUTHORING_RULES; a path literal in a comment in TYPE_TO_STACK_KEY))
  • content/docs/data-modeling/external-datasources.mdx (via providerConfig (literal, a string literal in JUDGED_MAPS))
  • content/docs/data-modeling/odata-datasources.mdx (via providerConfig (literal, a string literal in JUDGED_MAPS))
  • content/docs/deployment/validating-metadata.mdx (via AUTHORING_RULES (symbol, a top-level const object), runtimeTypes (symbol, a field of const object AUTHORING_RULES))
  • content/docs/kernel/cluster.mdx (via /meta/connector/:name (route, a path literal in a comment in AUTHORING_RULES; a path literal in a comment in TYPE_TO_STACK_KEY))

⛔ 2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via providerConfig (literal, a string literal in JUDGED_MAPS))
  • content/docs/releases/v17/17-6.mdx (via /meta/connector/:name (route, a path literal in a comment in AUTHORING_RULES; a path literal in a comment in TYPE_TO_STACK_KEY))

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

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/lint/src/index.ts) — pages documenting those are invisible to this run
  • 10 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 101 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • 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 d93acbbe552989632d22269e90841ed44860b589 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from cc1ba3d9958c3bda2134b9e043c01460c0179356 — the merge of head e7f39bdf04e24fac9e42b47335eeef2fe76e5e02 into base d93acbbe552989632d22269e90841ed44860b589, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin cc1ba3d9958c3bda2134b9e043c01460c0179356 && git checkout cc1ba3d9958c3bda2134b9e043c01460c0179356
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d93acbbe552989632d22269e90841ed44860b589 e7f39bdf04e24fac9e42b47335eeef2fe76e5e02 && git checkout -B drift-repro d93acbbe552989632d22269e90841ed44860b589 && git merge --no-ff e7f39bdf04e24fac9e42b47335eeef2fe76e5e02

node scripts/docs-audit/affected-docs.mjs --json d93acbbe552989632d22269e90841ed44860b589

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs d93acbbe552989632d22269e90841ed44860b589 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…public-surface widening

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

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67

Contract-review-claim: session_01ADHkmQJdgarUjPLNgFBY67 · head e7f39bd · 2026-11-02T14:48Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67

Contract review

Served-tier: TIER_DEFAULT
Head-sha: e7f39bdf04e24fac9e42b47335eeef2fe76e5e02
Local-runs: none

① Derived judgments

Read: card #29341 (body, triage 6577787052, claim 6578032174, dev report 6579919803, seat ruling 6579967665), the PR #29424 body, its 13-file list, and the net diff origin/main...pr29424. The head commit e7f39bdf changes only the changeset (2 lines added, 1 removed) on top of 28b45f8e, which is the head the dev measured. So the code under review is byte-identical to the measured code.

  • Three new @objectstack/lint entry exports: right. They are lintConnectorCredentialLiterals, CONNECTOR_CREDENTIAL_LITERAL (the string constant 'connector-credential-literal') and the type ConnectorCredentialLiteralFinding, all on packages/lint/src/index.ts. Each mirrors the sibling flow trio already on that entry. The finding type fixes severity: 'warning' and rule to the constant's literal type, so the published type cannot describe an error. CONNECTOR_CREDENTIAL_LITERAL_MAPS is exported from the module only. It is not on the barrel and not on the ./runtime or ./rule-explanations subpaths, so it is not public surface. All of these are additive, and nothing existing is renamed or removed.
  • Additive value changes on existing exports: right, and inside the widening. AUTHORING_RULES gains one advisory entry (tier: 'advisory', commands ALL, surfaces: CLI_AND_RUNTIME, runtimeTypes: ['connector']), so the CLI count goes from 60 to 61. RULE_EXPLANATIONS on ./rule-explanations gains the connector-credential-literal key. runtimeGatedTypes() and stackKeyForType() on ./runtime now also answer for connector.
  • New connector: 'connectors' row in TYPE_TO_STACK_KEY: right. The gate filters by runtimeTypes before it reads this table, and the new rule is the only one that declares connector. So a PUT /meta/connector/:name publish (state: 'active'; drafts stay ungated under D1) now runs exactly one rule. The row is required: the wiring guard refuses a declared type that has no mapping. The row also lands on the key the rule reads, because the rule opens with recordsOf(stack.connectors), so this is not the inert seed/seeds mismatch. Side effects:
    • connectors joins WRITTEN_STACK_KEYS.
    • RuntimeStackContext has no connectors member, so NAME_KEYED_STACK_KEYS is unchanged. A connector write is the only member of its own collection, and paths stay positional (connectors[0]...), which the protocol test pins.
    • The only consumer outside lint is metadata-diagnostics.ts itemRelativeIssuePath. It re-spells error issues only, and this rule raises none.
  • What the save door does and answers: advisories only, nothing refused. The finding type is warning-only, the registry tier is advisory (the wiring test reads the rule body for error), and runRuntimeAuthoringRules sorts severity !== 'error' into advisories. In metadata-protocol runtime-authoring-gate.ts, result.advisories goes only to advisoryFindings, never to localIssues. The answer is a 2xx with one warning advisory per credential-shaped literal, and the row is stored as written. The protocol test (LIT: three saves land and the literal at rest is unchanged; DARK: none) and the dev's ablation A1 (severity set to error, giving a 422, red) pin this.
  • Can the credential value be echoed in a finding? No.
    • message contains the map label, the entry key (the header or env NAME) and constant steer text.
    • path contains the index, the label and the key (JSON-quoted when it is not an identifier).
    • where contains the connector name. hint is a constant.
    • value is passed only to isCredentialShapedLiteral. The predicate returns false for non-strings, blanks and platform templates, so it never formats a value.
    • The gate's authoring-rule-threw fallback would echo err.message, but the rule is pure and guards every dereference (isRec, mapAt), so it does not throw on a malformed body.
    • The protocol test asserts that none of the four sentinel values appears in the serialized advisories.
    • Residual: an author who puts a secret in a header NAME would see it echoed. That is outside the heuristic's design and not a must-fix.
  • The four map paths match the redactor's withheld maps: right. JUDGED_MAPS lists providerConfig.headers, providerConfig.defaultHeaders, providerConfig.transport.headers and providerConfig.transport.env. That is the same set, in the same order, as CONNECTOR_CREDENTIAL_MAP_PATHS at packages/spec/src/integration/connector-credential-redaction.ts:132-137, identical on origin/main and on the head. The list is a mirror, not an import, because the spec does not export the constant (ruling ③A, packages: a package export marks each withheld connector header/env map, so an import knows it is incomplete (#28640 ruling 3A) #29342). The equality is pinned in lint-connector-credential-literals.test.ts through the public getMetadataTypeRedactor('connector'), so drift on either side turns that test red. The redactor withholds the maps whole on read and restores them after the gate, so a served-form round trip sends no map and nothing is re-warned. The rule does not need restoredCredentialPaths.
  • Boundary of the claim's file surface: held. The redactor, credential-literal.ts and every file under packages/spec are untouched. The barrel lines are the lint entry, not the spec export marker that packages: a package export marks each withheld connector header/env map, so an import knows it is incomplete (#28640 ruling 3A) #29342 holds.
  • The four docs transcript edits are right. Each changes Running author-time rules (60) to (61), which the registry entry forces (check:docs-transcript-drift). No existing test was edited.
  • Gate verdicts on this head (64 check-runs): 24 success, 10 skipped, 0 failure, 30 still in progress. The 30 in progress are Build Core, Test Core 1/8 to 8/8, Type Check workspace, Type Check consumer gates, Type Check UI, Test UI 1/16 to 16/16, Build & E2E UI and Live E2E UI. The successes include Check Changeset, PR-body guards, Governed Surface Queue Guard, Type Check source gates, Lint & Repo Gates, every scoped Lint family, Lint PM dispatch-gates, ESLint, Lint docs & code guards, Spec property liveness and Check PR Size. The skipped runs are opt-in or matrix-conditional (UI Published Artifacts, Temporal Conformance, the schedule gate, Packed-tarball smoke, Lint UI, Dogfood Verify CLI, the sharded Dogfood Regression matrix, the 18.x upgrade harness, plus duplicate PR Size and Auto Label rows). The non-sharded Dogfood Regression Gate passed. The in-progress families are the ones that run the new lint, protocol and CLI tests on this head. They are not yet a verdict, and they are owed green before the seat's ACCEPT.

② Semver level

Clause-②: yes (widening) — this is correct for the diff. It publishes three new names on the @objectstack/lint entry and a new advisory on the PUT /meta/connector 2xx answer. Nothing is refused, narrowed, renamed or removed. Seat ruling 6579967665 amends the claim's original no to this reading.

  • PR body: the key appears exactly once, on one line-initial line (line 5), with the value yes (widening). The reason sits on the next line and does not repeat the key. Metadata-protocol: none is on its own line (line 7).
  • Changeset .changeset/29341-connector-credential-literal.md: the key appears exactly once, on one line-initial line (line 7), with the same value. The reason line follows without the key. Metadata-protocol: none is on line 9.
  • Metadata-protocol: none is right. No authorable key or value moves, and packages/spec is untouched.
  • Level '@objectstack/lint': patch is right. It matches the seat ruling, and this is a non-protocol additive change on the lane's patch convention.
  • No other package publishes a change:
    • metadata-protocol changes only a test file.
    • cli changes only an e2e test.
    • content/docs is not a package.
    • Check Changeset is green on this head.

③ Boundary flags

  • Open question 1 (wording of the transport.env steer): answered A by seat ruling 6579967665, and I concur. On origin/main, connector-mcp/src/mcp-provider.ts:82 says auth is "Not applied to stdio transports", and content/docs/automation/connectors.mdx:232 says stdio credentials ride transport.env. A plain "move it to auth.credentialRef" (option B) would steer authors into a field that does nothing there. Dropping env (option C) would hide a real literal. The shipped text names the literal and names the auth.credentialRef route with its http condition, so it keeps ruling ①A's wording intact.
  • Deviation 1 (edits made in a worktree at ../objectstack-29341 instead of the shared container checkout): accepted. It is a process detail and has no effect on the diff.
  • Deviation 2 (no PR assignee, reviewer or subscription): accepted. os-dev forbids assignees on a dev pr_create, and the dispatch contract governs.
  • Deviation 3 (the four forced transcript edits): accepted. They are mechanical, forced by the registry count, and judged in ①.
  • Out-of-scope finding (a stdio MCP server has no secrets-layer route for its credentials; noted, not filed, carrier none): not a defect of this PR. It goes to the seat to file as its own card if wanted, for example env values resolved from a credentialRef. It does not block.
  • Nothing escalated. No security findings were reported, and I found none.

Implemented-by: claude/project-thread-2sk293
Reviewed-by: session_01ADHkmQJdgarUjPLNgFBY67

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67

席位核对 · ACCEPT · PR #29424 · 2026-11-02T14:55Z

Head-sha: e7f39bdf04e24fac9e42b47335eeef2fe76e5e02

维护者速读(席位终稿)

核对六项

  1. 形态:draft → main;Fixes #29341;13 个文件 +838/-4,都在申报面内(lint 规则与测试、运行时门的一行映射、protocol 与 CLI 测试、4 处被迫的文档计数、本卡 changeset)。spec 和凭据隐藏器未改。
  2. 前提实测:声明面契约复审(TIER_DEFAULT)在本 head 上 PASS,记录 6580241094。复审确认三点:只有警告、什么都不拒绝;值永不回显;四个表的路径与隐藏器一致,且有测试钉住。本 head 只改了 changeset 的声明行,代码与 dev 实测的 28b45f8e 逐字节相同。
  3. 门禁:dev 报告(6579919803):dispatch-gates 90 derived / 90 run / 0 NOT-MEASURED,全部 exit 0;pnpm lint 0;lint 7846/7846,metadata-protocol 22155 通过,CLI 入口 e2e 4/4。消融三处(改成拒绝、非凭据头、保存门接线)各转红,恢复后干净。dogfood 不适用(不是收窄)。28b45f8e 上的红是新推送取消了旧 head 的各条线,不是本 PR 的失败;入队前席位读本 head 全部 check-run。
  4. 接受的偏差:改动做在独立 worktree;dev 的 PR 不带 assignee;4 处文档计数从 60 改为 61,是规则注册强制的。PR 正文末尾有 relay 要求的签名 HTML 注释行。均接受。
  5. 裁定与去向:声明由席位改为放宽(6579967665)。开放问题(stdio 的 transport.env 文案)裁定 A,保留现有文案。范围外发现「stdio MCP 服务没有走密钥层的凭据路径」已立 connector-mcp: a stdio MCP server has no secrets-layer route for its credentials, so transport.env can only carry a literal (the route #29341's advisory cannot point to) #29434。
  6. 落地条款:Clause-②: yes (widening),Metadata-protocol: none,PR 正文与 changeset 都有,各只一行。semver:@objectstack/lint patch。check-governed-merges --pr 29424:NOT governed(入队前复核)。落地授权,维护者原话:「按照 pm-dispatch 规则复核过的都授权」(2026-10-25T11:35Z)。

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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

connectors: os validate and the save door warn on a credential-shaped literal in a connector header or env map (#28640 ruling 1A)

1 participant