Skip to content

Commit 5ec993b

Browse files
cameroncookesoharaa
andcommitted
fix(runtime): Separate MCP hydration and refresh scheduling state
Return explicit hydration status so bootstrap logging reflects what happened. Log hydration even when background simulator refresh is not scheduled. Also remove a trivial simulator selector pass-through in infer-platform to reduce indirection, and add coverage for scheme-only defaults. Refs #206 Co-Authored-By: Codex <noreply@openai.com>
1 parent 7d0fe2c commit 5ec993b

File tree

3 files changed

+57
-18
lines changed

3 files changed

+57
-18
lines changed

src/runtime/__tests__/bootstrap-runtime.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ function createFsWithSessionDefaults() {
2929
});
3030
}
3131

32+
function createFsWithSchemeOnlySessionDefaults() {
33+
const yaml = ['schemaVersion: 1', 'sessionDefaults:', ' scheme: "AppScheme"', ''].join('\n');
34+
35+
return createMockFileSystemExecutor({
36+
existsSync: (targetPath: string) => targetPath === configPath,
37+
readFile: async (targetPath: string) => {
38+
if (targetPath !== configPath) {
39+
throw new Error(`Unexpected readFile path: ${targetPath}`);
40+
}
41+
return yaml;
42+
},
43+
});
44+
}
45+
3246
describe('bootstrapRuntime', () => {
3347
beforeEach(() => {
3448
__resetConfigStoreForTests();
@@ -50,6 +64,21 @@ describe('bootstrapRuntime', () => {
5064
});
5165
});
5266

67+
it('hydrates non-simulator session defaults for mcp runtime', async () => {
68+
const result = await bootstrapRuntime({
69+
runtime: 'mcp',
70+
cwd,
71+
fs: createFsWithSchemeOnlySessionDefaults(),
72+
});
73+
74+
expect(result.runtime.config.sessionDefaults?.scheme).toBe('AppScheme');
75+
expect(sessionStore.getAll()).toMatchObject({
76+
scheme: 'AppScheme',
77+
});
78+
expect(sessionStore.getAll().simulatorId).toBeUndefined();
79+
expect(sessionStore.getAll().simulatorName).toBeUndefined();
80+
});
81+
5382
it.each(['cli', 'daemon'] as const)(
5483
'does not hydrate session defaults for %s runtime',
5584
async (runtime: RuntimeKind) => {

src/runtime/bootstrap-runtime.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,34 @@ export interface BootstrapRuntimeResult {
3333
notices: string[];
3434
}
3535

36+
interface MCPSessionHydrationResult {
37+
hydrated: boolean;
38+
refreshScheduled: boolean;
39+
}
40+
3641
/**
37-
* Returns true when defaults were hydrated and a background simulator refresh was scheduled.
42+
* Hydrates MCP session defaults and reports whether a background simulator refresh was scheduled.
3843
*/
39-
function hydrateSessionDefaultsForMcp(defaults: Partial<SessionDefaults> | undefined): boolean {
44+
function hydrateSessionDefaultsForMcp(
45+
defaults: Partial<SessionDefaults> | undefined,
46+
): MCPSessionHydrationResult {
4047
const hydratedDefaults = { ...(defaults ?? {}) };
4148
if (Object.keys(hydratedDefaults).length === 0) {
42-
return false;
49+
return { hydrated: false, refreshScheduled: false };
4350
}
4451

4552
sessionStore.setDefaults(hydratedDefaults);
4653
const revision = sessionStore.getRevision();
47-
return scheduleSimulatorDefaultsRefresh({
54+
const refreshScheduled = scheduleSimulatorDefaultsRefresh({
4855
expectedRevision: revision,
4956
reason: 'startup-hydration',
5057
persist: true,
5158
simulatorId: hydratedDefaults.simulatorId,
5259
simulatorName: hydratedDefaults.simulatorName,
5360
recomputePlatform: true,
5461
});
62+
63+
return { hydrated: true, refreshScheduled };
5564
}
5665

5766
export async function bootstrapRuntime(
@@ -75,8 +84,16 @@ export async function bootstrapRuntime(
7584

7685
const config = getConfig();
7786

78-
if (opts.runtime === 'mcp' && hydrateSessionDefaultsForMcp(config.sessionDefaults)) {
79-
log('info', '[Session] Hydrated MCP session defaults; simulator metadata refresh scheduled.');
87+
if (opts.runtime === 'mcp') {
88+
const hydration = hydrateSessionDefaultsForMcp(config.sessionDefaults);
89+
if (hydration.hydrated && hydration.refreshScheduled) {
90+
log('info', '[Session] Hydrated MCP session defaults; simulator metadata refresh scheduled.');
91+
} else if (hydration.hydrated) {
92+
log(
93+
'info',
94+
'[Session] Hydrated MCP session defaults; simulator metadata refresh not scheduled.',
95+
);
96+
}
8097
}
8198

8299
return {

src/utils/infer-platform.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,6 @@ function inferSimulatorSelectorForTool(params: {
110110
return {};
111111
}
112112

113-
function resolveSimulatorsFromSession(params: InferPlatformParams): {
114-
simulatorId?: string;
115-
simulatorName?: string;
116-
} {
117-
return inferSimulatorSelectorForTool({
118-
simulatorId: params.simulatorId,
119-
simulatorName: params.simulatorName,
120-
sessionDefaults: params.sessionDefaults,
121-
});
122-
}
123-
124113
function resolveCachedPlatform(params: InferPlatformParams): SimulatorPlatform | null {
125114
const defaults = params.sessionDefaults ?? sessionStore.getAll();
126115
if (!isSimulatorPlatform(defaults.simulatorPlatform)) {
@@ -246,7 +235,11 @@ export async function inferPlatform(
246235
return { platform: cachedPlatform, source: 'simulator-platform-cache' };
247236
}
248237

249-
const { simulatorId, simulatorName } = resolveSimulatorsFromSession(params);
238+
const { simulatorId, simulatorName } = inferSimulatorSelectorForTool({
239+
simulatorId: params.simulatorId,
240+
simulatorName: params.simulatorName,
241+
sessionDefaults: params.sessionDefaults,
242+
});
250243

251244
let simulatorIdForLookup = simulatorId;
252245
let simulatorNameForLookup = simulatorName;

0 commit comments

Comments
 (0)