Mount every external bundle layer as a cordis:contained-group entry `bundle/<package>` whose rows carry a `<package>/<id>` prefix, so one community bundle that no longer loads records a failure in the root `pluginFailures` registry instead of rejecting the whole Loader transaction, and two bundles may declare the same row id. Classify layers by origin (`builtin` for the template bundle and `dsh.profile.firstParty`, `external` for profile dependencies) and let `dsh.bundle.stage: boot` or `dsh.profile.stages` opt a bundle out of isolation when it provides a service built-in rows inject; a built-in row left pending beside an isolated bundle still fails boot and names the bundle. Keep `installFailLoud` for the boot transaction only and install runtime guards afterwards: an unhandled rejection is reported and contained, an uncaught exception is reported and exits. Report nested fiber failures under built-in entries as advisory lines. Provide `ctx.profileRuntime` from the launcher (layers with trust and stage, row origin, user-disabled rows, recomposition through the root include) and probe installed packages in a child process (`probePackage`, cached under `profiles/<name>/.dsh-plugins/`). Split installation from enablement in `reconcileInstalledBundles`; the CLI keeps install-means-enable. The plugin inventory now reports `trust`, `package`, `disabledBy`, and `failure` per row and lists rows only the failure registry knows.
apps/web browser e2e
English | 中文
These tests boot the real web composition in-process and drive it with a real
Chromium over real HTTP. The lane's mechanics — modes, fixtures, goldens, and
the deliberate composition divergences from dsh web — are documented in
scaffold.ts and the
browser e2e Agent Note.
These are Host-face tests
They type-check in the root tsconfig.host.json, not in the Client aggregate,
because they read Host services directly: ctx.connection, the Host
SessionStore, and ctx.sessionProjectionCache. Driving a browser at runtime does
not make a file part of the Client program — the two faces merge cordis
Context under the same keys with different services, so one program cannot see
both. Moving these files into the Client aggregate makes every Host-service
access fail to compile.
Do not import @deepseek-ai/dsh-client-* here
Importing a Client package — a value or a type — pulls its whole TypeScript
project, and every project it references, into the Host build graph. That has
bitten this lane once already: four Client consumer packages reference
api/remotes' Client face, which cannot compile until Host tsdown has generated
@deepseek-ai/dsh-goal/remote, so the Host build phase ended up waiting on an
artifact it produces itself.
When a scenario needs a Client-owned constant or pure function, mirror it here
instead, next to the commented-out import that names the source module. A drift
then surfaces as a missed selector or a stale mirrored value — a loud failure,
never a silent pass. scaffold.ts follows this rule for the welcome-notice
namespace, acknowledgement field, version, and asserted Chinese copy.
One kind of Client import stands. assembled-boot.ts drives the shell itself, so
it imports AppWebEntry from @deepseek-ai/dsh-client-web and the boot-manifest
type from @deepseek-ai/dsh-client-modules/client: booting the real shell is what
that harness is for, and both packages are already in the Host graph. The chat
scenarios mirror conversationContextKey in support.ts instead of importing
its Client owner.
Nothing mechanically enforces this rule; keep it in review.