# Client panel: why a restart is required The AcFun settings page (`client.js`) is a **static Client module**: the Web carrier turns each package's `dsh.client` declaration into a browser bundle and serves it under `/plugins`. Two facts discovered while installing this bundle into a live session matter for anyone iterating on the panel. ## 1. The bundle is composed from the Loader, not from the filesystem `dsh-client-modules` scans the *live Host Loader entries* for packages declaring `dsh.client` and composes `window.__DSH_BOOT__` from them. A package that is installed while the page is already open does not appear in that graph until the composition is re-run — which happens on Host restart, not on a page refresh. Evidence gathered from the running Host (see `docs/acfun-panel-diagnosis.md` for the raw output): `ctx.clientModules.graph()` listed the ~75 shipped client modules after installing this bundle, and `ctx.clientModules.clientPath( 'dsh-plugin-acfun')` returned `null`. The Host half was fully active at that moment (all twelve tools, `/acfun-panel/state`, QR issuance), so this is a client-composition fact, not a plugin bug. ## 2. Package metadata is cached per Loader specifier until restart The same package declares `dsh.client`, adds `client.js`, and exports `./client`. Those three edits are read when the package is first scanned. In this session the first install happened **before** `client.js` existed, so the cached metadata for `dsh-plugin-acfun` had no client declaration; later reinstalls kept the cached record. ## What this means in practice - Installing this bundle for the first time in a fresh Harness is enough: the next boot composes the panel automatically. - Upgrading a bundle that already declared `dsh.client` only needs a page reload after the Host restart. - When iterating on `client.js`, `plugin_manager action=remove_bundle` + `install_bundle` reloads the Host half, but the panel needs `restart the Harness → reload the page` to appear. ## Verifying without a browser The Host exposes the composition state directly: ``` GET http://127.0.0.1:/acfun-panel/state # client.path GET http://127.0.0.1:/acfun-panel/diagnose # client.entries ``` `path` is non-null only when the carrier registered the bundle. `/diagnose` lists every composed client module id, which is the fastest way to tell "the panel is not composed yet" apart from "the panel crashed while rendering". Slot registration itself is verifiable without a screenshot: `cordis_inspect_query` → `Slots.listSubTree` with `root: "settings.section"` shows the `acfun` occupant once the browser has loaded the module.