Skip to content

serve.ts's importFromHost does not pass its own resolution base to createHostImporter — measured harmless today, open by construction #11157

Description

@os-elon

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

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions