# Testing Use Node.js 24.9+. The release gate is: ```bash npm run qa npm run test:web npm pack --dry-run ``` ## DSH compatibility matrix | Host line | Gate | Expected result | | --- | --- | --- | | `0.2.1-rc.5` | Official config forms; reversible Settings DOM adapter; isolated profile and packed-plugin Chromium smoke | Pass | | `0.2.2-alpha.3` | Official config forms and `settings.section.icon`; isolated profile and packed-plugin Chromium smoke | Pass | | DSH 0.1, earlier 0.2 releases, untested future previews | Exact `engines.dsh` and DSH peer contract | Rejected; DSH 0.1 users can retain plugin 0.2.3 | The live browser smoke opens Account menu → Settings → Icons, requires all detected Settings rows to be changeable, writes General → Home through the official form, checks actual nonempty mask pixels, reloads the page to prove Host persistence, and restores automatic selection. It requires no third-party plugins or model. A present but empty `sidebar.footer.action` slot is a supported waiting state; a populated layout that cannot be correlated remains unsupported and untouched. Desktop shares the Web client and Host APIs, but the native Windows/macOS installers, custom-protocol transport and bundled CLI have not been end-to-end qualified here. Browser tests do not establish native Desktop qualification. ### Current isolated smoke Use an empty home and install the Host runtime separately: ```bash npm install --prefix /tmp/dsh-icons-rc5 @deepseek-ai/dsh@0.2.1-rc.5 npm pack --pack-destination /tmp export DSH_HOME=/tmp/dsh-icons-rc5-home /tmp/dsh-icons-rc5/node_modules/.bin/dsh plugin --profile icons-test add /tmp/dsh-icon-theme-0.3.0.tgz /tmp/dsh-icons-rc5/node_modules/.bin/dsh --profile icons-test --no-open --host 127.0.0.1 --port 3184 ``` In another terminal, pass that Host's authenticated URL as `DSH_E2E_URL` (see below). Repeat with `@deepseek-ai/dsh@0.2.2-alpha.3`, a different runtime/home and port 3185. No compatibility exemption is needed. Keep test tokens out of source control. When rebuilding an unpublished version, give its tarball a new filename and verify the installed client hash: pnpm may retain the old contents for a reused file spec. The alpha.3 source tag resolves to `05b1cae8db6e674c5685101494d4eec24652424a`. The smoke changes and clears the General icon; use a dedicated test profile. For process restart persistence, first run with `DSH_E2E_PHASE=seed`, restart that test Host, then run with `DSH_E2E_PHASE=verify`. Seed leaves the override; verify requires it before any write and then clears it. Also disable/re-enable the plugin through that profile's Plugin Manager and check that its page, styles and owned icons disappear and return without duplicates. `DSH_E2E_SCREENSHOT` optionally saves the persisted manual-icon state; `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` selects an installed browser. ### Historical 0.2.3 qualification on `0.1.2-alpha.1` The following record describes the previous plugin release, not the 0.3 contract. Use empty paths for `DSH_ALPHA_ROOT` and `DSH_ALPHA_HOME`, and point `ICON_THEME_ROOT` at this checkout: ```bash export DSH_ALPHA_ROOT=/tmp/deepseek-harness-0.1.2-alpha.1 export DSH_ALPHA_HOME=/tmp/dsh-icon-theme-alpha1-home export ICON_THEME_ROOT=/absolute/path/to/dsh-icon-theme git clone --depth 1 --branch dsh-v0.1.2-alpha.1 https://github.com/deepseek-ai/deepseek-harness.git "$DSH_ALPHA_ROOT" test "$(git -C "$DSH_ALPHA_ROOT" rev-parse HEAD)" = cd5ef8148158c3a752a658978873241fdf8e2bbc pnpm --dir "$DSH_ALPHA_ROOT" install --frozen-lockfile pnpm --dir "$DSH_ALPHA_ROOT" run build npm --prefix "$ICON_THEME_ROOT" ci npm --prefix "$ICON_THEME_ROOT" run qa npm --prefix "$ICON_THEME_ROOT" pack --pack-destination /tmp DSH_HOME="$DSH_ALPHA_HOME" pnpm --dir "$DSH_ALPHA_ROOT" dsh plugin --profile web add /tmp/dsh-icon-theme-0.2.3.tgz DSH_HOME="$DSH_ALPHA_HOME" pnpm --dir "$DSH_ALPHA_ROOT" dsh web --no-open --port 3182 ``` Observed on 2026-08-30 with the packed dependency recorded as `file:/tmp/dsh-icon-theme-0.2.3.tgz`: the Host identified itself as `0.1.2-alpha.1-cd5ef81`; Icons reported pack 121, detected 6, Settings active and changeable 5/5, and the empty sidebar action slot as waiting 0/1. Changing General to Home produced one owned glyph with icon ID `home`, survived a full page reload, and reset to automatic. All observed dynamic requests returned HTTP 200 and the browser console had zero warnings and zero errors. ## Layers 1. **Config and catalog** — volatile Host fields, normalized defaults and rejected malformed overrides; every SVG is unique, local, monochrome, safe, 16 px, and attributed. 2. **Resolution** — table-driven tests lock manual, plugin, original, preset, inference, and fallback priority. Localized labels are explicitly excluded. 3. **DOM contracts** — jsdom covers delayed mount, host rerender, ledger/DOM mismatch, look-alike/ambiguous dialogs, in-place child and compatibility attribute replacement, iconless rows, multi-root contributions, and complete disposal. A first-open mismatch retries on a bounded burst and on tab visibility even when the slot ledger catches up without another DOM mutation. It also proves unrelated streaming DOM mutations do not rescan the sidebar. 4. **Store and UI** — stable-key writes, user-layer clearing, both surfaces, icon picking, live source changes, filtering, and reset behavior. 5. **Lifecycle and build** — fake DSH context verifies registrations, subscriptions, observers, styles, and markers are owned and released. 6. **Official forms and icons** — shared form snapshots, receiver-preserving calls, readonly/unavailable/refused writes, transport errors, rollback and provider-driven reconnect refresh. A real SlotCore ledger checks original providers, manual priority, late contributions, owner size, declaration collapse/recreation, DOM fallback switching and disposal. Production types use the public SlotRegistry API. 7. **Ecosystem fixtures** — registrations pinned from five open-source plugins include immutable source blob IDs and prove generic discovery of an unknown Settings section, safe gear fallback, manual override, and non-interference with unrelated slot surfaces. 8. **Browser fixture** — real Chromium and React execute the produced `window.__ModuleLoader__` artifact, mount the complete settings component, inspect all 121 picker items, write a manual choice through a shared-form double, confirm non-empty mask pixels, and restore original SVGs on disposal. 9. **Real DSH smoke** — after local installation, run: ```bash DSH_E2E_URL='http://127.0.0.1:3184/?token=TEST_PROFILE_TOKEN' npm run test:web -- -t @real-dsh ``` The test verifies General → Home on both supported Host versions, waits for the official Host write, reloads the page, then resets and verifies the reset after another reload. Console errors and page errors fail the test. ## Regression requirements Any new supported surface needs a fail-closed mismatch test and a disposal test. Any new icon needs catalog generation, license metadata, semantic aliases, and the invariant suite. Any new exact plugin adapter needs a repository/license reference and evidence that the asset is a navigation icon rather than a logo, banner, screenshot, or favicon.