Repair session info on demand + fix callTool token reconcile - #184
Repair session info on demand + fix callTool token reconcile#184rohitthughtspot wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a lazy session info repair mechanism (ensureSessionInfo) to handle cases where the initial, init-time getSessionInfo call fails due to an expired token. This ensures that subsequent tool list and call requests can repair the session info using the kept-warm token. Feedback on these changes highlights two key issues: first, when sessionInfo is repaired on-demand, the active org initialization logic does not run, leaving the session unscoped to the user's default active org; second, concurrent calls to ensureSessionInfo can cause race conditions and duplicate trackers, which should be guarded against using a promise.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // Repair session info if the init-time fetch failed, so the org-tools gate | ||
| // below (and getActiveToken's token selection) act on the real state. | ||
| await this.ensureSessionInfo(); |
There was a problem hiding this comment.
If the init-time getSessionInfo fails (e.g., due to an expired token), postInit() skips defaulting this.activeOrgId to this.sessionInfo.currentOrgId. When ensureSessionInfo() later repairs this.sessionInfo during a tool call, this.activeOrgId remains undefined because the default active org initialization logic only ran in postInit(). This means the session will continue to run without being scoped to the user's default active org (no x-thoughtspot-orgs header or org-scoped token), which can lead to data discrepancies or errors. We should run the active org initialization logic inline when sessionInfo is repaired.
// Repair session info if the init-time fetch failed, so the org-tools gate
// below (and getActiveToken's token selection) act on the real state.
const hadSessionInfo = !!this.sessionInfo;
await this.ensureSessionInfo();
if (!hadSessionInfo && this.sessionInfo && this.areOrgToolsAvailable()) {
await this.loadActiveOrg();
if (!this.activeOrgId) {
const currentOrgId =
this.sessionInfo.currentOrgId != null
? String(this.sessionInfo.currentOrgId)
: undefined;
if (currentOrgId) {
this.activeOrgId = currentOrgId;
}
}
if (this.activeOrgId && !this.activeOrgToken) {
try {
await this.forceRecreateActiveOrgToken(recorder);
} catch (error) {
console.error("Failed to mint active org token after repair:", error);
}
}
}dd7b41e to
a66d443
Compare
|
@copilot review pr |
Reviewed the PR changes and I don’t see any high-signal bugs or security issues to address right now. CI is currently green on the latest pull_request run; earlier failures on this branch were from a transient Coveralls 504 error. |
9979b41 to
72b2681
Compare
… getSessionInfo sessionInfo is fetched once at init via getSessionInfo(). Previously that ran before the keep-warm global token was reconciled from the token-store DO, so on a cold-start reconnect after the frozen props access token expired (~24h), getSessionInfo authenticated with the dead token, failed, and left sessionInfo null for the DO's lifetime — silently hiding list_orgs/switch_org and mis-gating datasource discovery, even though the DO held a valid kept-warm token (data tool calls, which reconcile the DO token at call time, kept working). - Reorder (primary fix): add a preInit() hook that runs before initializeService(), and move MCPServer's global-token reconcile there (out of postInit's top). getSessionInfo now authenticates with the kept-warm DO token on the first try, so sessionInfo is populated correctly at init. - ensureSessionInfo() safety net in listTools: if init's getSessionInfo still failed (e.g. a transient error) and sessionInfo is null, refetch on demand so the advertised org-tool list reflects the real cluster state. No-op once populated; guarded by an in-flight promise so concurrent list calls share one fetch (no duplicate getSessionInfo or MixpanelTracker). - isOrgsEnabled() defaults to true when sessionInfo is absent, so org tools stay visible in the narrow window before the refetch completes. - callTool: reconcile the global token per call keyed on the absence of an active org token, so a data call always gets a fresh global token when no org token drives it. - Extract postInit's active-org bootstrap into ensureActiveOrg(). - Drop the [DEBUG] console.warn in isDatasourceDiscoveryAvailable (log noise). Tests: init succeeds via the warm token (reorder), the concurrency guard coalesces concurrent refetches, and existing suites pass (635). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72b2681 to
491b6bf
Compare
…repair-184 # Conflicts: # src/servers/mcp-server-base.ts # test/servers/mcp-server-base.spec.ts
Problem
After a cold-start reconnect (~24h, once the frozen props access token has expired),
list_orgs/switch_orgdisappear and datasource-discovery gating breaks — even though the keep-warm token is valid.Cause
sessionInfois fetched once at init viagetSessionInfo(), which runs beforepostInitreconciles the keep-warm global token from the DO. On that reconnect the fetch authenticates with the dead frozen props token, fails, and leavessessionInfonull for the instance lifetime. Org-tool visibility and datasource gating readsessionInfo, so they mis-gate — while the DO still holds a valid token (data tool calls, which reconcile it at call time, keep working).Fix
ensureSessionInfo()— refetch session info when it's null, called at the top oflistTools()/callTool(). By thenpostInithas loaded the kept-warm token, so the refetch authenticates with it. No-op (no network call) once populated — happy path unaffected.callToolper-call reconcile keyed on!this.activeOrgToken— so a data call always gets a freshly reconciled global token when no org token drives it (covers non-orgs clusters and the no-active-org case).Test
Regression test reproduces the failure (init
getSessionInfofails on an expired props token; DO holds a valid token) and asserts the repair restoressessionInfoand the org tools. Verified it fails without the fix. Server suites pass.🤖 Generated with Claude Code