Summary
The envelope reports project.root and project.boardYaml but not the SDK root tan actually used. With #101's walk-up discovery landing, that becomes the one fact the IDE cannot recover — and the one it needs to warn a customer that their build came from an SDK they never selected.
Evidence
The whole project object, alp-sdk-vscode at 9dda95a, src/alpCli/models.ts:12:
project: { root: string | null; boardYaml: string | null };
The extension passes --sdk-root conditionally — src/alpCli/vscodeAdapter.ts, withSdkRoot:
function withSdkRoot(args: string[]): string[] {
if (args.includes("--sdk-root")) return args;
const sdkRoot = collectProjectContext().sdkRoot;
if (!sdkRoot) {
log(
"[cli] no active SDK resolved — running without --sdk-root; tan will " +
"discover an SDK from the working directory (0.4.0+ searches parent " +
"directories too, so it may pick an enclosing checkout). Set alpSdk.path " +
"to pin one.",
);
return args;
So on the unpinned path — which is the first-run path, before any SDK is selected — tan chooses, and from 0.4.0 it may choose an ancestor checkout. The extension has no way to learn which. Every downstream result (validation, generation, the build plan, the doctor report) then silently comes from an SDK the customer never picked, and the IDE cannot say so because it does not know.
Ask
Add the resolved SDK root to the envelope, e.g.:
Any stable field name is fine — what matters is that it reports what tan used, not what it was told, so it is meaningful on both the pinned and the discovered path.
Why this is a tan change and not an extension one
The obvious workaround is to mirror tan's discovery rule in TypeScript so the IDE can compute the same answer. That is exactly what should not happen: two implementations of one rule drift, and the copy would be wrong the first time tan's discovery changed — which is #101 itself. The extension is deliberately thin and must read tan's answer rather than compute a competing one. Without this field there is no third option; the log line above is the honest best the extension can do, and a log line is not something a customer reads.
Context
Found while making alp-sdk-vscode ready for v0.4.0 (PR #372, merged). Related: #101 (the walk-up), #106 (freezing the envelope's field names — this adds one worth freezing with them).
Summary
The envelope reports
project.rootandproject.boardYamlbut not the SDK root tan actually used. With #101's walk-up discovery landing, that becomes the one fact the IDE cannot recover — and the one it needs to warn a customer that their build came from an SDK they never selected.Evidence
The whole
projectobject,alp-sdk-vscodeat9dda95a,src/alpCli/models.ts:12:The extension passes
--sdk-rootconditionally —src/alpCli/vscodeAdapter.ts,withSdkRoot:So on the unpinned path — which is the first-run path, before any SDK is selected — tan chooses, and from 0.4.0 it may choose an ancestor checkout. The extension has no way to learn which. Every downstream result (validation, generation, the build plan, the doctor report) then silently comes from an SDK the customer never picked, and the IDE cannot say so because it does not know.
Ask
Add the resolved SDK root to the envelope, e.g.:
Any stable field name is fine — what matters is that it reports what tan used, not what it was told, so it is meaningful on both the pinned and the discovered path.
Why this is a tan change and not an extension one
The obvious workaround is to mirror tan's discovery rule in TypeScript so the IDE can compute the same answer. That is exactly what should not happen: two implementations of one rule drift, and the copy would be wrong the first time tan's discovery changed — which is #101 itself. The extension is deliberately thin and must read tan's answer rather than compute a competing one. Without this field there is no third option; the log line above is the honest best the extension can do, and a log line is not something a customer reads.
Context
Found while making
alp-sdk-vscodeready for v0.4.0 (PR #372, merged). Related: #101 (the walk-up), #106 (freezing the envelope's field names — this adds one worth freezing with them).