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
automation: the sys_connector_connection status description, the markReconnectRequired docblock and reconnectRequiredReason all say reconnect_required means the authorization server refused the grant; three other paths set it #28863
Filing gate: ① defects with named locations, found by the #28614 dev (report 6567285836, out_of_scope_findings a and b) while correcting the same claim in @objectstack/spec (PR #28862). ⛔ Not a claim. No grade: triage sets it and the lane.
Reader: the owner of packages/services/service-automation and packages/platform-objects (likely domain:server); not domain:spec.
Dedupe (open AND closed): reconnectRequiredReason, markReconnectRequired docblock, sys_connector_connection status → only #28614 (the spec JSDoc, a different file).
reach: an admin reading a stored status_reason, or the connection object's field help, is told the authorization server refused the grant when it was never asked.
Where (on main)
packages/platform-objects/.../sys-connector-connection.object.ts ≈L98: the status field description says reconnect_required means the authorization server refused the grant.
packages/services/service-automation/src/connector-connections.ts: the ConnectorConnectionStore#markReconnectRequired docblock carries the same narrow claim.
packages/services/service-automation/src/oauth2-grant/grant-handle.ts ≈L123: reconnectRequiredReason opens with "its authorization server refused the grant". refreshOnce reuses it on the no-refresh-token path (≈L267) and the no-client path (≈L271), where no server was asked. So the stored statusReason first claims a refusal and only then states the real cause.
What is true
reconnect_required is set four ways: a refresh refused by the authorization server; no refresh token was issued; the connection keeps no client to refresh with; and the upstream refused the connection's token at MCP tool discovery (PR #28598, plugin.ts). PR #28862 words the spec contract this way.
Done when
Items 1 and 2 describe all four causes, as the spec JSDoc does after PR #28862. Item 3's reason names the cause that actually happened on each path, and a test pins the no-refresh-token and no-client reasons.
Two more rows for this card, from the contract review of PR #28862 (record 6567423011). Both are for triage to fold in or split out.
content/docs/automation/connectors.mdx L689–691 and L868 still give invalid_grant as the only cause of "reconnect required". The drift check cannot see this, because there is no shared anchor.
"expired" is narrower than the code. In grant-handle.ts, get() refreshes on any cache miss (L333–337: a fresh replica, or a revision another replica moved), and refresh() runs on a dispatch's 401. So a connection with no refresh token is marked even while its access token is still valid. The runtime's appended reason (L268–269) and the spec JSDoc as merged by PR docs(spec): reconnect_required docblock names every way the grant stops working #28862 both say "expired". Change them together, for example to "an access token it has to renew", so the two stay in agreement.
Claim: PM loop round 1 · card thread · 2026-11-02T03:57Z
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01FEkQ5mTYb1BTJNRqf3bdJ8 (the #28735 / #28776 / #28831 card thread, continuing)
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-xqgh8b (the card thread's harness-pinned branch, restarted from main after PR #28857; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#1
Ruling-ref: triage#1 graded the card p3 domain:server (03:02Z): use PR #28862's spec wording, and that review's should-fix ("an expired access token" is narrower than the code). Dispatch under 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」 (Leehom, 2026-11-01T12:11Z).
File surface: items 1–4 and the runtime half of item 5: the status description in sys-connector-connection.object.ts (packages/platform-objects), the markReconnectRequired docblock and reconnectRequiredReason / refreshOnce reasons in packages/services/service-automation, content/docs/automation/connectors.mdx; their tests and changesets. ⛔ No packages/spec/**: the spec JSDoc half of item 5 goes to the spec lane, filed by the seat.
Container & model: S, mode:thread, model and effort as the thread was opened
Clause-②: no (prose and a stored reason text; no accept-set change)
Metadata-protocol: per AGENTS.md, measured by the dev (likely none)
Responsibility: the code is the connector connection status of @objectstack/platform-objects and the OAuth2 grant handle of @objectstack/service-automation · the platform path is an admin reading a stored status_reason or the field help that names a refused grant that never happened · reached by every connection marked reconnect_required with no refresh token or no client
Thread-read: none
Premise: holds on main (the card's reading, after PR #28862)
Serial constraints cleared: no open server card edits grant-handle.ts or the connection object; #28866 (blocked on #28864) will touch the same store later and merges origin/main then.
Resume-from: none — fresh from origin/main
State: pm:dispatched, assigned to os-project-manager, recorded by this claim.
os-dev-report
{
"issue": 28863,
"status": "done",
"branch": "claude/project-thread-xqgh8b",
"pr": "#28955",
"session": "session_01FEkQ5mTYb1BTJNRqf3bdJ8",
"premise_still_valid": true,
"summary": "reconnectRequiredReason (service-automation oauth2-grant/grant-handle.ts) takes an optional cause ('refused' by default, its sentence unchanged; 'no_refresh_token'; 'no_client'), and refreshOnce passes each path's own, so the stored status_reason and the 503 message name the cause that happened: no claimed refusal on the two paths that never ask the server, and 'an access token the connection has to renew' instead of 'expired'. The sys_connector_connection status field help (it lives in service-automation, not platform-objects), the markReconnectRequired docblock and connectors.mdx (L689 paragraph, L868 table row) name all four causes in PR #28862's words. Spec half not touched: packages/spec/src/contracts/automation-service.ts L1145-1146 ('the connection keeps nothing to renew an / expired access token with') is for the spec lane.",
"tests": "Three new cases in grant-handle.test.ts ([#28863]): no refresh token and no client each store a reason naming their cause, without 'refused' or 'expired', equal to the 503 message, no token request; control invalid_grant still names the refusal. Base (grant-handle.ts from 5e1b9b0): Tests 2 failed | 20 passed (22), the two non-refusal paths ('to contain issued no refresh token, so an access…' / 'keeps no client to refresh with, so a…'); head 22/22; restore clean. At 7cf0294 after a full build (118/118): service-automation Test Files 255 passed, Tests 3284 passed, typecheck exit 0; platform-objects Test Files 108 passed, Tests 1503 passed, typecheck exit 0; repo lint command scoped to packages/services/service-automation exit 0. Old-text matches: grant-handle.test.ts L322 ('issued no refresh token', kept, green); connector-connections.test.ts L148-157 (own string); connector-connection-door.test.ts L576 (the plugin's onGrantRefused log, untouched). No consumer in objectstack, objectui or hotcrm reads the reason text.",
"gates": "dispatch-gates --commands derived 89 at 7cf0294 (docs families included); all 89 exit 0 (record pm-orders/server/28863-gates-ran.txt); --ran: 89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN; check:type-check-debt OK. CI families: see PR #28955's check-runs.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm; not run",
"mcp_calls": "2 — read only: issue_read x2 (#28863 get, its comments). No write tool.",
"api_writes": "3 — git push (claude/project-thread-xqgh8b to 7cf0294, plain), relay pr_create (#28955, draft, no assignees, no labels: a changeset is present), and this os-dev-report comment through post-stamped.",
"spec_jsdoc_line": "packages/spec/src/contracts/automation-service.ts L1145-1146 (ConnectorConnectionState.status JSDoc, merged by PR #28862): 'the connection keeps nothing to renew an expired access token with'. Proposed: 'an access token it has to renew', matching the runtime sentence.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: named producer: the plugin's onGrantRefused warn line (service-automation plugin.ts ≈L3697) logs 'the authorization server refused the grant' on all three refresh paths · evidence: read at 7cf0294 · dedupe words: onGrantRefused log refused the grant · carrier: seat 1 · noted, not filed",
"class: b · reach: the dispatch refusal for a row already marked reconnect_required (grant-handle.ts select ≈L238, refreshOnce first check, plugin hold-reason fallback ≈L3189) uses the default refused sentence whatever cause the row stores; answering with the row's statusReason would fix it · dedupe words: reconnect required dispatch refusal stored statusReason · carrier: seat 1 · noted, not filed"
]
}
PR #28955 merged by the merge queue as 07450b5c39 on main (Fixes #28863; Clause-②: no, with no contract review owed; ACCEPT 6569454809). The card closed on the merge.
Landed: a connection marked reconnect_required stores and answers the cause that happened (refused on refresh, no refresh token, no client), and none says "expired". The status field help, the markReconnectRequired docblock and connectors.mdx list all four causes. @objectstack/service-automation patch, Metadata-protocol: none.
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Two more rows for this card, from the contract review of PR #28862 (record 6567423011). Both are for triage to fold in or split out.
content/docs/automation/connectors.mdxL689–691 and L868 still giveinvalid_grantas the only cause of "reconnect required". The drift check cannot see this, because there is no shared anchor.grant-handle.ts,get()refreshes on any cache miss (L333–337: a fresh replica, or arevisionanother replica moved), andrefresh()runs on a dispatch's 401. So a connection with no refresh token is marked even while its access token is still valid. The runtime's appended reason (L268–269) and the spec JSDoc as merged by PR docs(spec): reconnect_required docblock names every way the grant stops working #28862 both say "expired". Change them together, for example to "an access token it has to renew", so the two stay in agreement.objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p3 ·
domain:server· 2026-11-02T03:02Z⛔ Not a claim.
sys_connector_connectionstatus description, themarkReconnectRequireddocblock andreconnectRequiredReasonall name only the refused grant. Prose that tells an admin the wrong cause: p3,domain:server, which ownsservice-automationandplatform-objects. It staysfindingfor the finding round. Use docs(spec): reconnect_required docblock names every way the grant stops working #28862's spec wording, and the PR docs(spec): reconnect_required docblock names every way the grant stops working #28862 review's should-fix ("an expired access token" is narrower than the code).Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC
Claim: PM loop round 1 · card thread · 2026-11-02T03:57Z
Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_01FEkQ5mTYb1BTJNRqf3bdJ8(the #28735 / #28776 / #28831 card thread, continuing)Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-xqgh8b(the card thread's harness-pinned branch, restarted frommainafter PR #28857; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#1Ruling-ref: triage#1 graded the card p3
domain:server(03:02Z): use PR #28862's spec wording, and that review's should-fix ("an expired access token" is narrower than the code). Dispatch under 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」 (Leehom, 2026-11-01T12:11Z).File surface: items 1–4 and the runtime half of item 5: the
statusdescription insys-connector-connection.object.ts(packages/platform-objects), themarkReconnectRequireddocblock andreconnectRequiredReason/refreshOncereasons inpackages/services/service-automation,content/docs/automation/connectors.mdx; their tests and changesets. ⛔ Nopackages/spec/**: the spec JSDoc half of item 5 goes to the spec lane, filed by the seat.Container & model:
S,mode:thread, model and effort as the thread was openedClause-②: no (prose and a stored reason text; no accept-set change)
Metadata-protocol: per AGENTS.md, measured by the dev (likely none)
Responsibility: the code is the connector connection status of
@objectstack/platform-objectsand the OAuth2 grant handle of@objectstack/service-automation· the platform path is an admin reading a storedstatus_reasonor the field help that names a refused grant that never happened · reached by every connection markedreconnect_requiredwith no refresh token or no clientThread-read: none
Premise: holds on
main(the card's reading, after PR #28862)Serial constraints cleared: no open server card edits
grant-handle.tsor the connection object; #28866 (blocked on #28864) will touch the same store later and mergesorigin/mainthen.Resume-from: none — fresh from
origin/mainState:
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01FEkQ5mTYb1BTJNRqf3bdJ8
os-dev-report
{
"issue": 28863,
"status": "done",
"branch": "claude/project-thread-xqgh8b",
"pr": "#28955",
"session": "session_01FEkQ5mTYb1BTJNRqf3bdJ8",
"premise_still_valid": true,
"summary": "reconnectRequiredReason (service-automation oauth2-grant/grant-handle.ts) takes an optional cause ('refused' by default, its sentence unchanged; 'no_refresh_token'; 'no_client'), and refreshOnce passes each path's own, so the stored status_reason and the 503 message name the cause that happened: no claimed refusal on the two paths that never ask the server, and 'an access token the connection has to renew' instead of 'expired'. The sys_connector_connection status field help (it lives in service-automation, not platform-objects), the markReconnectRequired docblock and connectors.mdx (L689 paragraph, L868 table row) name all four causes in PR #28862's words. Spec half not touched: packages/spec/src/contracts/automation-service.ts L1145-1146 ('the connection keeps nothing to renew an / expired access token with') is for the spec lane.",
"tests": "Three new cases in grant-handle.test.ts ([#28863]): no refresh token and no client each store a reason naming their cause, without 'refused' or 'expired', equal to the 503 message, no token request; control invalid_grant still names the refusal. Base (grant-handle.ts from 5e1b9b0): Tests 2 failed | 20 passed (22), the two non-refusal paths ('to contain issued no refresh token, so an access…' / 'keeps no client to refresh with, so a…'); head 22/22; restore clean. At 7cf0294 after a full build (118/118): service-automation Test Files 255 passed, Tests 3284 passed, typecheck exit 0; platform-objects Test Files 108 passed, Tests 1503 passed, typecheck exit 0; repo lint command scoped to packages/services/service-automation exit 0. Old-text matches: grant-handle.test.ts L322 ('issued no refresh token', kept, green); connector-connections.test.ts L148-157 (own string); connector-connection-door.test.ts L576 (the plugin's onGrantRefused log, untouched). No consumer in objectstack, objectui or hotcrm reads the reason text.",
"gates": "dispatch-gates --commands derived 89 at 7cf0294 (docs families included); all 89 exit 0 (record pm-orders/server/28863-gates-ran.txt); --ran: 89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN; check:type-check-debt OK. CI families: see PR #28955's check-runs.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm; not run",
"mcp_calls": "2 — read only: issue_read x2 (#28863 get, its comments). No write tool.",
"api_writes": "3 — git push (claude/project-thread-xqgh8b to 7cf0294, plain), relay pr_create (#28955, draft, no assignees, no labels: a changeset is present), and this os-dev-report comment through post-stamped.",
"spec_jsdoc_line": "packages/spec/src/contracts/automation-service.ts L1145-1146 (ConnectorConnectionState.status JSDoc, merged by PR #28862): 'the connection keeps nothing to renew an expired access token with'. Proposed: 'an access token it has to renew', matching the runtime sentence.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: named producer: the plugin's onGrantRefused warn line (service-automation plugin.ts ≈L3697) logs 'the authorization server refused the grant' on all three refresh paths · evidence: read at 7cf0294 · dedupe words: onGrantRefused log refused the grant · carrier: seat 1 · noted, not filed",
"class: b · reach: the dispatch refusal for a row already marked reconnect_required (grant-handle.ts select ≈L238, refreshOnce first check, plugin hold-reason fallback ≈L3189) uses the default refused sentence whatever cause the row stores; answering with the row's statusReason would fix it · dedupe words: reconnect required dispatch refusal stored statusReason · carrier: seat 1 · noted, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC
Landing record · #28863 · PR #28955
PR #28955 merged by the merge queue as
07450b5c39onmain(Fixes #28863;Clause-②: no, with no contract review owed; ACCEPT6569454809). The card closed on the merge.git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28955-*'origin/mainby contentgit diff --quiet 07450b5c39 origin/main --the PR's 6 filesgit merge-base --is-ancestor 07450b5c39 origin/mainreconnect_requiredstores and answers the cause that happened (refused on refresh, no refresh token, no client), and none says "expired". The status field help, themarkReconnectRequireddocblock andconnectors.mdxlist all four causes.@objectstack/service-automationpatch,Metadata-protocol: none.domain:spec); the already-marked refusal and theonGrantRefusedlog → automation: a dispatch on a connection already marked reconnect required, and the onGrantRefused log, still say the authorization server refused the grant whatever the stored cause #28963 (domain:server, seat 5).Release: branch
claude/project-thread-xqgh8bmerged; nothing unpushed.pm:dispatchedremoved and the card unassigned.Generated by Claude Code