Conversation
Connections present a red Expired verdict that is either wrong or unrecoverable, and the refresh machinery that produces it is uncoordinated across the surfaces that trigger it. This adds the analysis and the executable repros; it changes no runtime behavior. plans/oauth-refresh-and-expired-status.md ranks eight root causes with file:line evidence and phases the fix. Four are replicated here, each as a pair: a "documents current behavior" test that passes on main (the replication) and a REPRO test asserting the post-fix contract, checked in skipped so the suite stays green and the fix PR un-skips its own anchor. - A refresher that loses a rotation race records a permanent dead grant on a connection whose stored refresh token is valid: every surface then answers expired without probing, and the winner can no longer refresh either. - One transient 4xx from a token endpoint (a 429) ends the grant for good. - The health probe never refreshes reactively, so it persists expired for a credential the next tool call re-mints and heals — the disconnected-then- connected flap. - The MCP liveness probe dials a second connection instead of taking the pooled one, so a single-instance local stdio server fails its own health check while serving tool calls.
The plan document now follows ASD-STE100. Sentences are short. The voice is active. Each term names one concept. A new Terms section defines them. The metaphors are gone. Paragraphs keep normal prose wrapping; a sentence does not start a new paragraph. The technical content does not change. The eight causes keep their R1 to R8 identifiers, their evidence citations, and their rank order. The six phases, the invariants, and the pull request boundaries are the same work.
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Connections show the health status Expired. The status is sometimes wrong. The status is sometimes permanent. This pull request gives the analysis and the tests that show each defect. It does not change runtime behavior.
This pull request is a draft. It gives a diagnosis for review. It does not give a fix. The plan document proposes the fixes in five phases. Each phase has an acceptance test in this pull request.
Files
plans/oauth-refresh-and-expired-status.mdpackages/core/sdk/src/oauth-expired-status-repro.test.tspackages/plugins/mcp/src/sdk/mcp-liveness-second-spawn.test.tspackages/plugins/mcp/src/sdk/stdio-single-instance-test-server.tsTest convention
Each cause has two tests.
The first test shows the behavior on
maintoday. This test passes.The second test gives the required behavior after the fix. This test fails on
main. Therefore the test suite skips it. The pull request that makes the fix removes the skip. The test must then pass without changes.Cause 1: two refreshes at the same time make a valid connection permanently Expired
Test file:
oauth-expired-status-repro.test.ts.Two executor instances use one database and one credential store. Each instance has its own database handle. The cloud app has this shape.
The sequence is:
invalid_grant.The result on
main:oauthReauthRequiredAt. The stored refresh token is valid. The record is wrong.expired. No surface probes the upstream.Cause 2: one temporary HTTP 429 response ends the refresh permanently
Test file:
oauth-expired-status-repro.test.ts.A fixture endpoint answers the first refresh grant with
429 Too Many Requests. The fixture forwards all later grants to the healthy authorization server.The result on
main:expired.Cause 3: the health probe does not refresh before it answers Expired
Test file:
oauth-expired-status-repro.test.ts.The integration has a declared health check. The access token has a long advertised lifetime. The upstream revokes the token.
The result on
main:expired. It sends zero refresh grants.healthyto the same row.Cause 4: the MCP health probe makes a second connection
Test files:
mcp-liveness-second-spawn.test.tsandstdio-single-instance-test-server.ts.checkHealthbuilds a new connector. It does not use the pooled connection that tool calls use. For a stdio server, the probe starts a second child process.The result on
main:degradedfor a live server.Other causes in the plan
The plan gives four more causes. This pull request has no tests for them.
healthyafter it reads the token from the store. It does not contact the upstream.expires_insetsexpires_atto null. Proactive refresh then never runs again.permissionalso reads as Expired.Host scope
Linked issue
None. The plan proposes one issue per phase.
Verification
bun run format:check— all files have the correct format.bun run lint— 0 warnings and 0 errors in 1869 files. The changelog stub check passes.bun run typecheck— I ran the command for the two changed packages. No errors.bun run test— I ran the command for the two changed packages. sdk: 923 passed, 3 skipped, 65 files. plugin-mcp: 311 passed, 30 skipped, 41 files. No existing test changed.Run the tests:
Remove one skip to see that test fail on
main.Checklist
Notes for review
oauth-flow.test.tsalready makes the two-instance race. That test examines the credential store only. It does not examine the connection row. This is the reason nobody found cause 1 before.refreshGateFordocumentation already recommends that coordination.Stack
A fix pull request is stacked on this branch:
The fix pull request is open in the fork, because a stacked pull request needs
its base branch in the same repository, and the base branch exists only in the
fork. After this pull request merges, retarget that one to
UsefulSoftwareCo/executor:main.