Skip to content

Port experimentation service and reporting to extension#3675

Merged
DanielRosenwasser merged 12 commits intomainfrom
experimentation
May 1, 2026
Merged

Port experimentation service and reporting to extension#3675
DanielRosenwasser merged 12 commits intomainfrom
experimentation

Conversation

@DanielRosenwasser
Copy link
Copy Markdown
Member

No description provided.

Comment thread _extension/package.json
"@vscode/extension-telemetry": "^1.5.1",
"vscode-languageclient": "^10.0.0-next.21"
"vscode-languageclient": "^10.0.0-next.21",
"vscode-tas-client": "0.1.84"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locked on 0.1.84 because of microsoft/tas-client#95

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports VS Code TAS (experimentation) plumbing into the native-preview VS Code extension so telemetry can include shared experimentation context (flights/treatments) and the extension can query treatment variables.

Changes:

  • Add vscode-tas-client dependency and wire experimentation telemetry into the existing telemetry reporter.
  • Introduce an ExperimentationService wrapper plus a helper to read extension package name/version for TAS initialization.
  • Update extension activation to construct the experimentation service during startup; add a new _extension/pnpm-lock.yaml.
Show a summary per file
File Description
package-lock.json Adds vscode-tas-client (and transitive tas-client) to the workspace lockfile.
_extension/package.json Declares vscode-tas-client dependency for the extension workspace.
_extension/pnpm-lock.yaml Adds a pnpm lockfile for the extension workspace.
_extension/tsconfig.json Changes TS module setting to preserve for the extension project.
_extension/src/util.ts Adds getPackageInfo helper for extension id/version discovery.
_extension/src/telemetryReporting.ts Extends the telemetry reporter to implement IExperimentationTelemetry and inject shared properties.
_extension/src/extension.ts Instantiates ExperimentationService during activation.
_extension/src/experimentationService.ts New TAS experimentation service wrapper and initialization logic.
_extension/src/commands.ts Removes an unused import.

Copilot's findings

Files not reviewed (1)
  • _extension/pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

_extension/src/experimentationService.ts:62

  • createTasExperimentationService awaits experimentationService.initialFetch and will reject if the fetch fails. Since ExperimentationService constructs this promise without attaching a rejection handler (and activate doesn't await it), this can trigger an unhandled promise rejection during activation. Consider catching/logging fetch errors inside createTasExperimentationService (or in the constructor) and returning a usable service that falls back gracefully.
    const experimentationService = tas.getExperimentationService(id, version, targetPopulation, reporter, globalState);
    await experimentationService.initialFetch;
    return experimentationService;
  • Files reviewed: 7/9 changed files
  • Comments generated: 4

Comment on lines +23 to +31
public async getTreatmentVariable<K extends keyof ExperimentTypes>(name: K, defaultValue: ExperimentTypes[K]): Promise<ExperimentTypes[K]> {
const experimentationService = await this._experimentationServicePromise;
try {
const treatmentVariable = await experimentationService.getTreatmentVariableAsync("vscode", name, /*checkCache*/ true) as ExperimentTypes[K];
return treatmentVariable ?? defaultValue;
}
catch {
return defaultValue;
}
Comment thread _extension/src/extension.ts Outdated
Comment on lines +35 to +41
const packageInfo = getPackageInfo(context);
if (packageInfo) {
const { name: id, version } = packageInfo;
// Constructing the experimentation service actually sets shared properties
// so that events include context on treatments/flights.
const _expService = new ExperimentationService(telemetryReporter, id, version, context.globalState);
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now this is fine, we are just using this to stamp common properties like the assignment context. I could just void it.

Comment thread _extension/pnpm-lock.yaml Outdated
Comment thread _extension/src/telemetryReporting.ts Outdated
This blocks actually constructing the service which basically delays extension loads.

Our `getTreatmentVariable` calls `getTreatmentVariableAsync`, which calls their `getFeaturesAsync` and actually resolves the initial fetch.
Comment thread _extension/tsconfig.json Outdated
"compilerOptions": {
"target": "es2023",
"module": "NodeNext",
"module": "preserve",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we bundle, so maybe this should be bundler mode?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't think I needed to make this change. I might undo it.

Though I think that preserve implies bundler, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only bundle now

Comment thread _extension/src/commands.ts
Comment thread _extension/src/experimentationService.ts Outdated
Comment thread _extension/src/extension.ts Outdated

const packageInfo = getPackageInfo(context);
if (packageInfo) {
const { name: id, version } = packageInfo;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not just context.extension.id?

Copy link
Copy Markdown
Member Author

@DanielRosenwasser DanielRosenwasser May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, name is native-preview, context.extension.id would be TypeScriptTeam.native-preview

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well right, but surely the exp platform wants more of a name than native-preview?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right and I think that the built-in extension was doing this wrong.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, because builtin extensions don't have a publisher name and that's how they are determined to be builtins

@DanielRosenwasser DanielRosenwasser added this pull request to the merge queue May 1, 2026
Merged via the queue into main with commit 6dff52f May 1, 2026
21 checks passed
@DanielRosenwasser DanielRosenwasser deleted the experimentation branch May 1, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants