Skip to content

docs(adr-0143): note that the installer-client server slice landed (PR #29097) - #29483

Merged
os-zhuang merged 2 commits into
mainfrom
claude/project-thread-i5savo
Nov 2, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/project-thread-i5savo

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #29256

Clause-②: no
Metadata-protocol: none

domain:server#2 · os-steve · session_01ADHkmPosotet8HaKtCv2id

维护者速读

What changes

Tests

Docs only: no test, no ablation (os-dev: docs are not ablated). The note's six new anchors are checked by check:adr-symbol-anchors.

Acceptance notes

Verification

Head 0a3e4078 (the note commit 794155db plus a merge of origin/main 8ca9dd7b, a scripts/pm change). The derived gate list is identical on both heads, and all 21 were re-run on 0a3e4078.

Symbol anchors: main vs this head
  • origin/main aca58cdb: 2977 anchors across 148 records resolve — 702 symbol (675 declaration, 27 literal), 2228 file-level.
  • 0a3e4078: 2983 anchors across 148 records resolve — 706 symbol (679 declaration, 27 literal), 2230 file-level — the four new symbol anchors (installerClientOfBegin, parseKeptConnectionClient, endpointOf, ConnectorConnectionState) and the two test-file anchors all resolve.
Derived gates (dispatch-gates --commands, 21 commands)

All 21 exit 0 on 794155db and again on 0a3e4078: check-adr-links (+ --self-test), check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, plan-test-core-shards --self-test, @objectstack/lint check:doc-formula-expressions (after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under os-verify-lock.sh, VERDICT command-exit 0), check:adr-anchors, check:adr-index, check:adr-symbol-anchors, check:ci-filter-parity, check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal.

dispatch-gates --ran: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN.


Generated by Claude Code

…#29097)

Append-only amendment note at D2's "Slices" bullet: the connect door takes
the installer's client, the grant handle uses it for authorize, exchange
and refresh, the connection state reads client { source, clientId,
hasSecret } and never the secret, and an installer instance is no longer
held degraded for a missing clientId. The original sentence is unchanged.

Claude-Session: https://claude.ai/code/session_01ADHkmPosotet8HaKtCv2id
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 2, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Nov 2, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 0a3e40783722a57e4fe76d091e6082cec3c39507
Local-runs: none
Scope: docs/adr/0143-outbound-connector-auth-is-open-tier.md + packages/runtime/src/domains/automation.ts, packages/runtime/src/route-ledger.ts, packages/services/service-automation/src/plugin.ts, packages/services/service-automation/src/oauth2-grant/grant-handle.ts, packages/services/service-automation/src/oauth2-grant/installer-client.ts, packages/services/service-automation/src/oauth2-grant/mcp-authorization.ts, packages/services/service-automation/src/connector-connections.ts, packages/services/service-automation/src/sys-connector-connection.object.ts, packages/spec/src/contracts/automation-service.ts, packages/spec/src/shared/connector-auth.zod.ts, ui/packages/app-shell/src/views/setup/connectorConnections.ts, packages/services/service-automation/src/connector-connection-door.test.ts, packages/qa/dogfood/test/connector-installer-oauth-client.dogfood.test.ts (all read on origin/main at 6af3d2957; the cited code is read, not reviewed)

Face: rules (docs/adr/**, governed Tier H). Inputs: card #29256 (body + 4 comments, rulings 6566728470 and 6580268872 read on their own cards), PR #29483 (body, file list, net diff origin/main...0a3e4078), the head's check-runs. The head is 794155db + a merge of origin/main; origin/main has since moved to 6af3d2957, and the three-dot diff against it is still the same +28/−0 on one file.

① Derived judgments

The diff publishes nothing: one file under docs/adr/, no package, no schema, no route, no changeset. Each claim of the note was read against the code on origin/main:

  • Append-only, original text untouched — right. git diff origin/main...0a3e4078: 1 file, 28 insertions, 0 deletions, one hunk at @@ -250,6 +250,34 @@. The Status line (line 3), the Amends header (line 14) and the "Until the server slice lands …" sentence (lines 252–255) are context, not changed.
  • "the server slice landed (PR feat(automation): an oauth2 connector with clientSource: 'installer' connects with the administrator's OAuth client #29097) … merged on 2026-11-02 as ec0316ea44" — right. PR feat(automation): an oauth2 connector with clientSource: 'installer' connects with the administrator's OAuth client #29097 merged: true, merge_commit_sha ec0316ea44c97855fa1bc519fbf098a22fba5c74, merged 2026-11-02T15:29:22Z, and ec0316ea44 is an ancestor of origin/main. Card automation: a sys_connector_connection stores and uses the installer-supplied OAuth client for an authorization_code instance (#28702 B, server slice) #28866 is closed.
  • "The key names are the maintainer's ruling of record 6580268872, letter A" — right. That comment on automation: a sys_connector_connection stores and uses the installer-supplied OAuth client for an authorization_code instance (#28702 B, server slice) #28866 binds client { clientId, clientSecret } on the request and client { source, clientId, hasSecret } on the state, "the secret is never read back".
  • The connect door, closed body { clientId, clientSecret? }, 400 refusals — right. packages/runtime/src/domains/automation.ts#CONNECTOR_CONNECTION_BEGIN_BODY_KEYS is ['clientId', 'clientSecret']; connectorConnectionBeginClientOf answers an unknown key (and a clientSecret without clientId) as 400 with code: 'VALIDATION_ERROR', and respondToConnectorConnectionDoor reads a body on POST only, handing it to the service as client. The service's plugin.ts#installerClientOfBegin refuses a clientSource: 'installer' instance begun without a client, and a client offered to an instance that declares its own or leaves it to MCP registration, both credentialDoorRefusal(…, 'VALIDATION_ERROR', 400); it closes the key set again and judges the values. refuseClientOffLeg refuses a client on the read and revoke legs. The route is POST /automation/connectors/:name/connection in route-ledger.ts, served under the /api/v1 base.
  • Authorize, exchange, refresh use the installer's client — right. Begin: buildAuthorizationUrl({ clientId: client?.clientId ?? installerClient?.clientId ?? auth.clientId }), where on MCP discovery client.clientId is the installer's (passed as declared.clientId, registered: false). Complete: requestOAuth2Token({ client: { clientId: client?.clientId ?? installerClient?.clientId …, clientSecret } }) with clientSecret = installerClient?.clientSecret. Refresh: grant-handle.ts#endpointOf reads the kept client through parseKeptConnectionClient and sends it.
  • Kept, encrypted through the secret channel, read back by parseKeptConnectionClient — right. sys-connector-connection.object.ts declares registered_client: Field.secret(…); connect() writes serializeInstallerClient(installerClient, client) into it; resolveRegisteredClient → resolveSecret → installer-client.ts#parseKeptConnectionClient. D3 on main already says "their secrets encrypted at rest through the secret channel (ADR-0100)".
  • A kept client of the wrong kind is a reconnect, never used — right. endpointOf: if (!kept || kept.installer !== (config.clientSource === 'installer')) return undefined, and refreshOnce turns undefined into grantRefused(current, reconnectRequiredReason(…, 'no_client')), which marks the row reconnect_required before refusing. The exchange leg has the matching check on the pending authorization (takesInstallerClient(auth) !== (installerClient !== undefined) → 400, code unused).
  • State client { source: 'installer', clientId, hasSecret }, never the secret — right. automation-service.ts#ConnectorConnectionState.client is exactly that shape; plugin.ts#describeConnection fills it from the plain client_id / client_has_secret columns only.
  • No longer held degraded for a missing clientId; MCP over http discovers endpoints and registers no client — right. plugin.ts#oauth2NotServableReason lists clientId as missing only when auth.clientId === undefined && !takesInstallerClient(auth); mcpDiscoveryServerUrl counts the installer's client as supplied, and mcpAuthorizationClient passes it as declared.clientId, which mcp-authorization.ts takes "as is" (registered: false, no RFC 7591 call).
  • "The schema description no longer says the key is not served" — right. connector-auth.zod.ts#ConnectorInstanceOAuth2AuthorizationCodeAuthSchema's clientSource description reads "The connection keeps the client encrypted, and every authorization, code exchange and refresh of that connection uses it (ADR-0143 D2.1)"; no "not served" / PLANNED wording, and connector-auth-grant-kinds.test.ts pins that.
  • "The ui slice is console: the connector connection form asks the administrator for the OAuth client (client id + secret) when the instance takes an installer-supplied client (#28702 B, ui slice) #28869, still open … the Console begins a connect with no client" — right. console: the connector connection form asks the administrator for the OAuth client (client id + secret) when the instance takes an installer-supplied client (#28702 B, ui slice) #28869 is open with no linked PR; ui/packages/app-shell/src/views/setup/connectorConnections.ts#beginConnection is POST with no body (its own doc line says so), so an installer instance gets installerClientOfBegin's refusal, which names the vendor registration step and the redirect URI. PR feat(automation): an oauth2 connector with clientSource: 'installer' connects with the administrator's OAuth client #29097's body says the same.
  • The pins exist and hold the scenarios — right. connector-connection-door.test.ts has the describe("ADR-0143 D2.1 — an instance that takes the installer's OAuth client") block (connect/refresh/revoke as the client, 400 without one, 400 on a malformed or misplaced client, read/revoke refuse a client, changed declaration uses no code, secret in no output); connector-installer-oauth-client.dogfood.test.ts pins "never for a missing clientId", the two 400s and the connected read naming the id, never the secret.

Nothing overstated. Two wording notes, neither a misstatement of behaviour (see ④).

② Semver level

skip-changeset label, Clause-②: no, Metadata-protocol: none on the PR body: correct. docs/adr/** publishes nothing; no packages/** path in the diff. Check Changeset: success.

③ Boundary flags

Author objectstack-fleet[bot] (relay of os-steve); no non-fleet login to name. open_questions: [] in dev report 6581966146. Two declared deviations, both answered: (a) no assignee / reviewer request was made through MCP — consistent with the standard order; a Tier H draft waits on a GOVERNED_APPROVERS approval, which no reviewer request grants; (b) the PR footer is the repo's session-URL form — the repo's rule wins over the harness default. No pm:prior-rulings conflict: the note records rulings 6566728470 (B) and 6580268872 (A) and takes no decision of its own. The ADR index needs no regeneration (check:adr-index is part of the green Lint · repo & tooling gates).

④ Design judgment

hits: docs/adr/0143-outbound-connector-auth-is-open-tier.md. Judged against its first consumer (a reader of D2.1 deciding whether clientSource: 'installer' is served) and the execution plan it records (rulings B and A; server slice landed, ui slice open):

No must-fix.

CI on 0a3e40783722a57e4fe76d091e6082cec3c39507 (gh api …/commits/<sha>/check-runs --paginate, read 2026-11-02T16:15Z): 43 check-runs — 19 success, 20 skipped, 0 failure, 0 cancelled, 4 still in_progress at the read (Test Core (1/8), Type Check · debt ledger, Type Check · consumer gates, Lint · PM dispatch-gates). Nothing red. The doc gates this diff answers to are complete and green: Lint · repo & tooling gates (check:adr-anchors, check:adr-index, check:doc-authoring), Lint · docs & code guards (check:adr-symbol-anchors), Check Documentation Links, Check Changeset, Governed Surface Queue Guard, PR-body guards. The four pending runs touch no docs/adr/** input; the enqueue-time check still reads them all green before this PR moves (landing-operations clause ②).

Implemented-by: claude/project-thread-i5savo
Reviewed-by: session_01ADHkmQxwoGb5fSnrFkpxmt

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt

席位核对

ACCEPT · domain:server seat 2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt · 2026-11-02T16:17Z · head 0a3e4078 · claimed by seat 2 on #29256 (claim 6581379774)

This note records what landed under two rulings: 6566728470 (letter B, the installer-supplied OAuth client) and 6580268872 (letter A, the key names). The note owes no ruling of its own. The server slice landed in PR #29097 (ec0316ea44).

  1. Shape:
    • A draft against main with Fixes #29256.
    • One file, +28/−0, docs only, with skip-changeset.
    • check-governed-merges --pr 29483: GOVERNED (docs/adr/**, landing tier H). The seat does not ready it, enqueue it or arm auto-merge until an authorized APPROVED review from GOVERNED_APPROVERS exists.
  2. Contract review: PASS at this head (6582116051).
    • Every claim in the note holds against origin/main: the closed body and its 400s, the client used on every leg, a wrong-kind kept client meaning reconnect required, a state that never carries the secret, an installer instance no longer held degraded, and console: the connector connection form asks the administrator for the OAuth client (client id + secret) when the instance takes an installer-supplied client (#28702 B, ui slice) #28869 still open.
    • The note is append-only. The original sentence, the Status line and the Amends header are untouched, and its shape matches the repo's amendment convention. The anchors resolve.
    • Two should-fix wording notes leave the behaviour stated correctly: authorize and exchange sit in the plugin's begin and complete legs, not the grant handle, and the closed key set is first enforced at the runtime door. The approver can ask for them on this PR. The seat does not cut a new head for them.
  3. Evidence: 21 of 21 derived gates exit 0, and check:adr-index reads current. CI at the review had no failures, with 4 runs still in progress. The seat re-reads them complete at enqueue.
  4. Hand-off: in this act the PR gets needs-user-decision and a review request to GOVERNED_APPROVERS (os-zhuang, hotlong). After an approval, the seat readies and enqueues it.

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review November 2, 2026 16:30
@os-zhuang
os-zhuang enabled auto-merge November 2, 2026 16:30
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 461b0d3 Nov 2, 2026
52 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-i5savo branch November 2, 2026 16:55
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt

Landing record · PR #29483

domain:server seat 2 · session_01ADHkmQxwoGb5fSnrFkpxmt · 2026-11-02T17:23Z · card #29256

Reading Probe Result
Merged PR #29483 state merged by os-zhuang (a GOVERNED_APPROVERS account) through the queue, merge commit 461b0d3f3e
On main git merge-base --is-ancestor 461b0d3f3e origin/main yes
Queue refs git ls-remote origin refs/heads/gh-readonly-queue/* matching 29483 0
Content git grep -n "29256" origin/main -- docs/adr/0143-outbound-connector-auth-is-open-tier.md present

Generated by Claude Code

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 skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants