fix(review): label host-preparation failures and gate vendored lockfile links
ds-review-bot round 1: boot() now throws `host preparation failed` when prepare() rejects before any config-tree entry mounts (the plugin-tree label overstated), and the new hygiene gate verify-vendored-links pins the linkWorkspacePackages fix — every vendored package name in pnpm-lock.yaml must resolve to a workspace link with no registry copy alongside.
This commit is contained in:
@@ -445,7 +445,9 @@ export async function assertEntriesActivated(ctx: Context, binName: string): Pro
|
||||
* @param prepare - optional host setup run after Loader installation and before any config-tree entry mounts.
|
||||
* @returns the root context once every entry has started, or as soon as a
|
||||
* surface disposed the tree while startup was still in flight.
|
||||
* @throws a labelled load error after disposing the partial context.
|
||||
* @throws a labelled error after disposing the partial context — `host
|
||||
* preparation failed` when `prepare` threw before any config-tree entry
|
||||
* mounted, `plugin tree failed to load` afterwards.
|
||||
*/
|
||||
export async function boot(
|
||||
binName: string,
|
||||
@@ -454,12 +456,16 @@ export async function boot(
|
||||
prepare?: (ctx: Context) => Promise<void> | void,
|
||||
): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
// Two failure labels: `prepare` runs before any config-tree entry mounts,
|
||||
// so its failure is host setup, not the plugin tree.
|
||||
let stage = 'host preparation failed'
|
||||
try {
|
||||
ctx.baseUrl = pathToFileURL(dirname(absoluteConfigPath)).href + '/'
|
||||
ctx.provide('dshHomePath', dshHomePath)
|
||||
await ctx.plugin(Loader)
|
||||
ctx.loader.builtins.include = Include
|
||||
await prepare?.(ctx)
|
||||
stage = 'plugin tree failed to load'
|
||||
// Pinned id: the bootstrap include is app glue, not a config row, and its
|
||||
// id appears in Loader failure chains — a random id would make startup
|
||||
// diagnostics unstable across runs (and snapshot fixtures).
|
||||
@@ -485,6 +491,9 @@ export async function boot(
|
||||
await assertEntriesActivated(ctx, binName)
|
||||
return ctx
|
||||
} catch (cause) {
|
||||
// Root-fiber disposal contains cleanup failures per observer (Cordis
|
||||
// fiber.ts hardening) and a repeated call returns the settled single-shot
|
||||
// result, so this await cannot reject and replace `cause`.
|
||||
await ctx.fiber.dispose()
|
||||
const detail = cause instanceof Error ? cause.message : String(cause)
|
||||
// The transactional Loader wraps a failing entry apply in one message per
|
||||
@@ -495,7 +504,7 @@ export async function boot(
|
||||
let deepest: unknown = cause
|
||||
while (deepest instanceof Error && deepest.cause !== undefined) deepest = deepest.cause
|
||||
const stack = deepest instanceof Error && deepest !== cause ? `\n${deepest.stack ?? deepest.message}` : ''
|
||||
throw new Error(`${binName}: plugin tree failed to load: ${detail}${stack}`, { cause })
|
||||
throw new Error(`${binName}: ${stage}: ${detail}${stack}`, { cause })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ describe('boot', () => {
|
||||
})
|
||||
|
||||
await expect(task).rejects.toMatchObject({
|
||||
message: `${NAME}: plugin tree failed to load: ${failure}`,
|
||||
message: `${NAME}: host preparation failed: ${failure}`,
|
||||
cause: failure,
|
||||
})
|
||||
expect(disposed).toBe(true)
|
||||
@@ -418,9 +418,9 @@ describe('boot', () => {
|
||||
const deepest = new Error('stackless deep failure')
|
||||
delete (deepest as { stack?: string }).stack
|
||||
await expect(boot(NAME, join(dir, 'cordis.yml'), undefined, () => {
|
||||
throw new Error('host preparation failed', { cause: deepest })
|
||||
throw new Error('wrapped setup failure', { cause: deepest })
|
||||
})).rejects.toThrow(
|
||||
`${NAME}: plugin tree failed to load: host preparation failed\nstackless deep failure`,
|
||||
`${NAME}: host preparation failed: wrapped setup failure\nstackless deep failure`,
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user