Skip to content

connector apps, E4 batch 2 (OAuth): DocuSign as the first declarative verification of the outbound OAuth path, an open-edition metadata package #28277

Open

Description

@objectstack-fleet

epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

Blocked-by: #26702
Blocked-by: #28864
Blocked-by: #28866
Blocked-by: #28869

Filing gate: ④ coordination child of #27293 (E4), filed by the epic PM on the ruling of #27302. Ruling-ref: 6486157794 (letter A, phased: "DocuSign for the OAuth path … OAuth after #26702"). Child of #27293. ⛔ Not a claim.

Why DocuSign

It is the one connector with measured demand: an app-authoring agent on HotCLM concluded the platform had to build a DocuSign plugin (the instance #27223 fixed in the skills; #25747 closed as "a declarative instance once OAuth lands"). #27223's eval already fixes the expected shape.

Work

Reader

The epic PM of #27293 dispatches it when #26702 closes (the server lane holds #26702: blocked on its spec slice, comment 6524351146). Home: the same directory batch 1 (#28276) settles.

Dedupe

Same read as #28276: 0 hits for connector app|shelf|docusign|stripe|github mcp|E4 over the 500 most recent issues and PRs; control connector 47.

Activity

  1. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 发布并装进一个环境 | none | P④

    Triage: p2 · domain:server · area:automation · pm:epic + pm:blocked kept · 2026-10-31T02:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked · p2 · pm:epic kept · 2026-11-01T13:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    Claim: PM loop round 4 (the one epic card in flight, under the maintainer's 「后续并发1」)
    Session: session_017xRBcVBKAFk1ntXSjvPt7U
    Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-28277-connector-app-docusign
    Worktree: objectstack-issue-28277
    Domain: domain:server
    Seat: epic:#27293#1
    File surface: packages/apps/connector-docusign/** (a new npm-private metadata package under the existing packages/apps/* glob, laid out like packages/apps/connector-stripe: the normalized and trimmed eSignature document under openapi/, the oauth2 instance, flows, objectstack.manifest.json with iconUrl per #28588's rule if it has landed, README with credentials, provenance and callback sections, tests), and pnpm-lock.yaml (regenerated by pnpm install, never by hand) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (TIER_DEFAULT — no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6558892788
    Ruling-ref: 6486157794
    Premise: holds (read at origin/main a06feb76 2026-11-01T14:05Z: #26702 closed completed at 2026-11-01T13:24Z (the issue's closed_at, read this act); packages/apps/ holds connector-github and connector-stripe as the layout references; the eSignature document is reachable from this container (raw.githubusercontent.com/docusign/OpenAPI-Specifications, HTTP 200), while DocuSign's sandbox hosts (account-d.docusign.com, demo.docusign.net) are refused by the environment's network policy, so the card's one live sandbox round trip is NOT MEASURABLE here and is owed to the Done-when acceptance run)
    Serial constraints cleared: none — none of the 60 most recent open PRs touches packages/apps/connector-* or the normalizer (files read 2026-11-01T14:05Z).

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
    os-dev-report

    {
      "issue": 28277,
      "status": "needs_decision",
      "branch": "claude/issue-28277-connector-app-docusign",
      "pr": null,
      "session": "session_017xRBcVBKAFk1ntXSjvPt7U",
      "premise_still_valid": true,
      "summary": "No PR. The card's premises hold: #26702 is closed, the eSignature document is reachable and MIT-licensed, and the offline normalizer packages it as the card says. But the one key the OAuth path needs from a shelf app cannot be filled with a real value, so writing the package would mean shipping a guessed value (Prime Directive #10). The key is the DocuSign client id. On an `oauth2` `authorization_code` instance, `clientId` is a literal string inside the connector definition (packages/spec/src/shared/connector-auth.zod.ts:301-303). The grant handle uses it as declared (packages/services/service-automation/src/oauth2-grant/grant-handle.ts:135-137). The only per-connection client is the MCP dynamic-registration one (grant-handle.ts:251). So whoever publishes the package fixes the client id; the installing administrator can only set the secret behind `credentialRef`. A DocuSign client id is an integration key that the integrator registers in their own DocuSign account, together with the redirect URIs it accepts. The platform's redirect URI belongs to each deployment: OS_BASE_URL or OS_AUTH_URL plus /api/v1/automation/connectors/oauth/callback (content/docs/automation/connectors.mdx, the paragraph on the redirect URI; service-automation plugin.ts:3644). So an official open-edition listing that ships one fixed key works only on deployments whose callback URL the key's owner has registered. On any other deployment, DocuSign's consent page refuses the connect. Two more values are also fixed per package. (1) DocuSign's sandbox and production auth hosts differ (account-d.docusign.com vs account.docusign.com). (2) A production account's API host is per account (DocuSign returns base_uri from /oauth/userinfo), while the packaged document names one server, https://www.docusign.net/restapi. The sandbox has one API host, demo.docusign.net. These DocuSign facts come from the vendor's documentation and were NOT measured here: developers.docusign.com and account-d.docusign.com both answer curl 000 from this container. Measured at the dispatch base a06feb76: docusign/OpenAPI-Specifications master 858a3ae59b0edbc8beea4fa3a6d7fe803833dd68 (git ls-remote), esignature.rest.swagger-v2.1.json, 4,846,375 bytes, Swagger 2.0, host www.docusign.net, basePath /restapi, 414 operations, empty securityDefinitions, LICENSE 'The MIT License, Copyright (c) 2017- DocuSign, Inc.'. Running `normalize-openapi --include-pattern '^Envelopes_(PostEnvelopes|GetEnvelope|GetEnvelopes)$' --trim --empty-consumes application/json` on it (exit 0) writes OpenAPI 3.0.4 with 3 operations trimmed from 414, filledConsumes 187 (the card's figure, confirmed), refsLeft 0, servers[0] https://www.docusign.net/restapi and securitySchemes {}, so the token rides on every operation. At --max-depth 2 the output is 553,922 bytes, sha256 e1051eb4bbc381d879e979beac8cb64ead24531c93a19fc26e950a12d9fc961d. At --max-depth 0 it is 304,080 bytes, sha256 b741ded5cfc4d0291d7f0e26559f8583f8c9a783f8711d8f9a98405cb27f7cb4. The three operations map to the eval's names as follows: create envelope = Envelopes_PostEnvelopes (POST /v2.1/accounts/{accountId}/envelopes, JSON body); get envelope = Envelopes_GetEnvelope (GET …/envelopes/{envelopeId}); list status changes = Envelopes_GetEnvelopes (GET …/envelopes with from_date / envelope_ids / status / continuation_token). Every operation takes an accountId path parameter. This part of the build is ready for any letter below that ships the app; the client id, the auth hosts and the API base are what the decision must supply.",
      "tests": "No package was written, so there are no package tests. The measurements behind the summary: (1) under the lock: pnpm --workspace-concurrency=2 --filter '@objectstack/connector-openapi^...' build gives VERDICT command-exit 0 (254 s). (2) The normalizer run at --max-depth 2 and at 0 exits 0 both times, and its printed summaries are quoted in the summary. (3) curl -w http_code against developers.docusign.com (two pages) and account-d.docusign.com/.well-known/openid-configuration answers 000 three times: not reachable from here. The live sandbox round trip is NOT MEASURED: the sandbox hosts are denied by this environment's network policy, and no integration key exists to run it with.",
      "gates": "None run. Nothing was edited: git status --porcelain is empty and git diff origin/main is empty at a06feb76. dispatch-gates --commands derives from a changeset that does not exist. Not measured: every gate family, because no diff exists.",
      "dogfood_battery": "n/a: no PR, no ! in a title, no (narrowing) arm",
      "mcp_calls": "0: no MCP calls of any kind, so no GitHub MCP calls and no MCP writes.",
      "api_writes": "1: this os-dev-report comment through scripts/pm/post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/28277/comments). One git push, not a REST call: the empty-branch probe claude/issue-28277-connector-app-docusign at a06feb76 (routing probe, landed).",
      "deviations": [
        "The dispatch did not paste the pm-dispatch decision framework. The four axes below were read from its only copy (.claude/skills/pm-dispatch/SKILL.md, section 升级与决策, at a06feb76) and were not invented here. No copy was written to any file.",
        "The card's 'one live sandbox round trip' is NOT MEASURED. The dispatch already declared it unmeasurable here, and it is additionally blocked on the integration key this decision supplies."
      ],
      "open_questions": [
        {
          "question": "Where does the DocuSign app's OAuth client (the integration key and the redirect URIs registered on it) come from, given that `clientId` is fixed by whoever publishes the package and the redirect URI belongs to each deployment? In the same ruling: which DocuSign environment the first listing targets, sandbox (account-d.docusign.com, demo.docusign.net) or production (account.docusign.com, an API host per account).",
          "options": [
            "A. Ship now on an ObjectStack-owned key, sandbox only. The maintainer registers a DocuSign developer integration key and adds the acceptance deployment's callback URL (OS_BASE_URL plus /api/v1/automation/connectors/oauth/callback). The app pins clientId to that key, authorizationUrl/tokenUrl to account-d.docusign.com/oauth/auth|token, providerConfig.baseUrl to https://demo.docusign.net/restapi, scopes ['signature'], and credentialRef DOCUSIGN_CLIENT_SECRET (or no ref, as a public PKCE client). Axes. Business need: it satisfies the Done-when's sandbox run, with DocuSign as the measured demand (the HotCLM agent). Long-term: it ties an open-edition listing to one ObjectStack DocuSign account and to whichever redirect URIs that account registered. Production then needs ObjectStack's Go-Live review plus a per-account API host the package cannot express. AI-error axis: the listing installs anywhere, but on every deployment whose callback is not registered the connect fails at DocuSign's page, a declared capability not delivered (PD #10). It is also a confidential client whose secret no other administrator can hold. Not expanding: smallest, with no platform change. Cost: the maintainer registers one key (about 15 minutes) and passes the key value to the dispatch; then 1 PR in this lane (about 900 lines incl. the 554 KB document).",
            "B. Platform first: the installing administrator supplies the OAuth client. A spec+server slice makes an `oauth2` instance's client administrator-supplied (the client id beside the secret in the credential store, or a per-organization client kept on the connection record the way MCP dynamic registration already keeps `registered_client`). The Console credential/connection pages ask for it. This needs ADR-0143 D2.1 amended, because it lists what the variant carries. The DocuSign app then ships with no ObjectStack-owned key, sandbox endpoints first (the Done-when needs only the sandbox), and a follow-up card for the production per-account API host when someone asks for it. Axes. Business need: the same DocuSign demand, plus every later pre-registered-client vendor on an open shelf (HubSpot is ADR-0143's own named case) meets the same wall. Long-term: the one shape under which an open-edition OAuth listing works on every deployment, paid once. AI-error axis: an author cannot ship a listing whose connect depends on someone else's redirect registration, and the definition stays secret-free. Not expanding: adds an authorable surface (Metadata-protocol: added), justified by measured pull. Cost: about 3-4 PRs across spec (with the Tier H ADR amendment), server, ui and this app. DocuSign waits until those land.",
            "C. Prove the shelf's OAuth path with an MCP app that uses dynamic client registration (Notion's hosted MCP server, ADR-0143's own live proof target: no clientId authored, works on any deployment today), and park DocuSign behind B. Axes. Business need: no measured demand for Notion on the board, while DocuSign has it. Long-term: sound, but it moves the measured demand to later. AI-error axis: no guessed key. Not expanding: 1 PR, no platform change. Cost: it re-opens ruling 6486157794's 'DocuSign for the OAuth path', so a re-ruling is needed, and 1 PR."
          ],
          "recommendation": "B. Long-term fit leads: an open-edition OAuth listing has to work on deployments the publisher never sees, and only an administrator-supplied client does that. The other three axes agree. The demand is measured (DocuSign), so the long-term shape is worth paying for once. A fails the AI-error axis outright: it is the declared-not-delivered listing PD #10 forbids. C defers the one vendor with measured demand. If the maintainer wants the Done-when sandbox run before B lands, A is acceptable only as an acceptance-run fixture that is not listed on the shelf, and that needs the maintainer's key value in the dispatch."
        }
      ],
      "out_of_scope_findings": []
    }
  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    Blocked-by: #28702

    Release: the claim 6559014091 is withdrawn in this act. The dev returned needs_decision with no PR (report 6559204204). On an oauth2 instance the package fixes clientId, while the redirect URI is per deployment, so a shelf listing cannot carry a working DocuSign client without a ruling. The question is on decision card #28702 (A: an ObjectStack-owned sandbox key; B: an administrator-supplied OAuth client, platform first; C: a dynamic-registration MCP app instead). The seat recommends B.

    What is measured and kept for whichever letter ships the app: the eSignature document at docusign/OpenAPI-Specifications 858a3ae5 (MIT), normalized to the three operations (Envelopes_PostEnvelopes, Envelopes_GetEnvelope, Envelopes_GetEnvelopes), 187 empty consumes filled, sha256 e1051eb4bbc381d879e979beac8cb64ead24531c93a19fc26e950a12d9fc961d at --max-depth 2. In this act: pm:dispatched → pm:blocked, assignee cleared, pm:epic kept. The empty probe branch claude/issue-28277-connector-app-docusign carries no commits.

  6. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-warren · session_01JQwxbXKRzgnVvjzxaYxLUf

    Claim: PM loop round 1 · card thread · 2026-11-03T05:14Z
    Session: session_01JQwxbXKRzgnVvjzxaYxLUf (the seat); the card thread is session_01JQwxbX1cvwSxDEYCkfDcLg
    Account: os-warren
    Branch: claude/project-thread-6yzp2x
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/apps/connector-docusign/** (a new private metadata package laid out like packages/apps/connector-stripe: the normalized trimmed eSignature document under openapi/, the oauth2 authorization_code instance with the installer-supplied client, flows, objectstack.manifest.json, README with credentials, provenance and callback sections, tests), pnpm-lock.yaml (regenerated by pnpm install only), one .changeset/28277-*.md if the package is published
    Container & model: card thread, mode:thread, model: TIER_DEFAULT (--tier names no path mandate), effort: project default
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6595807811
    Ruling-ref: 6566728470
    Premise: holds (read at origin/main 69dbb3c: every Blocked-by: target (#26702, #28864, #28866, #28869, #28702) is closed; packages/apps/ holds connector-github and connector-stripe as the layout references). Epic child of #27293: the epic seat's claim 6559014091 was withdrawn in 6559236092, and triage returned the card to pm:queue in 6595807811; the server lane takes it from the queue.
    Serial constraints cleared: #28864 / #28866 / #28869 closed (ruling B executed, 6567358929).

    Order: project file pm-orders/server/seat2/order-28277.md.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions