Skip to content

feat(spec): ConnectorConnectionState declares redirectUri, the derived OAuth redirect URI - #29618

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

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

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #29574

Clause-②: yes (widening)
Metadata-protocol: none

维护者速读

What changes

ConnectorConnectionState (@objectstack/spec/contracts, packages/spec/src/contracts/automation-service.ts) declares one optional key, redirectUri?: string: the absolute URL of GET /api/v1/automation/connectors/oauth/callback that the administrator registers with the vendor's OAuth client. Its TSDoc states:

No server change, no docs change (the card leaves content/docs/automation/connectors.mdx to #29463), no api/protocol.zod.ts / identity/protocol.ts / metadata-protocol protocol.ts edit (freeze until 2026-11-03 06:00Z). The interface has no Zod wire mirror in packages/spec/src/api/, so no schema or generated reference moves.

Why

#28702 ruling B (6566728470) has each deployment's administrator register their own OAuth client against this deployment's callback, and asks the Console's Connect step (#28869) to show that exact URI with a copy button. The server derives it but answers it nowhere a client can read before a client exists. Split from #29463 on route ruling 6585200349; triage 6586696710 (p1).

Open questions

  • The key name (merge gate: the maintainer approves it before the queue). Proposed redirectUri. Reasoning, by the method the client ruling 6580268872 used (reuse the words the contract layer already uses for the concept):
    • It is the RFC 6749 redirect_uri parameter, camelCased per the config-key rule.
    • The code that derives and sends this exact value already spells it redirectUri: the plugin option connectorOAuthRedirectUri, and the request fields of services/service-automation/src/oauth2-grant/authorization.ts and mcp-authorization.ts. The vendor consoles an administrator pastes it into call it "Redirect URI".
    • Not redirectUrl: in the spec that word is the action handler-return navigation convention ({ redirectUrl, openIn? }, ui/action.zod.ts), a different concept a reader would conflate.
    • Not callbackUrl: no precedent in the spec, and it names the route rather than the OAuth term the vendor asks for.
    • Not nested as client.redirectUri: client is absent until the installer enters one, which is exactly when the URI is needed.
    • Noted: redirectUri once named an inline key of the retired ConnectorOAuth2Schema (connector.authentication, migration entry connector-auth-config-oauth2-retired). That was an authorable metadata key; this is a read-only answer field on a service contract, never authored, so nothing collides with that retirement.
    • Options: A redirectUri (recommended, for the reasons above) · B callbackUrl · C redirectUrl.

Tests

  • New packages/spec/src/contracts/connector-connection-redirect-uri.pin.test.ts, compiled by check:test-typecheck under tsconfig.test.json: the key is exactly string | undefined and optional; ConnectorConnectionRequest has no such key; every prior key of the state keeps its type; a structured value does not compile (@ts-expect-error); the TSDoc names the callback path, the derivation chain and both absence conditions.
  • Reverse check, run once: with the key mutated to number (scripts/ablation-replace.mjs), check:test-typecheck went red with "2 type error(s)" in the pin file; restored blob equals HEAD (31cf455e60bc).

Acceptance notes

  • No readonly modifier: "read-only" here means no request carries it (pinned); the interface's sibling keys carry none either.
  • Metadata-protocol: none: ConnectorConnectionState is a service answer, not something a metadata author writes. Clause-②: yes (widening): the published contract gains a key.

Verification

All readings at head 555302a1f (this branch merged with origin/main at the time of the run), in objectstack-ai/objectstack:

  • pnpm --filter @objectstack/spec build :: exit 0 (lock VERDICT command-exit 0).
  • pnpm --filter @objectstack/spec check:generated :: exit 0, "All 14 generated artifacts are up to date"; nothing regenerated, nothing committed (the interface has no Zod mirror, and the api-surface row ConnectorConnectionState (interface) names the interface, not its members).
  • pnpm --filter @objectstack/spec test :: exit 0, Test Files 802 passed (802), Tests 23700 passed, 1 todo.
  • pnpm --filter @objectstack/spec typecheck :: exit 0 (includes check:test-typecheck, which compiles the new pin).
  • node scripts/pm/dispatch-gates.mjs --commands: 79 derived families; all 79 run, each exit 0; --ran reconciliation: "79 derived famil(ies) accounted for — 79 run, 0 NOT-MEASURED". Prerequisite builds: turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/objectql, and git fetch origin 621a4876 for the teardown-shape self-test's pinned control.
  • Every family CI runs beyond that local subset (repo-wide lint, Test Core, Build Core, the type-check lanes): this PR's check-runs.
  • Dogfood: not owed (no ! in the title, no (narrowing) arm).

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (A contract interface with no Zod mirror, as its siblings.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (Repo-wide lint is CI's.)
  • 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. (check:generated: all 14 up to date, nothing moved.)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

Maintainer approval

Warren approved the key name redirectUri (on ConnectorConnectionState, option A; callbackUrl and redirectUrl were not taken) on 2026-11-03 at 00:08 UTC. He chose 「全部批准」 on decision card cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Rr7w8AxYJLZP6jP9v41T4n, whose question was 「六个命名/措辞全部按推荐批准吗?」, in the project thread "Decide pending spec name approvals". The post above that card recommended redirectUri as spelled.

@github-actions github-actions Bot added size/m 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/spec, touching 3 documentable anchor(s).

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

  • content/docs/automation/connectors.mdx (via /api/v1/automation/connectors/oauth/callback (route, a path literal in a comment in ConnectorConnectionState))
What this run could not see
  • 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 — 168 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 0bfb225e4d6b359d8481ec3f5351221c634ed35c → packageMentionDocs.

Which tree this was computed on

This run read content/docs from e63f91b5642688d387d68af28a56b5f1aeac431e — the merge of head 555302a1f39e04e55cb8e140ef312a477e2d5f19 into base 0bfb225e4d6b359d8481ec3f5351221c634ed35c, 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 e63f91b5642688d387d68af28a56b5f1aeac431e && git checkout e63f91b5642688d387d68af28a56b5f1aeac431e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0bfb225e4d6b359d8481ec3f5351221c634ed35c 555302a1f39e04e55cb8e140ef312a477e2d5f19 && git checkout -B drift-repro 0bfb225e4d6b359d8481ec3f5351221c634ed35c && git merge --no-ff 555302a1f39e04e55cb8e140ef312a477e2d5f19

node scripts/docs-audit/affected-docs.mjs --json 0bfb225e4d6b359d8481ec3f5351221c634ed35c

⚠️ 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 0bfb225e4d6b359d8481ec3f5351221c634ed35c → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

Contract-review-claim: session_01JQwxbWR3K3h7i1ytwycVg1 · head 555302a · 2026-11-02T21:59Z

The seat runs the at-tier review (a widening of packages/spec/src/contracts/automation-service.ts) once CI on this head is green.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 555302a1f39e04e55cb8e140ef312a477e2d5f19
Local-runs: none
Scope: packages/spec/src/contracts/automation-service.ts + packages/services/service-automation/src/plugin.ts (the connectorOAuthRedirectUri option and its derivation, connectionDoorSubject, describeConnection, getConnectorConnection, beginConnectorConnection), packages/services/service-automation/src/oauth2-grant/authorization.ts, packages/services/service-automation/src/oauth2-grant/mcp-authorization.ts, packages/runtime/src/domains/automation.ts (the connection door's arms and capability gate), packages/runtime/src/dispatcher-plugin.ts, packages/runtime/src/route-ledger.ts, docs/adr/0143-outbound-connector-auth-is-open-tier.md (D2.1 amendments, D5), content/docs/automation/connectors.mdx, packages/spec/package.json, packages/spec/api-surface/contracts.json, packages/spec/export-origins/contracts.json, packages/spec/src/contracts/approval-service.ts, packages/spec/src/contracts/notification-service.ts, packages/spec/src/contracts/metadata-service.ts, packages/spec/src/ui/action.zod.ts, packages/spec/src/migrations/entries/semantic/18.connector-auth-config-oauth2-retired.ts, ui/packages/app-shell/src/views/setup/connectorConnections.ts, ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx

Inputs read: card #29574 (body, triage 6586696710, Claim 6587703954, dev report 6589522107); ruling B on #28702 (6566728470) in place; route ruling 6585200349 on #29463 and that card's body; #28869's body and its blocked report 6581473243; the client key-name ruling 6580268872 on #28866; PR #29618's body, file list, both comments (docs-drift 6589539800, the seat's claim 6589546632), no review comments; the net diff against main at this head (three files, 130 added, 0 removed); the 64 check-runs on this head. Every gate-carrying context concludes success: Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core, Governed Surface Queue Guard, Type Check UI, Test UI, Build & E2E UI, Live E2E UI, plus Check Changeset, Spec property liveness and the PR-body guards; Lint UI is skipped by its paths filter, the other skips are opt-in or schedule lanes. The docs-drift check is advisory and names content/docs/automation/connectors.mdx, read below.

① Derived judgments

  • What the diff adds to the published surface. One optional member, redirectUri?: string, appended last on ConnectorConnectionState, a TypeScript interface in packages/spec/src/contracts/automation-service.ts. It has no Zod schema and no wire mirror: git grep ConnectorConnection over packages/spec/src/api, integration and shared finds nothing, so no .describe(), no generated reference page and no authorable-surface baseline moves. Right, and the dev's "no generated artifact moved" reading matches the tree: api-surface/contracts.json:71 and export-origins/contracts.json:71 record ConnectorConnectionState (interface) by name only, members unrecorded, so a member addition is invisible to check:api-surface by design; TypeScript Type Check (which runs the generated-artifact gates) is success on this head.
  • It is a published surface. packages/spec/src/contracts/index.ts:33 does export * from './automation-service.js', and package.json publishes ./contracts as a subpath export (dist/contracts/index.d.ts / .d.mts, ESM and CJS). The member ships in the .d.ts of @objectstack/spec@18.2.0's successor. Right that the PR says so.
  • Accept-set, implementer side. IAutomationService.getConnectorConnection, completeConnectorConnection and revokeConnectorConnection all return a Promise of ConnectorConnectionState (engine.ts:2626-2629, :5059-5074; plugin.ts:3990, :4087, :4142, :4288). An optional member widens the return type without obliging any implementation to set it: describeConnection (plugin.ts:3990-4010) compiles unchanged, which Build Core and TypeScript Type Check confirm. Right: a pure widening, nothing an implementer wrote stops compiling.
  • Accept-set, caller side. ConnectorConnectionRequest is untouched; the pin asserts 'redirectUri' is not a key of it. The REST door (domains/automation.ts, respondToConnectorConnectionDoor) hands the service's answer to deps.success(answer) with no response schema in between, and the Console reads the whole payload as ConnectorConnectionState (connectorConnections.ts:144), so once the server sets the key it reaches the page with no further contract change. Right: the diff declares exactly the key the two later halves (connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463 server, 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 Console) need, and nothing else.
  • No runtime change. packages/services/service-automation and packages/runtime are not in the diff; describeConnection never sets redirectUri. Today no answer carries it, which the TSDoc's last sentence states. Right, see ④.
  • The retired redirectUri of ConnectorOAuth2Schema. The semantic entry connector-auth-config-oauth2-retired names redirectUri as an inline key of the retired connector.authentication oauth2 variant; no retiredKey('redirectUri') tombstone exists anywhere in packages/spec/src. The retirement is of an authorable definition key on another surface; this is a read-only answer field on a service contract. Right that nothing collides.
  • Docs. content/docs/automation/connectors.mdx names the callback route (lines 642-650) and the derivation chain (lines 696-698: OS_BASE_URL or OS_AUTH_URL plus the path, or the plugin option) and says today the administrator takes the URI from the documentation, which the Console's own prose repeats (ConnectorConnectionsPage.tsx:495). This PR changes no behaviour, so the page is still accurate; the sentence that the status read answers the URI is connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463's to write, as that card's body says. Right that this diff owes no docs edit.

② Semver level

The changeset is '@objectstack/spec': patch with Clause-②: yes (widening) and Metadata-protocol: none, both lines also in the PR body. Judged against AGENTS.md Post-Task Checklist step 3 and scripts/check-changeset-no-major.mjs (its "THE LEVEL AXIS" block and the WHICH LEVEL prose in pr-automation.yml): the level follows the metadata protocol alone, the change to what a metadata author can write. ConnectorConnectionState is a service answer nobody authors, so the kind is none, and none takes patch; the gate's own rule is that a declared none must grade every entry it introduces patch, so minor would be refused, not merely unowed. A widening of a published contract type is still Clause-②: yes (widening), which this declares, and carries no level of its own under the ruling the gate encodes ("a non-protocol change, widening or breaking, ships patch"). Check Changeset is success on this head. Patch is right; a widening owes no minor here.

③ Boundary flags

  • The key name (merge gate, escalated, not granted). Triage 6586696710 and the Claim both bind: the maintainer approves the name before the queue, the PR body quotes that approval, and a contract-review PASS does not stand in for it. This record does not stand in for it either. The seat's judgment of the spelling on the tree, for the maintainer: redirectUri is the word the code already uses for this exact value: the plugin option connectorOAuthRedirectUri (plugin.ts:270), the grant-request fields redirectUri in oauth2-grant/authorization.ts:73 and :208 (sent as redirect_uri, line 217) and mcp-authorization.ts:73 (sent as redirect_uris, line 266), the pending-authorization record's redirectUri (plugin.ts:4113), and ConnectorConnectionRequest.client's TSDoc ("this deployment's redirect URI"). redirectUrl is the handler-return navigation convention in ui/action.zod.ts:1121-1123, a different concept the spec actively redirects authors away from; callbackUrl has no precedent in packages/spec/src. The method is the one ruling 6580268872 used (reuse the contract layer's word). The seat recommends A, redirectUri; the choice is the maintainer's.
  • A note for connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463, the server half. connectorOAuthRedirectUri() (plugin.ts:3853-3864) throws a 503 SERVICE_UNAVAILABLE refusal when no base exists. The TSDoc commits the read to answering absent in that case, never a refusal; so the server half must derive on the read leg without throwing (a non-throwing sibling, or a catch on that one refusal) and keep the 503 for the connect leg. Not a defect in this diff; it is the contract the server half now owes.
  • ADR-0143. The D2.1 amendment already says the ui slice "shows the deployment's redirect URI" and D5 fixes the URI per deployment, which is what the TSDoc cites; the ADR names no contract key for it. The docs(adr-0143): append an amendment note that the installer-client server slice has landed (the "until the server slice lands … held degraded" sentence is now history) #29256 amendment pattern recorded the client key names once the server slice landed; the same stroke, naming this key, belongs to connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463's landing. No Tier H path is in this diff (Governed Surface Queue Guard success).
  • Docs drift (advisory). Answered in ①: the flagged page stays accurate on this head; its update is connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463's.
  • Dev deviations (report 6589522107). A name-kill of the seat's own Claim watcher and the model-free commit trailer pair: process notes, neither touches the tree.
  • Dev open question beyond the name. None. The PR is a draft by design (name approval pending) and is not armed.

④ Design judgment

Judged on the hits file only, against the code it cites and ruling B (6566728470).

  • "ADR-0143 D5 — the redirect URI this deployment's connect names ... answered so the Connect step can show it before any client is entered (ADR-0143 D2.1, clientSource: 'installer')." Holds: D5 fixes the URI per deployment and never from the request; the D2.1 amendment assigns the Console the job of showing it; beginConnectorConnection names it on every connect (plugin.ts:4108).
  • "Derived by the server and fixed per deployment, never taken from a request: the automation plugin's connectorOAuthRedirectUri option, else that path under OS_AUTH_URL, else under OS_BASE_URL." Holds against plugin.ts:3853-3857 in that order, and against the option's own TSDoc (plugin.ts:262-270). One nuance, not a misstatement: an env origin that is not http(s):// is treated as no base; "no base to derive it from" covers it.
  • "Present on getConnectorConnection's answer whenever the server can derive it, whatever status says." Consistent with the code's shape: getConnectorConnection (plugin.ts:4087-4091) answers for every status including not_connected (no row), and derivation depends only on config, never on the row. It is a present-tense claim about a member the service does not set yet, and the paragraph's last sentence corrects the reader before the sentence ends: "until the automation service sets it, no answer carries it." That is the repo's declared-before-wired form, read in approval-service.ts:254 ("Declared ahead of its producer ... serves it from plugin-approvals: the approval request page's highlights strip shows the current step's machine id (current_step, such as approve_step) where the approvals get serves the step's label only as step_label #24281 on"), notification-service.ts:228 ("Declared ahead of their implementation ... not a description of running code") and metadata-service.ts:190. The claim is as narrow as the enforcement, which is what Prime Directive chore: version packages #10's corollary asks; nothing is advertised as delivered.
  • "Absent when the deployment has no base to derive it from — a connect is then refused 503 — and ⛔ never guessed from the request's origin." Holds: the connect leg refuses 503 through connectorOAuthRedirectUri() before any client check (plugin.ts:4108 precedes installerClientOfBegin), and the derivation reads no request. The sentence correctly distinguishes the read (absent) from the connect (refused), which is the constraint ③ forwards to connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463.
  • "Only an authorization_code instance has a connection, so no other grant ever carries it." Holds: connectionDoorSubject (plugin.ts:3964-3971) refuses any instance whose auth is not oauth2 / authorization_code with 400 VALIDATION_ERROR before any state is described, so a client_credentials instance never has a ConnectorConnectionState at all. The claim is structural, not a promise about a branch the server half must write.
  • "Read-only: no connection request takes it." Holds: ConnectorConnectionRequest carries connector, context, client only, and refuseClientOffLeg is the pattern for refusing extra input on read and revoke. No readonly modifier, matching every sibling member; "read-only" means what the pin asserts.
  • Is declaring a key the service does not yet set honest? Yes, in this repo's convention: three sibling contracts do it in the same words, and this TSDoc says so in its own text rather than in a comment beside it. The sentence is a known temporary: the PR body commits connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463's PR to delete it.
  • Leak surface. The value is the deployment's public callback URL: the configured public origin (OS_AUTH_URL / OS_BASE_URL, or an option whose whole purpose is to be registered with vendors) plus a fixed path. It carries no secret, and it is already disclosed to the same audience today: inside the 400 prose of a client-less begin (plugin.ts:4055 region, "register ... the redirect URI ${redirectUri}") and as redirect_uri inside every authorizationUrl. The door is gated by the organization-scoped manage_connector_connections capability (domains/automation.ts:1033, :3430-3437; route-ledger rows). Exposing it on the read adds no new disclosure to no new audience. No security defect found.

Findings.

Implemented-by: claude/project-thread-ahu4vx
Reviewed-by: session_01JQwxbWR3K3h7i1ytwycVg1

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

维护者速读

席位核对

ACCEPT · domain:spec#5 · head 555302a1f39e04e55cb8e140ef312a477e2d5f19 · 2026-11-02T22:28Z

  1. Shape: three files: packages/spec/src/contracts/automation-service.ts (the key and its TSDoc), connector-connection-redirect-uri.pin.test.ts (a type-level pin), and .changeset/29574-connector-redirect-uri.md (patch for @objectstack/spec). This matches claim 6587703954. The interface is recorded by name only in api-surface/contracts.json and export-origins/contracts.json, so no ledger or generated artefact moves.
  2. Premise: on main, ConnectorConnectionState has no redirect-URI key. Every TSDoc sentence holds against the plugin code: the derivation chain, the 400 refusal of non-authorization_code instances, no request key, and the declared-ahead wording that follows the approval-service.ts / notification-service.ts convention.
  3. Gates: 64 check-runs on this head: 55 success and 9 skipped (opt-in harnesses and path filters), 0 failed.
  4. Contract review: claim 6589546632. The isolated at-tier record 6590094400 is a PASS on this same head. Semver: patch is right and is the only passing level. With Metadata-protocol: none (a service answer, not authorable metadata), check-changeset-no-major requires every entry to be patch (AGENTS.md step 3). Clause-②: yes (widening) is declared.
  5. Not carried, recorded: (a) Should-fix: name connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463 in the declared-ahead sentence, as approval-service.ts names its producer card. It is prose and rides connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463's PR, which edits that sentence anyway. (b) A note for connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463: connectorOAuthRedirectUri() throws 503 today, so the read leg must derive the value without throwing to honour "absent, never a refusal". (c) A lane observation on the pin: its docAbove assertion assumes redirectUri stays the last member, so the next appended key will need the assertion moved. The pin still checks the shape correctly today.
  6. Landing: not governed (check-governed-merges --pr 29618: 130 changed lines ≤ 3000). ⛔ Merge gate (triage 6586696710): the maintainer approves the key name redirectUri, and the PR body quotes that approval before the queue. The seat lands it via pr_ready + automerge_enable only after that approval.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 00:12
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 3, 2026 00:13
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 744211f Nov 3, 2026
79 of 81 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-ahu4vx branch November 3, 2026 00:38
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/m tests tooling

Projects

None yet

1 participant