Filed unassigned from the domain:cli lane while implementing #10943. Recording only — deliberately out of scope there, for a reason named below.
What #10943 changed
createHostImporter(hostRoot, options) now takes the caller's resolution base as options.fallbackImport — the caller's own import(), written in the calling module. Without it the undeclared fallback resolves from @objectstack/types, which under a pnpm-isolated layout sees only @objectstack/spec.
@objectstack/verify (bootStack) and packages/qa/dogfood's enterprise probe pass their base. packages/cli's importFromHost does not.
Why it was left out, and why that is safe TODAY
Every specifier serve routes through importFromHost was measured against packages/cli's own resolution (ESM import.meta.resolve from a probe inside packages/cli):
@objectstack/service-cluster MISS
@objectstack/service-cluster-redis MISS
@objectstack/service-cluster-postgres MISS
@objectstack/service-i18n MISS
@objectstack/organizations MISS
@objectstack/service-ai MISS
@objectstack/service-ai-studio MISS
All seven are app-supplied or cloud-private and resolve from nowhere in the framework workspace, so the fallback base cannot change their outcome either way. The one serve path where the base would matter — an undeclared bare name in plugins: [...] — does not go through the fallback at all: Serve.importConfigPlugin's undeclared branch keeps the CLI's own import() (the local workaround written for #10908), which is exactly the resolution passing a base would produce.
So this is not a live defect. It is the class left open: the next app-declarable load added to serve.ts for a package the CLI does declare (@objectstack/plugin-auth, @objectstack/plugin-audit, chalk — all measured resolvable from packages/cli, none from @objectstack/types) would silently miss the CLI's own dependencies. That is the same shape as #10769: a repair that fixed each instance and left the class open.
Sequencing — why it was not simply done
packages/cli/src/commands/serve.ts was being edited concurrently by the in-flight branch for #10944 (Serve.importConfigPlugin's relative-specifier refusal). #10943's change lands entirely in packages/types, packages/verify and packages/qa/dogfood; adding a fourth edit to the hottest file in that set, for zero measured behaviour change, was refused rather than raced.
Blocked-by:#10944 landing (or being closed), after which this is a two-line edit inside importFromHost:
importer=createHostImporter(hostRoot,{fallbackImport: (specifier)=>import(specifier),});Second half of the same finding: re-read importConfigPlugin
Once serve passes its base, importConfigPlugin's undeclared branch and its re-entry branch become the same call, and the three-branch shape written for #10908 may collapse to two. It was re-read while implementing #10943 and deliberately left intact — its pin (serve-config-plugin-host-resolution.test.ts) still describes real behaviour, and nothing about it was measurably redundant while importFromHost carries no base. Re-read it again with this change, not before.
Not a duplicate
Filed unassigned from the
domain:clilane while implementing #10943. Recording only — deliberately out of scope there, for a reason named below.What #10943 changed
createHostImporter(hostRoot, options)now takes the caller's resolution base asoptions.fallbackImport— the caller's ownimport(), written in the calling module. Without it the undeclared fallback resolves from@objectstack/types, which under a pnpm-isolated layout sees only@objectstack/spec.@objectstack/verify(bootStack) andpackages/qa/dogfood's enterprise probe pass their base.packages/cli'simportFromHostdoes not.Why it was left out, and why that is safe TODAY
Every specifier
serveroutes throughimportFromHostwas measured againstpackages/cli's own resolution (ESMimport.meta.resolvefrom a probe insidepackages/cli):All seven are app-supplied or cloud-private and resolve from nowhere in the framework workspace, so the fallback base cannot change their outcome either way. The one
servepath where the base would matter — an undeclared bare name inplugins: [...]— does not go through the fallback at all:Serve.importConfigPlugin's undeclared branch keeps the CLI's ownimport()(the local workaround written for #10908), which is exactly the resolution passing a base would produce.So this is not a live defect. It is the class left open: the next app-declarable load added to
serve.tsfor a package the CLI does declare (@objectstack/plugin-auth,@objectstack/plugin-audit,chalk— all measured resolvable frompackages/cli, none from@objectstack/types) would silently miss the CLI's own dependencies. That is the same shape as #10769: a repair that fixed each instance and left the class open.Sequencing — why it was not simply done
packages/cli/src/commands/serve.tswas being edited concurrently by the in-flight branch for #10944 (Serve.importConfigPlugin's relative-specifier refusal). #10943's change lands entirely inpackages/types,packages/verifyandpackages/qa/dogfood; adding a fourth edit to the hottest file in that set, for zero measured behaviour change, was refused rather than raced.Blocked-by:#10944 landing (or being closed), after which this is a two-line edit insideimportFromHost:Second half of the same finding: re-read
importConfigPluginOnce
servepasses its base,importConfigPlugin's undeclared branch and its re-entry branch become the same call, and the three-branch shape written for #10908 may collapse to two. It was re-read while implementing #10943 and deliberately left intact — its pin (serve-config-plugin-host-resolution.test.ts) still describes real behaviour, and nothing about it was measurably redundant whileimportFromHostcarries no base. Re-read it again with this change, not before.Not a duplicate
createHostImporter's undeclared fallback resolves from@objectstack/types, not from the calling package — its documented contract says otherwise #10943 is the shared helper's own contract. This is one caller declining to state its base.serve.tscomments claim the capability loop loads "host copy first", but it bare-imports — the CLI's copy always wins #10909 is whether the capability loop should be host-anchored at all — an undecided resolution-policy question over 21 packages, closed as option 1 (comment correction) by docs(cli): correct capability-loop comments — bare import, CLI copy wins (#10909) #10956. This finding proposes no change there.