When configuration behavior changes (new keys, renamed/repurposed toggles, UI pickers, feature-gates), ensure user intent is preserved and avoid unsafe process-wide environment side effects.
Guidelines: 1) Preserve backward compatibility
2) Keep schema-driven configuration reachable in the UI
3) Avoid global process.env as a workaround
process.env can affect other extensions/features indirectly.afterEach) to prevent leakage.Example (compatibility migration pattern):
function readSandboxEnabled(config: IConfigurationService, log: ILogService): boolean {
// New key
const newEnabled = config.getValue<boolean>('chat.agent.sandbox.enabled');
// Legacy key (explicit user opt-in)
const legacy = config.getValue<boolean>('chat.agentHost.sdkSandbox.enabled');
// Compatibility rule: use explicit new value if set; otherwise fall back to legacy.
// (Implementation detail: treat `undefined` as “not explicitly set”.)
if (newEnabled !== undefined) {
return newEnabled;
}
if (legacy !== undefined) {
log.debug('[Sandbox] Migrating legacy opt-in to new key');
return legacy;
}
// Final default
return false;
}
Example (env cleanup in tests):
afterEach(() => {
delete process.env['COPILOT_API_URL'];
});
Applying this standard prevents silent behavior regressions after upgrades, ensures configuration is actually controllable by users, and reduces risk from hidden cross-feature coupling via process.env.