You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
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
Filing gate: ④ execution of a maintainer ruling, slice 3 of 3 (ui). Ruling-ref: 6566728470 (#28702, letter B). Child of #27293 (E4). Handed to the ui lane per 「按你的方案交给车道」. ⛔ Not a claim.
Ruling-ref: 6566728470
Work (this slice, after the server slice #28866 lands)
#28866 landed (PR #29097, ec0316ea44, merged 2026-11-02T15:29Z). An oauth2 connector declaring clientSource: 'installer' connects with the administrator's client { clientId, clientSecret }, and the connection state reads client { source, clientId, hasSecret } (key names ruled A, 6580268872). This card's blocker is gone: the server half and the API for the Console form are on main; domain:ui picks it up on its next round.
State: pm:blocked → pm:queue, recorded by this comment.
Claim: PM loop round 22 · 2026-11-02T15:45Z
Session: session_01QsR2jQhfprmgNtfhzNURJ6 (card thread, os-dev); dispatched by seat session session_01QsR2jV4dWohojjbTJTQq5m
Account: zhuangjianguo
Branch: claude/project-thread-80b6qg (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-28869
Domain: domain:ui
Seat: domain:ui#3
File surface: ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx, connectorConnections.ts, their tests, the locale files for the new keys, and a changeset. If the redirect URI this deployment registers is in no answer the Console can read, the os-dev stops and reports (a server addition is the server lane's) (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: yes (new locale keys; contract review is the seat's own at review)
Metadata-protocol: none
Responsibility: open — recorded at review
Thread-read: none
Premise: holds (at origin/mainaca58cdb: the server half landed as PR #29097ec0316ea44 — an oauth2 connector with clientSource: 'installer' connects with { clientId, clientSecret } and the state reads client { source, clientId, hasSecret } (key names ruled A, 6580268872); ConnectorConnectionsPage.tsx asks for no client).
Serial constraints cleared: Blocked-by: #28866 closed (PR #29097 merged 2026-11-02T15:29Z, unblock comment 6581205465). DocuSign (#28277) waits on this card. No other open PR of this seat touches these files.
Stamped 2026-11-02T15:47Z. Stopped before any code, as the claim (6581428199) orders: the redirect URI this deployment registers is in no answer the Console can read.
{
"issue": 28869,
"status": "blocked",
"branch": "claude/project-thread-80b6qg",
"pr": null,
"session": "session_01QsR2jQhfprmgNtfhzNURJ6",
"premise_still_valid": false,
"summary": "Wanted item 2 (show the exact redirect URI the server derives, with a copy button) has no source on origin/main aca58cdb. The service derives it in ServiceAutomationPlugin.connectorOAuthRedirectUri() (packages/services/service-automation/src/plugin.ts:3853: the connectorOAuthRedirectUri plugin option, else OS_AUTH_URL then OS_BASE_URL plus /api/v1/automation/connectors/oauth/callback, else 503) and hands it to no structured answer. ConnectorConnectionState (packages/spec/src/contracts/automation-service.ts:1144) carries connector, organizationId, status, statusReason, scopes, expiresAt, connectedAt, connectedBy, client; ConnectorConnectionBegin carries authorizationUrl and expiresAt; the /meta/connector item carries the declaration (auth.clientSource is there, so item 1 is feasible). git grep -i redirect_?uri over packages/spec/src, packages/runtime/src, packages/rest/src and service-automation/src outside oauth2-grant finds only the derivation and its uses. The value reaches the Console only (a) inside the prose of the 400 VALIDATION_ERROR a client-less begin answers (plugin.ts:4055), which connectorConnections.ts rules is rendered, never parsed, and (b) as the redirect_uri query parameter of the authorizationUrl a begin WITH a client answers: after the administrator already needed it to register the client, and that URL is never rendered or rebuilt by the module's own rule. A Console-side build from window.location is the hand-built guess the card forbids: the server's origin comes from OS_AUTH_URL / OS_BASE_URL or a plugin option and can differ from the Console's origin. Items 1, 3, 4, 5 are buildable today; item 2 needs a server addition, which the claim routes to the server lane.",
"tests": "none run: no code written",
"gates": "none run: no diff",
"dogfood_battery": "n/a: no diff",
"mcp_calls": "4 GitHub MCP reads, no writes: issue_read get #28869, issue_read get_comments #28869 x2, issue_read get_comments #28866",
"api_writes": "1: POST issues/28869/comments (this report, via post-stamped.mjs through the fleet relay)",
"files_changed": [],
"line_budget": "0",
"deviations": [],
"open_questions": [
{
"question": "Where does the Console read the redirect URI the deployment registers with the vendor?",
"options": [
"A: server lane adds the derived redirect URI to a read the Console already makes, e.g. ConnectorConnectionState on GET /automation/connectors/:name/connection for an authorization_code instance (a new public key: needs a key-name ruling like 6580268872, spec contract + service + door test). This card then resumes on the same branch, Blocked-by that card.",
"B: land items 1, 3, 4, 5 now as Part of #28869 (form, write-only secret, reconnect keeps the stored client, i18n, no form elsewhere) with no redirect URI shown; item 2 follows once A lands.",
"C: parse the URI out of the 400 refusal prose or the authorizationUrl. Not recommended: it reads prose as contract and arrives after the administrator needed it."
],
"recommendation": "A, with B in parallel if the seat wants the form sooner. Four axes: real demand, the administrator cannot register a client without the URI, and DocuSign (#28277) waits on it; long-term, one derivation answered by the server beats a second one in the Console; AI-error, a declared field is checkable while a guessed origin silently differs behind a proxy or OS_BASE_URL; startup focus, one read-only key on an existing answer adds no new surface."
}
],
"security_findings": "withheld",
"out_of_scope_findings": [
"class: none (a missing server answer this card needs, not a defect in landed code) · reach: GET /api/v1/automation/connectors/:name/connection answers no redirect URI; a client-less begin names it only in refusal prose · evidence: plugin.ts:3853 and 4055, automation-service.ts:1144-1182 · dedupe words: connector redirect uri connection state installer client console · carrier: seat 3 routes to the server lane"
]
}
Claim amended · 2026-11-02T15:49Z · on the os-dev's stop report (6581473243), before any code. This adds to claim 6581428199; branch, session, surface and size are unchanged.
Seat's call: option B. PR 1 lands items 1, 3, 4, 5 now — the client id + write-only secret form for a clientSource: 'installer' instance (read from /meta/connector), the begin POST carrying { clientId, clientSecret }, reconnect keeping the stored client unless replaced, the four locales, no form for any other instance — with the body line Part of #28869 (never Fixes). No redirect URI is shown, guessed or parsed from prose (option C refused). Where the URI will sit, the form may say the URI is shown in the Connector docs; no placeholder value.
Stamped 2026-11-02T16:31Z. PR 1 of 2 on this card (claim amendment 6581522588, option B).
{
"issue": 28869,
"status": "done",
"round": "PR 1 of 2 (items 1, 3, 4, 5); item 2 waits on #29463",
"branch": "claude/project-thread-80b6qg",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29496",
"head": "4a4fe174",
"session": "session_01QsR2jQhfprmgNtfhzNURJ6",
"premise_still_valid": true,
"summary": "Connect / Reconnect on an oauth2 authorization_code instance declaring auth.clientSource 'installer' (read from GET /meta/connector) opens a form for the client ID and a masked, write-only client secret before any window opens; Continue begins the connect with the JSON body { clientId, clientSecret } (secret omitted for a public client). The secret is cleared from form state before the begin is awaited, starts empty on every opening and never reaches the DOM. A connected row shows the kept client from the status's client { clientId, hasSecret }. Reconnect shows the stored client ID and whether a secret is kept, prefills the ID and sends the client again, per the seat's call: today's server refuses a client-less begin of such an instance on every begin. Every other instance connects with no form and no body. No redirect URI is shown, guessed or parsed; the form points to the Connectors documentation. Twelve keys in all ten locales.",
"tests": "ConnectorConnectionsPage.test.tsx 17 passed (11 + 6 new) on bc8ea24a; with packages/i18n on merge head 4a4fe174: Test Files 96 passed, Tests 1460 passed, 13 skipped (os-verify-lock VERDICT 0). Ablations via ablation-replace.mjs, each restored blob == HEAD and git diff HEAD empty: A1 installer gate in startConnect dropped -> 6 failed / 11 passed (the no-form pin among them); A2 reader never marks clientSource installer -> 5 failed / 12 passed; A3 secret not cleared on send -> 1 failed / 16 passed. ui vitest aliases @object-ui/* to src, so no rebuild leg. i18n suite 95 files / 1443 passed. turbo type-check app-shell + i18n: 66 tasks, VERDICT 0. Live run: app-crm objectstack dev --fresh with OS_BASE_URL at the Vite Console origin, a local vendor stub, an installer connector saved via PUT /meta/connector/vendor_docs; Playwright: form shown, POST body keys clientId + clientSecret, stub authorize saw that client id, token leg authenticated as that client, row Connected with 'OAuth client live-installer-client, secret stored', status read client { source installer, clientId, hasSecret true }, Reconnect form prefilled with empty secret, typed secret absent from page HTML. Screenshots: /mnt/project-files/issue-28869/live-connect-step.png, live-connected.png, live-reconnect-step.png.",
"gates": "bc8ea24a: dispatch-gates --commands 34 families, all exit 0 (33 node/pnpm check families + pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped, 4921 tests). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. check-sdui-manifest exit 0. PR body gates with GITHUB_EVENT_PATH: check-changeset-no-major exit 0, check-adr-0087-registration exit 0, check-closing-keyword-parity exit 0, check-partof-closing-keyword exit 0. CI on the PR: not yet concluded when this was written (in_progress).",
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "5 GitHub MCP reads, no writes: issue_read get #28869, issue_read get_comments #28869 x3, issue_read get_comments #28866",
"api_writes": "3: POST issues/28869/comments (stop report 6581473243), pr_create #29496 via fleet-write relay, POST issues/28869/comments (this report). git push x3 (not REST).",
"files_changed": [
".changeset/28869-installer-oauth-client-form.md",
"ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.test.tsx",
"ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx",
"ui/packages/app-shell/src/views/setup/connectorConnections.ts",
"ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
],
"line_budget": "14 files, +503 / -16 vs origin/main 94d3e254",
"deviations": [
"Reconnect re-sends the client (secret re-entered) instead of keeping the stored one: seat's ruling B for PR 1, because the server requires a client on every begin today; pinned in a test and named in the PR body. Ask 2 of #29463 adds the reuse; PR 2 switches.",
"Locale keys in all ten packs, not four: all-locales-key-parity holds every pack to one key set.",
"Live run used a local stub for the vendor's authorize/token endpoints, not a real vendor."
],
"open_questions": [],
"security_findings": "withheld",
"out_of_scope_findings": []
}
PR #29496 merged at 2026-11-02T17:07Z as c88467d4 (Part of #28869, ACCEPT and contract review PASS 6582868503). Delivered: an installer-client instance's Connect / Reconnect asks for the client id and a write-only secret and begins with { clientId, clientSecret }; the row shows the kept client id and whether a secret is stored; every other instance connects with no form.
Still open on this card (PR 2, same branch claude/project-thread-80b6qg, Blocked-by #29463): the redirect URI this deployment registers, shown with a copy button from the server's answer; and "reconnect keeps the stored client unless replaced" once the server reuses it. The card stays assigned to domain:ui#3 with pm:dispatched.
Stamped 2026-11-03T04:06Z. PR 2 of 2 on this card (claim 6581428199 as amended by 6581522588, option B, PR 2 leg). The card's first PR was #29496.
{
"issue": 28869,
"status": "done",
"round": "PR 2 of 2 (item 2 and the keep-unless-replaced half of item 3); closes the card",
"branch": "claude/project-thread-80b6qg",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29772",
"head": "9b3449be",
"session": "session_01QsR2jQhfprmgNtfhzNURJ6",
"premise_still_valid": true,
"closing_keyword": "Fixes #28869; #29496 named in prose as the card's first PR, not as a closer",
"body_lines": "Clause-②: yes and Metadata-protocol: none, verbatim in the PR body and the changeset",
"summary": "The installer OAuth client form shows state.redirectUri exactly as GET /automation/connectors/:name/connection answers it (server #29463, PR #29701 c779611e; spec #29618 744211fc), read-only with a Copy button. When the read answers none, the form says the deployment has no redirect URI and names OS_BASE_URL / OS_AUTH_URL; no URI is built from the page origin or parsed from prose. A connection whose status carries client opens Reconnect in keep mode: no fields, and Continue begins with no body, so the server reuses the kept client. 'Replace the stored client' shows the fields (ID prefilled, secret empty) and sends { clientId, clientSecret? }. Disconnect re-reads the status after the revoke (the revoke answer has no redirectUri), so the next Connect still shows the URI. The secret stays write-only: never prefilled, cleared before the begin is awaited, never in the DOM. Eight new keys and two reworded values (clientIntro, clientResend) in all ten locales; no key removed.",
"tests": "ConnectorConnectionsPage.test.tsx 21 passed (5 new: keep default sends no body, replace path, URI shown + Copy, absent URI with no guess, re-read after disconnect; the hubspot disconnect test queues the post-revoke GET). With packages/i18n on merge head 9b3449be: Test Files 96 passed, Tests 1464 passed, 13 skipped. Ablations via ablation-replace.mjs, each restored blob == HEAD and git diff HEAD empty: B1 keep default off (replacing: true) -> 2 failed / 19 passed; B2 replace sends nothing when a client is stored -> 1 failed / 20 passed; B3 URI guessed from window.location.origin when absent -> 1 failed / 20 passed; B4 no re-read after disconnect -> 1 failed / 20 passed. ui vitest aliases @object-ui/* to src, so no rebuild leg. Type-check: turbo app-shell + i18n 66 tasks VERDICT 0 on b223134d; @object-ui/app-shell type-check clean on 9b3449be after pnpm install picked up main's new pinyin-pro dependency. Live run (app-crm objectstack dev --fresh, OS_BASE_URL at the Vite Console origin, local vendor stub, installer connector via PUT /meta/connector/vendor_docs; Playwright): status read before any connect answered redirectUri with status not_connected and the form showed and copied it; Connect sent clientId + clientSecret; Reconnect in keep mode POSTed no body and the stub saw authorize and a token request authenticated as the stored client; Replace prefilled the ID with an empty secret; after Disconnect, Connect still showed the URI; typed secret absent from page HTML. Screenshots: /mnt/project-files/issue-28869/pr2-connect-step-redirect-uri.png, pr2-reconnect-keep.png, pr2-reconnect-replace.png.",
"gates": "c67b39c6: dispatch-gates --commands 35 families, all exit 0 (34 node/pnpm check families + pnpm --dir ui exec vitest run scripts/: 170 files passed, 2 skipped, 4977 tests). --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. Main re-merged at 9b3449be (six commits, no shared file): derivation gives the identical 35 commands; page + i18n suites and app-shell type-check re-run green there. pnpm check:changeset-fixed green. PR body gates with GITHUB_EVENT_PATH: check-changeset-no-major exit 0, check-adr-0087-registration exit 0, check-closing-keyword-parity exit 0, check-partof-closing-keyword exit 0. CI on the PR: not concluded when this was written.",
"contract_review": "owed per the seat; the seat requests it",
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "5 GitHub MCP reads on the card in total, no writes: issue_read get #28869, issue_read get_comments #28869 x3, issue_read get_comments #28866",
"api_writes": "2 this round: pr_create #29772 via fleet-write relay (read-back 7605 bytes identical, no assignees), POST issues/28869/comments (this report). git pushes of the branch (not REST).",
"files_changed": [
".changeset/28869-connect-redirect-uri-keep-client.md",
"ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.test.tsx",
"ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx",
"ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
],
"line_budget": "13 files, +335 / -93 vs origin/main 3eeb81d1",
"deviations": [
"Locale keys in all ten packs: all-locales-key-parity holds every pack to one key set.",
"Live run used a local stub for the vendor's authorize/token endpoints, not a real vendor.",
"A teardown killed the container's environment-manager process (listed by lsof on a dev port), which restarted the worker mid gate loop; every gate was re-run from the start. No repo effect."
],
"open_questions": [],
"security_findings": "withheld",
"out_of_scope_findings": []
}
PR #29772 merged at 2026-11-03T04:42Z as 946a173f. Fixes #28869 closed this card, and pm:dispatched is removed. The seat's ACCEPT is 6595384633; the director's contract review passed at 6595261457.
Delivered across two PRs: #29496 put the redirect URI on the connection read. #29772 shows that URI on the connector connections page with a Copy button (or a line saying it is missing), and lets an admin reconnect while keeping the stored client instead of re-entering it. A revoke now re-reads the connection status. Nothing else is left on this card.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
domain:ui· 2026-11-02T02:57Z⛔ Not a claim.
clientIdis fixed by the package and the redirect URI is per deployment #28702 ruling: the Connect step asks for the client id and secret, and shows the redirect URI to register. p2;Blocked-by: #28866stands.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Unblocked · 2026-11-02T15:35Z
#28866 landed (PR #29097,
ec0316ea44, merged 2026-11-02T15:29Z). An oauth2 connector declaringclientSource: 'installer'connects with the administrator's client{ clientId, clientSecret }, and the connection state readsclient { source, clientId, hasSecret }(key names ruled A, 6580268872). This card's blocker is gone: the server half and the API for the Console form are onmain;domain:uipicks it up on its next round.State:
pm:blocked→pm:queue, recorded by this comment.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Claim: PM loop round 22 · 2026-11-02T15:45Z
Session:
session_01QsR2jQhfprmgNtfhzNURJ6(card thread, os-dev); dispatched by seat sessionsession_01QsR2jV4dWohojjbTJTQq5mAccount:
zhuangjianguoBranch:
claude/project-thread-80b6qg(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28869Domain:
domain:uiSeat:
domain:ui#3File surface:
ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx,connectorConnections.ts, their tests, the locale files for the new keys, and a changeset. If the redirect URI this deployment registers is in no answer the Console can read, the os-dev stops and reports (a server addition is the server lane's) (stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (new locale keys; contract review is the seat's own at review)
Metadata-protocol: none
Responsibility:
open — recorded at reviewThread-read: none
Premise: holds (at
origin/mainaca58cdb: the server half landed as PR #29097ec0316ea44— an oauth2 connector withclientSource: 'installer'connects with{ clientId, clientSecret }and the state readsclient { source, clientId, hasSecret }(key names ruled A, 6580268872);ConnectorConnectionsPage.tsxasks for no client).Serial constraints cleared:
Blocked-by: #28866closed (PR #29097 merged 2026-11-02T15:29Z, unblock comment 6581205465). DocuSign (#28277) waits on this card. No other open PR of this seat touches these files.objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jQhfprmgNtfhzNURJ6
os-dev-report
Stamped 2026-11-02T15:47Z. Stopped before any code, as the claim (6581428199) orders: the redirect URI this deployment registers is in no answer the Console can read.
{ "issue": 28869, "status": "blocked", "branch": "claude/project-thread-80b6qg", "pr": null, "session": "session_01QsR2jQhfprmgNtfhzNURJ6", "premise_still_valid": false, "summary": "Wanted item 2 (show the exact redirect URI the server derives, with a copy button) has no source on origin/main aca58cdb. The service derives it in ServiceAutomationPlugin.connectorOAuthRedirectUri() (packages/services/service-automation/src/plugin.ts:3853: the connectorOAuthRedirectUri plugin option, else OS_AUTH_URL then OS_BASE_URL plus /api/v1/automation/connectors/oauth/callback, else 503) and hands it to no structured answer. ConnectorConnectionState (packages/spec/src/contracts/automation-service.ts:1144) carries connector, organizationId, status, statusReason, scopes, expiresAt, connectedAt, connectedBy, client; ConnectorConnectionBegin carries authorizationUrl and expiresAt; the /meta/connector item carries the declaration (auth.clientSource is there, so item 1 is feasible). git grep -i redirect_?uri over packages/spec/src, packages/runtime/src, packages/rest/src and service-automation/src outside oauth2-grant finds only the derivation and its uses. The value reaches the Console only (a) inside the prose of the 400 VALIDATION_ERROR a client-less begin answers (plugin.ts:4055), which connectorConnections.ts rules is rendered, never parsed, and (b) as the redirect_uri query parameter of the authorizationUrl a begin WITH a client answers: after the administrator already needed it to register the client, and that URL is never rendered or rebuilt by the module's own rule. A Console-side build from window.location is the hand-built guess the card forbids: the server's origin comes from OS_AUTH_URL / OS_BASE_URL or a plugin option and can differ from the Console's origin. Items 1, 3, 4, 5 are buildable today; item 2 needs a server addition, which the claim routes to the server lane.", "tests": "none run: no code written", "gates": "none run: no diff", "dogfood_battery": "n/a: no diff", "mcp_calls": "4 GitHub MCP reads, no writes: issue_read get #28869, issue_read get_comments #28869 x2, issue_read get_comments #28866", "api_writes": "1: POST issues/28869/comments (this report, via post-stamped.mjs through the fleet relay)", "files_changed": [], "line_budget": "0", "deviations": [], "open_questions": [ { "question": "Where does the Console read the redirect URI the deployment registers with the vendor?", "options": [ "A: server lane adds the derived redirect URI to a read the Console already makes, e.g. ConnectorConnectionState on GET /automation/connectors/:name/connection for an authorization_code instance (a new public key: needs a key-name ruling like 6580268872, spec contract + service + door test). This card then resumes on the same branch, Blocked-by that card.", "B: land items 1, 3, 4, 5 now as Part of #28869 (form, write-only secret, reconnect keeps the stored client, i18n, no form elsewhere) with no redirect URI shown; item 2 follows once A lands.", "C: parse the URI out of the 400 refusal prose or the authorizationUrl. Not recommended: it reads prose as contract and arrives after the administrator needed it." ], "recommendation": "A, with B in parallel if the seat wants the form sooner. Four axes: real demand, the administrator cannot register a client without the URI, and DocuSign (#28277) waits on it; long-term, one derivation answered by the server beats a second one in the Console; AI-error, a declared field is checkable while a guessed origin silently differs behind a proxy or OS_BASE_URL; startup focus, one read-only key on an existing answer adds no new surface." } ], "security_findings": "withheld", "out_of_scope_findings": [ "class: none (a missing server answer this card needs, not a defect in landed code) · reach: GET /api/v1/automation/connectors/:name/connection answers no redirect URI; a client-less begin names it only in refusal prose · evidence: plugin.ts:3853 and 4055, automation-service.ts:1144-1182 · dedupe words: connector redirect uri connection state installer client console · carrier: seat 3 routes to the server lane" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Claim amended · 2026-11-02T15:49Z · on the os-dev's stop report (6581473243), before any code. This adds to claim 6581428199; branch, session, surface and size are unchanged.
Clause-②: yes
Metadata-protocol: none
plugin.ts:3853derives it;ConnectorConnectionStateandConnectorConnectionBegincarry none). Filed to the server lane as connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463 (the connection state answers the derived redirect URI).clientSource: 'installer'instance (read from/meta/connector), the begin POST carrying{ clientId, clientSecret }, reconnect keeping the stored client unless replaced, the four locales, no form for any other instance — with the body linePart of #28869(neverFixes). No redirect URI is shown, guessed or parsed from prose (option C refused). Where the URI will sit, the form may say the URI is shown in the Connector docs; no placeholder value.objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jQhfprmgNtfhzNURJ6
os-dev-report
Stamped 2026-11-02T16:31Z. PR 1 of 2 on this card (claim amendment 6581522588, option B).
{ "issue": 28869, "status": "done", "round": "PR 1 of 2 (items 1, 3, 4, 5); item 2 waits on #29463", "branch": "claude/project-thread-80b6qg", "pr": "https://github.com/objectstack-ai/objectstack/pull/29496", "head": "4a4fe174", "session": "session_01QsR2jQhfprmgNtfhzNURJ6", "premise_still_valid": true, "summary": "Connect / Reconnect on an oauth2 authorization_code instance declaring auth.clientSource 'installer' (read from GET /meta/connector) opens a form for the client ID and a masked, write-only client secret before any window opens; Continue begins the connect with the JSON body { clientId, clientSecret } (secret omitted for a public client). The secret is cleared from form state before the begin is awaited, starts empty on every opening and never reaches the DOM. A connected row shows the kept client from the status's client { clientId, hasSecret }. Reconnect shows the stored client ID and whether a secret is kept, prefills the ID and sends the client again, per the seat's call: today's server refuses a client-less begin of such an instance on every begin. Every other instance connects with no form and no body. No redirect URI is shown, guessed or parsed; the form points to the Connectors documentation. Twelve keys in all ten locales.", "tests": "ConnectorConnectionsPage.test.tsx 17 passed (11 + 6 new) on bc8ea24a; with packages/i18n on merge head 4a4fe174: Test Files 96 passed, Tests 1460 passed, 13 skipped (os-verify-lock VERDICT 0). Ablations via ablation-replace.mjs, each restored blob == HEAD and git diff HEAD empty: A1 installer gate in startConnect dropped -> 6 failed / 11 passed (the no-form pin among them); A2 reader never marks clientSource installer -> 5 failed / 12 passed; A3 secret not cleared on send -> 1 failed / 16 passed. ui vitest aliases @object-ui/* to src, so no rebuild leg. i18n suite 95 files / 1443 passed. turbo type-check app-shell + i18n: 66 tasks, VERDICT 0. Live run: app-crm objectstack dev --fresh with OS_BASE_URL at the Vite Console origin, a local vendor stub, an installer connector saved via PUT /meta/connector/vendor_docs; Playwright: form shown, POST body keys clientId + clientSecret, stub authorize saw that client id, token leg authenticated as that client, row Connected with 'OAuth client live-installer-client, secret stored', status read client { source installer, clientId, hasSecret true }, Reconnect form prefilled with empty secret, typed secret absent from page HTML. Screenshots: /mnt/project-files/issue-28869/live-connect-step.png, live-connected.png, live-reconnect-step.png.", "gates": "bc8ea24a: dispatch-gates --commands 34 families, all exit 0 (33 node/pnpm check families + pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped, 4921 tests). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. check-sdui-manifest exit 0. PR body gates with GITHUB_EVENT_PATH: check-changeset-no-major exit 0, check-adr-0087-registration exit 0, check-closing-keyword-parity exit 0, check-partof-closing-keyword exit 0. CI on the PR: not yet concluded when this was written (in_progress).", "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "5 GitHub MCP reads, no writes: issue_read get #28869, issue_read get_comments #28869 x3, issue_read get_comments #28866", "api_writes": "3: POST issues/28869/comments (stop report 6581473243), pr_create #29496 via fleet-write relay, POST issues/28869/comments (this report). git push x3 (not REST).", "files_changed": [ ".changeset/28869-installer-oauth-client-form.md", "ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.test.tsx", "ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx", "ui/packages/app-shell/src/views/setup/connectorConnections.ts", "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts" ], "line_budget": "14 files, +503 / -16 vs origin/main 94d3e254", "deviations": [ "Reconnect re-sends the client (secret re-entered) instead of keeping the stored one: seat's ruling B for PR 1, because the server requires a client on every begin today; pinned in a test and named in the PR body. Ask 2 of #29463 adds the reuse; PR 2 switches.", "Locale keys in all ten packs, not four: all-locales-key-parity holds every pack to one key set.", "Live run used a local stub for the vendor's authorize/token endpoints, not a real vendor." ], "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Landed (partial, PR 1 of 2) · 2026-11-02T17:07Z
PR #29496 merged at 2026-11-02T17:07Z as
c88467d4(Part of #28869, ACCEPT and contract review PASS 6582868503). Delivered: an installer-client instance's Connect / Reconnect asks for the client id and a write-only secret and begins with{ clientId, clientSecret }; the row shows the kept client id and whether a secret is stored; every other instance connects with no form.Still open on this card (PR 2, same branch
claude/project-thread-80b6qg, Blocked-by #29463): the redirect URI this deployment registers, shown with a copy button from the server's answer; and "reconnect keeps the stored client unless replaced" once the server reuses it. The card stays assigned todomain:ui#3withpm:dispatched.objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jQhfprmgNtfhzNURJ6
os-dev-report
Stamped 2026-11-03T04:06Z. PR 2 of 2 on this card (claim 6581428199 as amended by 6581522588, option B, PR 2 leg). The card's first PR was #29496.
{ "issue": 28869, "status": "done", "round": "PR 2 of 2 (item 2 and the keep-unless-replaced half of item 3); closes the card", "branch": "claude/project-thread-80b6qg", "pr": "https://github.com/objectstack-ai/objectstack/pull/29772", "head": "9b3449be", "session": "session_01QsR2jQhfprmgNtfhzNURJ6", "premise_still_valid": true, "closing_keyword": "Fixes #28869; #29496 named in prose as the card's first PR, not as a closer", "body_lines": "Clause-②: yes and Metadata-protocol: none, verbatim in the PR body and the changeset", "summary": "The installer OAuth client form shows state.redirectUri exactly as GET /automation/connectors/:name/connection answers it (server #29463, PR #29701 c779611e; spec #29618 744211fc), read-only with a Copy button. When the read answers none, the form says the deployment has no redirect URI and names OS_BASE_URL / OS_AUTH_URL; no URI is built from the page origin or parsed from prose. A connection whose status carries client opens Reconnect in keep mode: no fields, and Continue begins with no body, so the server reuses the kept client. 'Replace the stored client' shows the fields (ID prefilled, secret empty) and sends { clientId, clientSecret? }. Disconnect re-reads the status after the revoke (the revoke answer has no redirectUri), so the next Connect still shows the URI. The secret stays write-only: never prefilled, cleared before the begin is awaited, never in the DOM. Eight new keys and two reworded values (clientIntro, clientResend) in all ten locales; no key removed.", "tests": "ConnectorConnectionsPage.test.tsx 21 passed (5 new: keep default sends no body, replace path, URI shown + Copy, absent URI with no guess, re-read after disconnect; the hubspot disconnect test queues the post-revoke GET). With packages/i18n on merge head 9b3449be: Test Files 96 passed, Tests 1464 passed, 13 skipped. Ablations via ablation-replace.mjs, each restored blob == HEAD and git diff HEAD empty: B1 keep default off (replacing: true) -> 2 failed / 19 passed; B2 replace sends nothing when a client is stored -> 1 failed / 20 passed; B3 URI guessed from window.location.origin when absent -> 1 failed / 20 passed; B4 no re-read after disconnect -> 1 failed / 20 passed. ui vitest aliases @object-ui/* to src, so no rebuild leg. Type-check: turbo app-shell + i18n 66 tasks VERDICT 0 on b223134d; @object-ui/app-shell type-check clean on 9b3449be after pnpm install picked up main's new pinyin-pro dependency. Live run (app-crm objectstack dev --fresh, OS_BASE_URL at the Vite Console origin, local vendor stub, installer connector via PUT /meta/connector/vendor_docs; Playwright): status read before any connect answered redirectUri with status not_connected and the form showed and copied it; Connect sent clientId + clientSecret; Reconnect in keep mode POSTed no body and the stub saw authorize and a token request authenticated as the stored client; Replace prefilled the ID with an empty secret; after Disconnect, Connect still showed the URI; typed secret absent from page HTML. Screenshots: /mnt/project-files/issue-28869/pr2-connect-step-redirect-uri.png, pr2-reconnect-keep.png, pr2-reconnect-replace.png.", "gates": "c67b39c6: dispatch-gates --commands 35 families, all exit 0 (34 node/pnpm check families + pnpm --dir ui exec vitest run scripts/: 170 files passed, 2 skipped, 4977 tests). --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. Main re-merged at 9b3449be (six commits, no shared file): derivation gives the identical 35 commands; page + i18n suites and app-shell type-check re-run green there. pnpm check:changeset-fixed green. PR body gates with GITHUB_EVENT_PATH: check-changeset-no-major exit 0, check-adr-0087-registration exit 0, check-closing-keyword-parity exit 0, check-partof-closing-keyword exit 0. CI on the PR: not concluded when this was written.", "contract_review": "owed per the seat; the seat requests it", "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "5 GitHub MCP reads on the card in total, no writes: issue_read get #28869, issue_read get_comments #28869 x3, issue_read get_comments #28866", "api_writes": "2 this round: pr_create #29772 via fleet-write relay (read-back 7605 bytes identical, no assignees), POST issues/28869/comments (this report). git pushes of the branch (not REST).", "files_changed": [ ".changeset/28869-connect-redirect-uri-keep-client.md", "ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.test.tsx", "ui/packages/app-shell/src/views/setup/ConnectorConnectionsPage.tsx", "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts" ], "line_budget": "13 files, +335 / -93 vs origin/main 3eeb81d1", "deviations": [ "Locale keys in all ten packs: all-locales-key-parity holds every pack to one key set.", "Live run used a local stub for the vendor's authorize/token endpoints, not a real vendor.", "A teardown killed the container's environment-manager process (listed by lsof on a dev port), which restarted the worker mid gate loop; every gate was re-run from the start. No repo effect." ], "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Landed · 2026-11-03T04:43Z
PR #29772 merged at 2026-11-03T04:42Z as
946a173f.Fixes #28869closed this card, andpm:dispatchedis removed. The seat's ACCEPT is 6595384633; the director's contract review passed at 6595261457.Delivered across two PRs: #29496 put the redirect URI on the connection read. #29772 shows that URI on the connector connections page with a Copy button (or a line saying it is missing), and lets an admin reconnect while keeping the stored client instead of re-entering it. A revoke now re-reads the connection status. Nothing else is left on this card.