# Development verification
[简体中文](TESTING.md)
This guide explains how to verify the current implementation; it does not record acceptance results for a particular release. Select checks by change scope, then add integration evidence for the affected DSH interfaces.
Run admission and standard Host checks against both rc.2 and rc.3 dependency roots. Future RC and final-release values in range tests exercise policy, not those runtimes. Web acceptance also covers opening and unpinning RP / Trace entries folded into More in narrow windows, session switching, returning to blank drafts and restoration after removal.
## 3.1.5 compatibility
Tavern 3.1.5 and independent Standard Assembler 1.1.3 admit Hosts in `>=0.2.1-rc.2 <0.2.2-0`. Target official runtimes are [rc.2](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.2) (`687f282e8625c6b8d11ff58211a90524be2e4317`) and [rc.3](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.3) (`1f81c047fc48fa190a683e469daa699857e9afe8`). Required peers are Cordis `4.0.5`, DSH crypto in the same range, and Assembler `~1.1.3`. Install and enable Assembler as an independent profile component. Later 0.2.1 RCs and the final release are admitted by policy, not a claim of prior validation; reassess 0.2.2 and its prereleases.
Backend scope covers plugin admission, public Session/Workspace controllers, prompt assembly and parameter fallback, V4 history and historical reference migration, Trace, and the [operation log contract](OPERATION_LOGS_en.md). Existing V4 references need no new conversion. The migration codec allowlist is separate from runtime support; see [migration](DSH_0.1.7_MIGRATION_en.md).
Use both compatibility-root variables below for real official-module tests, including `test/plugin-runtime-compatibility.test.mjs`. In a separate temporary DSH_HOME, install and start the target Web Host, then verify create, prompt acknowledgement, complete history and Trace reads, and a historical fork with queued/steering source input. The child queues must be empty, the source unchanged by branching, and old input absent from the child's next model request. Normal DSH shutdown cancels remaining inbox items with durable canceled splices; do not treat this native shutdown behavior as a Tavern branch mutation. Inject a workspace attachment failure after real create/fork to verify HTTP 409, one creation checkpoint with the new identity, and a correlated terminal failure. Restart the Host to check cold history/Trace reads, persistent journal records and a changed runId. Record source, runtime and synthetic-provider evidence under `.local/`.
Frontend, backend and operation logs must be verified together. Run the presentation, rich-text and log-panel browser fixtures, then check the integrated target Web/Desktop Host: RP/native switching, avatars and bubble settings, request-token refresh after restart, correlated errors and log queries/export. Panel fixtures alone do not establish complete Host UI acceptance; record real-provider and third-party coverage separately.
## Environment and commands
Standalone Tavern tests require Node.js `>=20`; the target DSH `0.2.1-rc.2` / `0.2.1-rc.3` requires Node.js `^22.19.0 || >=24.0.0`. Use the latter requirement when running real DSH modules or a Host, and verify the versions of the core packages actually resolved. The standalone CI matrix does not establish support for every DSH runtime.
Run `npm ci --legacy-peer-deps` at the repository root to install locked dependencies, then run these commands. [package.json](../package.json) is the command definition source. The development lockfile pins an Assembler GitHub source archive and includes official `@deepseek-ai/dsh-llm` `0.2.1-rc.2` for tests. The target DSH supplies official peers at runtime; the user installs and enables independent Assembler.
| Change scope | Check |
| --- | --- |
| Documentation only | Check content, bilingual parity, relative links, and diff; no build required |
| Localized logic | `node --test test/.test.mjs` |
| Cross-module behavior | `npm test` |
| Client bundle | Relevant tests and `npm run build`; `dist/client.js` is generated |
| Full build and tests | `npm run check` |
| Protocol, installation, packaging, or release preparation | `npm run verify:2.0`, plus affected runtime checks |
`npm test` discovers tests through the Node test runner; `check` builds before running them. `verify:2.0` retains its historical command name: it runs the [listed test groups](../scripts/verify-2.0.mjs), then builds and runs `npm pack --dry-run`. It is not the full test suite and does not start a Web Host or browser.
## Patch release documentation
Use a patch version for compatible bug fixes; documentation corrections alone do not require a version bump. Release preparation must deliver a candidate with final versions, changelog, bilingual documentation, and installation examples, ready to publish immediately after review. Do not leave preparation status, unreleased labels, or old-version installation placeholders in candidate documentation; record pending review/publication in the handoff and `.local/`. Revise or roll back the candidate if review finds issues. Align the package version, Git tag, GitHub Release, and pinned installation examples. Never move or overwrite a published tag. Push completed, locally validated commits under the standing repository authorization in AGENTS.md; tags and releases require explicit authorization.
| File or release item | When to update |
| --- | --- |
| Root `package.json` and `package-lock.json` | Synchronize versions during release preparation; no bump for documentation-only changes |
| Root [CHANGELOG.md](../CHANGELOG.md) | Record the final version, fix, user impact, and compatibility limits in the candidate; do not invent a publication date |
| Chinese and English README and INSTALLATION | Synchronize the final version in the candidate, switch install and source-checkout examples to the intended tag, and state the target DSH and migration requirements |
| Chinese and English API and USAGE | Update changed interface behavior, error codes, or user-visible results; internal fixes with an unchanged contract need no edits |
| Chinese and English TESTING | Add reusable regression scenarios or verification methods when needed |
| Architecture, migration, security documents and diagrams | Check target versions, migration allowlists, the maintained security line and diagram source revisions; rewrite behavior descriptions only when the design, data format or security boundary changes |
| Git tag and GitHub Release | At publication, create the matching tag and concise release notes covering the fix, target DSH, upgrade steps, and known limits |
Before publication, check both READMEs’ versions and update summaries, install commands, the SECURITY maintenance line, migration allowlists, API impact notes, and the versions/source revisions in diagram sources and generated pages. Older version numbers should occur only in change history or supported migration guidance. After pushing, read both READMEs from GitHub’s default branch and target tag and confirm they match the accepted commit before publishing the Release.
Keep run-specific logs, screenshots, test counts, and release-note drafts in Git-ignored `.local/`; summarize relevant evidence in the PR. Keep reusable procedures in `docs/`, without accumulating per-release acceptance records. Update corresponding Chinese and English files in the same change.
Run `npm run verify:2.0` and inspect package contents before release; validate affected APIs, Host behavior, and UI as described here. Later documentation or version-metadata changes can reuse runtime evidence for the same implementation and target DSH, identifying the tested commit, without repeating unrelated interactions. New DSH compatibility requires fresh verification; old Host results do not establish support.
## Enable integration tests with official modules
Both variables point to directories from which Node can resolve the target DSH dependencies. Tests use `package.json` under each directory as the resolution base. These paths are neither `DSH_HOME` nor an RP workspace.
| Variable | Required modules and coverage |
| --- | --- |
| `DSH_TAVERN_COMPAT_ROOT` | Session format/catalog, migration packages, and session controller; real codecs, migration of temporary logs, and official error mapping |
| `DSH_TAVERN_PROMPT_COMPAT_ROOT` | Cordis, AppBoot, SystemPrompt, Session, AgentLoop, LLM, and other Host modules; official plugin version admission, assembly, request observation, event references, and failure attribution |
An installed DSH distribution can usually use one root for both. A source checkout may resolve these dependencies from different directories; tests do not search `apps/cli` or other workspaces automatically. This POSIX shell example uses placeholder dependency paths. In PowerShell, set the same variables using `$env:VARIABLE_NAME`.
```sh
export DSH_TAVERN_COMPAT_ROOT="/path/to/dsh-dependencies"
export DSH_TAVERN_PROMPT_COMPAT_ROOT="/path/to/dsh-host-dependencies"
npm run check
npm run verify:2.0
```
For targeted checks:
```sh
node --test test/coordinate-migration-integration.test.mjs test/session-coordinates.test.mjs
node --test test/trace-v3-host.test.mjs test/trace-failures-host.test.mjs test/preset-fallback-host.test.mjs test/plugin-runtime-compatibility.test.mjs
node --test test/dsh017-host-migration.test.mjs test/dsh017-client-sessions.test.mjs test/resource-capabilities.test.mjs
```
The official-module checks in these tests skip when their variables are absent; an invalid configured root fails. They use temporary data and real DSH modules. AgentLoop tests use a synthetic model adapter, do not contact a real provider, and do not validate Web Remote, browsers, or actual third-party plugins.
Separately, `DSH_TAVERN_ACCEPTANCE_FIXTURE` enables a [specific external preset fixture check](../test/acceptance-fixture.test.mjs), not a general acceptance test for arbitrary character cards. It skips when the variable is absent or the file does not exist; contents that do not meet its assertions fail. Some path checks may also skip when the platform disallows symlink/junction creation. Read the reasons reported by the runner; skipped checks are not passes.
For this compatibility boundary, additionally check all five resources through create/import/export/edit on an isolated Host; unsaved template protection on Escape and panel switching; independently retained sessions switching RP, native Chat and Trace; and recovery after temporary binding-read failures. Sampling tests exercise explicit parameter rejection, prior output, abort and authentication failure, checking bounded retries and Trace requested/effective/fallbacks. Migration covers V3 interruption insertion and child catalogs, earlier format chains, backup conflicts and reruns.
## Independent Assembler and installation boundaries
Run `node --test test/tavern-bundle.test.mjs` and `npm test` to verify that Tavern only consumes the independent service and creates no Host or standalone-client copy. Package contents and lifecycle are separate boundaries and need separate checks. Run `DSH_TAVERN_PROMPT_COMPAT_ROOT= node --test test/host-client-discovery.test.mjs` to verify that the declared Host file is anchored by the official patch loader and advertises Tavern in the official browser module graph.
Use a temporary profile outside the development checkout, retaining DSH's `nodeLinker: hoisted` and `autoInstallPeers: false`. Produce two separate tarballs with `npm run pack:release -- --assembler node_modules/dsh-prompt-assembler`. Install and enable Assembler 1.1.3 before Tavern 3.1.5. Check that Tavern declares no `bundleDependencies`, regular Assembler subdependency or nested Assembler files. Verify the development source archive and lockfile through clean `npm ci --legacy-peer-deps`; do not rely on npm version 1.1.3 being available.
Run these checks against both rc.2 and rc.3:
1. Install Tavern alone. Confirm an actionable missing-Assembler diagnostic and no private instance. Also test Assembler installed but disabled, and a running service below the required version.
2. Enable both bundles in either order and in one startup. Confirm one final Assembler runtime, one assembly API registration and one independent configuration entry. A third consumer, Tavern and independent Assembler must use the same service and strategy store.
3. Compare the actual Host service `version`, Tavern SDK resolution path and independent package version. Import success, directory presence or a successful install command does not establish service availability. A compatible SDK must not hide an incompatible running service.
4. Open both the independent assembler and Tavern editor. Save and apply strategies, checking refresh synchronization, unsaved drafts, session switching and closing. Tavern's client must not register another standalone Assembler configuration entry or overlay.
5. Disable, reenable and remove Tavern. Independent Assembler, a third consumer, saved strategies and session selections must remain; Tavern sources and provider must be released. Then disable or remove Assembler and confirm consumers stop without restoring a private copy.
6. Upgrade from 3.0.5 or a bundled candidate. Preserve default Assembler storage. Separately use custom `assemblerStorageDir` and formerly forwarded security settings to exercise the [upgrade procedure](INSTALLATION_en.md#upgrade-to-3-1-5). Reject the obsolete field before new resource writes. After moving settings to the independent component and removing the old field, retain readable strategies and selections.
In the real GUI, separately install the final Release attachment URL and a fixed Git revision. Record the entered address, profile/lock source and actual loaded versions. Reject Release webpage addresses; repository installation must not select an attachment automatically. Stop a CLI target Host before installation; GUI operations follow their own reload or restart prompts. Preserve an upgrade copy and never run removal experiments in real user profiles.
## Host and browser checks
Run `DSH_TAVERN_PROMPT_COMPAT_ROOT= node --test test/native-greeting-host.test.mjs` with the same Assembler as the candidate package. It checks both standard layouts, primary and alternate greetings, macros, the actual first request, later-turn gating, and historical Trace after restoring a session. The provider is offline.
Run `node scripts/verify-shell-titlebar-browser.mjs` to check four panel types at three UI scales across Web, different window-titlebar heights, and fullscreen transitions in Chrome. Host chrome and WCO env are independent inputs, including restoration where Host clearance remains zero while native controls have returned. The entire close button must stay below the native region. Regular browser tabs have no desktop WCO, so this substitutes the CSS env input and simulates the native control region; it does not replace Windows Electron acceptance. On desktop, test maximize, fullscreen, exit fullscreen and restore to a normal window in sequence, recording actual env heights. At each scale, use native mouse clicks to close panels, confirm DSH remains visible, and check fullscreen has no excess top clearance.
For real DOM fullscreen regression, set `TITLEBAR_FIXTURE_PATH` to export the HTML, open it in an active browser tab and click Verify actual fullscreen. It uses the Fullscreen API while keeping Host and simulated WCO heights at 40px, checking that matching `:fullscreen` places the panel top at zero. After exit, it retains a stale `data-fullscreen` marker and checks that 40px clearance returns. That marker alone does not establish actual fullscreen. The automated headless checks do not include this step, which requires a user gesture.
Use an authorized, isolated test profile, a workspace copy, and the target DSH version; see [installation](INSTALLATION_en.md). After replacing backend files in a running Host, restart it to load the new code.
This opt-in smoke only reads v2 `GET /chrome` and `GET /workspace`, checking mode and workspace information from a running Host. It does not cover writes, Remote transport, or UI lifecycle. Replace the URL with the test Host address.
```sh
DSH_TAVERN_PLAY_LIVE=1 \
DSH_TAVERN_PLAY_LIVE_URL="http://127.0.0.1:" \
node --test test/play-sessions.test.mjs
```
Select interaction checks for the affected behavior:
- **Style ownership and plugin reload:** Run `node --test test/client-style-ownership.test.mjs` to cover all 13 Host-document style installers: ownership before insertion, correction of retained legacy tags, idempotency and reconstruction after cleanup. In an isolated Host, load Tavern's native and lazy RP styles before enabling a test plugin that injects its own style. Trigger that plugin's bundle rebuild/HMR and disable it. Tavern styles must retain `data-plugin="pmp-dsh-tavern"`, with unchanged computed launcher and menu layout. Disabling Tavern must remove its styles while preserving the other plugin's style; re-enabling must restore required styles without duplicate nodes. Existing `data-plugin-css` and opening markers remain supported. Verify iframe, Shadow DOM and exported HTML styles within their respective isolation boundaries.
- **rc.1 upgrade:** Run offline migration tests separately with alpha.1, alpha.2 and rc.1 format libraries, including rejection of unverified releases. Verify rc.1 plugin installation and startup admission without a version exemption. Check long-history pagination, pending submissions, first/later swipe streaming and cancellation, plus RP/native switching and final-reply deduplication during tool preparation, execution and completion. Restart the test Host with the page and input draft retained, then confirm replies still arrive after reconnection.
- **RP and UI lifecycle:** Switch between native/RP modes, workspaces, and characters without leaking messages between sessions. Check greeting boundaries, control recovery from streaming to terminal states, and affected swipe/branch flows. Missing old logs should surface a problem without blocking healthy or new playthroughs.
- **History actions during generation:** During ordinary generation and a later-turn swipe, verify variant switching, swipe, fork, and rollback are disabled on all historical replies with a reason. Copy, display save and restore remain usable; edits appear immediately in pending RP context and survive terminal commit. Another playthrough remains usable; completion, failure and interruption restore path actions.
- **Pending swipe and cancellation:** Use a slow synthetic stream for both first-turn and later-turn swipes. Immediately after session creation, verify that RP and native Chat target the same new session and clicking the playthrough again returns there. Check that preceding context is not duplicated, new text streams in, and the native stop button works. Cancel before the first chunk and after some chunks, checking the error return action or adoption of actual persisted coordinates without losing existing variants.
- **Historical forks and pending input:** Complete two turns in a temporary Host, then append queued/steering input through the public inbox without waking the Agent. Use native fork as a control, and exercise the Tavern branch API, same-playthrough rollback, new-playthrough fork, and a non-first-turn swipe. Check actual model requests for stale input and duplicate swipe input, empty child inboxes, and preserved source queues and inherited history. Send again after a Host restart to check that canceled input stays canceled. Cleanup failure must report an explicit error before context copying or timeline commit.
- **Playthrough archive:** Archiving must hide the playthrough from the default list without exposing its members as loose or ordinary sessions; refresh and restart must preserve this state. Viewing from the archive must not restore it implicitly. Restoring must preserve numbering, names, branches, and bindings. Creating after archiving the latest empty playthrough must use the next number, and sessions shared with an active playthrough must remain visible there. Compare timelines, selections, and DSH logs before and after archiving to confirm that only the archive marker in the catalog changes.
- **Trace:** Compare the recorded configuration, world-book decisions, Loader section order, text, and sources with the official request. Read old records again after a restart; removing official logs from a test copy must make their text explicitly unavailable. Failure records still derive from official events and must not add failed assistant messages to RP. See the [Prompt API v3 contract](PROMPT_API_V3_en.md). `node --test test/mvu-trace.test.mjs` checks added/removed field comparisons from source HTTP history. `TAVERN_BROWSER_FIXTURE=./fixtures/tavern-trace-browser.js node scripts/verify-rich-text-browser.mjs` mounts the complete Trace with authored provider payloads, covering Chinese/English missing-value and unknown-before labels, real text wrappers, React boundaries and unchanged data. It reads no user state, sends no model request and does not replace full target Host acceptance.
- **Streaming interaction:** In an RP conversation with multiple rich-text history messages, open, close, and drag the launcher during generation. Each chunk must not reparse or sanitize unchanged history; expanded historical details must stay open. `node scripts/verify-rich-text-browser.mjs` mounts real React components to verify that continuous updates sanitize only changed messages, preserve style isolation, and replace terminal content. Synthetic checks do not establish acceptance of the real model streaming path.
- **Rich text and diagnostics:** Check static HTML/CSS isolation, display regexes, and script filtering. Verify the bounded MVU and optional restricted interactive-card capabilities against their current contracts; full Tavern Helper compatibility is not claimed. Check consistency across problem entry points, summary dismissal, rechecking, and recovery. Trace text must remain plain text.
For concurrent writes, uninstall, or coordinate migration, validate conflict and recovery paths on test copies; see [API](API_en.md) and the [migration guide](DSH_0.1.7_MIGRATION_en.md). Real-provider timeouts/retries, actual third-party integration, and platform differences need separate evidence; synthetic failures or another platform's results do not establish them.
Record the source revision, Node/DSH versions, enabled checks, skipped checks, and reproduction steps. Distinguish automated tests, real Host, browser, and external integration coverage. Diagnostic reports and Trace metadata can contain private identifiers and content; review and remove sensitive details before publishing a problem report.
Current DSH acceptance covers the stock Standard backend only. Legacy advanced Host suites using `installIndependentAssembler` remain historical fixtures for the frozen Assembler 1.1.0 / DSH 0.2.0-rc.2 environment. Mixing the new standard package with the old addon is unsupported. New-version checks leave core environment variables unset; skipped historical tests imply no newer compatibility commitment.
## Invalid playthrough archive and cleanup regression
Run `node --test test/play-maintenance.test.mjs test/play-cleanup.test.mjs test/play-archive.test.mjs` and `node scripts/verify-play-maintenance-browser.mjs`. Temporary workspaces cover archive of multiple diagnostic failures, including corruption, missing data, and read failures, while preserving healthy runs and drafts, CAS, and workspace identity. Cleanup separately covers strict all-reference absence, surviving branches, empty references, cancellation, case aliases, shared import context, interrupted cleanup, and restore conflicts. The Chrome fixture checks real React buttons, counts, older Hosts, and response isolation after switching or unmounting.
Set `DSH_TAVERN_PROMPT_COMPAT_ROOT` to the target official runtime and run `node --test test/maintenance-tools-host.test.mjs`. Real Cordis, tools, and Session controller check default-disabled behavior, opt-in, preview, clean, restore, remount, and disposal while native sessions remain unchanged. This uses temporary data and no real model calls.
On an isolated target Web Host, check the diagnostics entry, batch archive, the archive box after refresh, and restoration. Check the same interaction and forwarding on the desktop Host separately. Browser fixtures and official-module tests alone do not establish official desktop application acceptance. Do not manufacture missing logs or execute cleanup against real user workspaces for acceptance.
## Recorded request Trace and RP classification regression
Run `node --test test/trace-view.test.mjs test/trace-v3.test.mjs test/trace-references.test.mjs test/mvu-trace-view.test.mjs test/play-chat-model.test.mjs`. Compare latest and earlier record-ID details with every message in the original request order. Verify native coordinates, requestMessageIds and complete-system contributor IDs; keep module bodies and complete system text separately collapsed. Changed system bytes without refreshed module evidence must not receive stale attribution. Missing evidence must stay explicit; current preview and latest-only `/actual` must not fill historical requests. Opening Trace must issue no MVU reads until its section is expanded; closing or switching must release polling.
For the standard backend, set `DSH_ASSEMBLER_STOCK_ROOT` to a stock target DSH dependency root and `DSH_ASSEMBLER_MANAGER_ROOT` to an isolated Manager source checkout, then run `node --test test/request-assembly-native-host.test.mjs`. This uses real Host modules and a synthetic provider with temporary sessions, covering head/in-history updates, recorded requests, cold replay, world-book slot roles/order and unload continuation. Native runtime-context cleanup is a separate message; compare contributed message order separately while verifying the complete recorded request against the provider request. Historical advanced protocol-1 fixtures are not used for current DSH acceptance.
In an authorized Host/browser, verify all four roles, earlier requests, source-name fallbacks, module/raw disclosure and lazy MVU. For RP classification, use synthetic absent/corrupt unrelated timelines and a healthy non-root branch: the healthy RP view must load while sidebar diagnostics remain. Direct owner reads, permission and migration errors must still fail. Do not repair old logs to make classification pass. These checks do not establish native Windows, real-provider behavior or actual downstream memory-archive integration.
## Persistent operation-log regression
`node --test test/operation-contract.test.mjs test/operation-journal.test.mjs test/operation-log-client.test.mjs` uses temporary directories for whitelist enforcement, rotation limits, expired cursors, concurrent writes, second-writer refusal, process-exit recovery, partial tails, symlink refusal and logging failure isolation. `node scripts/verify-operation-logs-browser.mjs` uses real React in headless Chrome for explicit reads, text rendering, pagination, current-page export, old-Host 404, stale response isolation and degraded status; set `CHROME_PATH` to select a browser. This does not replace full Host page acceptance.
In a temporary target Host, read `GET /pmp-dsh-tavern/api/v2/operation-logs`, perform successful and failing workspace/session mutations, and compare response operationId with terminal records and error codes. Queries/exports must not log themselves or expose fixture bodies or paths. Stop and restart the Host normally; verify retained records, changed runId and plugin.stop. Use the existing diagnostics panel to view, filter, page and export. Closing, switching or changing filters must prevent old requests from replacing the new view. Degraded log storage must not block business operations; an older Host without logs must retain current-problem diagnostics.
See the [operation log contract](OPERATION_LOGS_en.md) for event semantics and upgrade rules. Contract tests also cover correlated failures for all declared mutations, resource IDs after Host creation followed by failure, branch inbox cleanup failure, creation checkpoint deduplication and mixed legacy/current records after restart. API completion only means handler return; user-message is accepted, not proof of generation completion or client receipt.
## Presentation regression
For greeting display regex, run `node --test test/play-greeting-render.test.mjs test/play-chat-regex.test.mjs test/play-export.test.mjs` and `TAVERN_BROWSER_FIXTURE=./fixtures/greeting-browser.js node scripts/verify-rich-text-browser.mjs`. Check variable folds, status panels, global/preset/character rule order and filtering, depth, alternate selection, empty-result fallback, unchanged sources, and rendered HTML versus source JSONL exports. The browser fixture covers the RP message component and the rich-text component used by the opening dock; still check native/RP switching and actual cards in the full Host.
For math, run `node --test test/play-math.test.mjs test/play-rich-text.test.mjs test/play-export.test.mjs` and `TAVERN_BROWSER_FIXTURE=./fixtures/math-browser.js node scripts/verify-rich-text-browser.mjs`. Cover all four delimiters, native MathML fraction/matrix layout, currency and escapes, emphasis/tables/details, literal HTML attributes and code, style isolation, wide-equation scrolling, streamed completion and stable history DOM, error fallback, macro isolation, malicious TeX/MathML sanitization and offline HTML export. This fixture uses the actual message component but does not replace full DSH Host acceptance. Check RP messages, greetings, display edits and native switching in the target Web/Desktop Host; verify MathML support separately for older browsers.
Run `node --test test/presentation.test.mjs test/api-fetch.test.mjs test/api-security.test.mjs` and the existing full check. With Chrome available, run both `node scripts/verify-rich-text-browser.mjs` and `TAVERN_BROWSER_FIXTURE=./fixtures/presentation-browser.js node scripts/verify-rich-text-browser.mjs`. The latter exercises live DOM updates, explicit proposal confirmation, unchanged-card state, lifecycle disposal, streaming suppression, quotas, blocked parent/network interfaces, sanitization, avatars and bubble styles.
In an isolated target Host, upload/save a user avatar, verify the root-bound default, change a single message and the whole playthrough, reload and compare another playthrough and source resource. Preview/apply/import/export a style and reject an invalid version. Use the [counter example](examples/interactive-counter.html) with scripts off/on, then check native/RP navigation, streaming, branches and desktop mutations. Test the official desktop distribution separately: an Electron harness using its unchanged forwarding module establishes protocol behavior, not complete application acceptance. Use synthetic resources/provider responses for repeatable tests; real-provider and real-card acceptance remains separate. Keep run-specific evidence under ignored `.local/`.
For the controlled input bridge, run `node --test test/card-composer.test.mjs test/card-worker-lifecycle.test.mjs`, `node scripts/verify-card-composer-browser.mjs`, and `TAVERN_COMPOSER_WIDTH=390 node scripts/verify-card-composer-browser.mjs`. The self-authored SUOT fixture covers window readiness, templates, seven buttons, real/synthetic clicks, fill-only/direct requests, preference restore, errors, close and resize. It uses a synthetic send adapter; separately validate public inputActions, durable DSH history and desktop forwarding in an isolated target Host.
For external rendering and unified settings run `node --test test/rendering-sources.test.mjs` and `TAVERN_WORKER_FIXTURE=scripts/fixtures/rendering-browser.js node scripts/verify-card-worker-browser.mjs`. Authored fixtures cover both Helper formats, unlabelled body fences, per-content approval, relative modules, blocked nested dependencies, revocation/disable, repeat rendering, cancellation during switches, read-only variable scope and unsaved settings drafts. They never download or execute unknown code and do not establish third-party framework compatibility. Check resource binding and native/RP switching in the complete Host as well.
Worker framework tests use `node scripts/verify-card-worker-browser.mjs` with `TAVERN_FRAMEWORK_VENDOR_DIR` pointing to local fixed official libraries (filenames and required SHA-256 are in the verifier). The verifier never downloads them. It uses a fresh headless browser profile and real-time CDP waits, covering React+JSX/Vue/jQuery events, state, revocation, scope remount, transitive owner authorization and budgets. Use `TAVERN_WORKER_FIXTURE=scripts/fixtures/rendering-browser.js` with the same verifier for unified-settings regression. Run `node --test test/card-worker-lifecycle.test.mjs` for constructor/transfer/timer failure cleanup. These fixtures do not establish compatibility with arbitrary private cards or peak process-memory bounds.
For variable writes use `TAVERN_WORKER_FIXTURE=scripts/fixtures/card-write-browser.js node scripts/verify-card-worker-browser.mjs`. It uses actual CDP mouse input to verify isTrusted cause, with synthetic transactions covering default denial, full-code review/separate grants, patch/replace, CAS, events, forged scope, revoke/unmount and intervals. `test/rendering-authority.test.mjs` covers Host hash/scope/expiry/revocation and route security. The real MVU source + manager durable commit chain still needs acceptance in the integrated environment.
Script-list enablement uses `node --test test/script-enablement.test.mjs` for native defaults, stable identity, persistence, reset, workspace isolation and inert normalization. `node scripts/verify-script-list-browser.mjs` runs authored synthetic code in a fresh Chrome profile to check enable/review separation, disabled runtime disposal, revocation, changed source and scope remount. On an isolated Host, also verify complete bounded source scrolling, narrow layouts, save failure, reload, appearance reset preserving script choices and Host tooltip keyboard/touch behavior.
For demand media, run `node --test test/card-images.test.mjs test/card-images-observer.test.mjs` and `TAVERN_BROWSER_TOOLS_ROOT= node scripts/verify-card-images-browser.mjs`. Independent Chrome uses 6000 self-authored URLs and synthetic raster responses to verify 6000 hidden pseudo-element URLs without requests, pseudo paint-state changes, zero import/collapsed requests, actual scrolling/mobile viewports, four-way concurrency, cache reuse, CSS image custom properties, actual six-cover aliases for a bounded large PNG with refresh/hiding cleanup, CSS assignment/cascade failures without false displayed status, placeholders, generation cancellation, unmounting, CSP and inert template sanitization. Pixel screenshots/reports default to `.local/card-images-browser/`. It does not download a real gallery. Continue with RP greetings, separate media status, native switching and the target desktop application in an isolated Host; a mobile viewport does not establish physical-device or official desktop-package acceptance.
For selected photos, run `node --test test/card-photo.test.mjs test/card-worker-lifecycle.test.mjs` and `TAVERN_BROWSER_TOOLS_ROOT= node scripts/verify-card-photo-browser.mjs`. Chrome uses temporary generated images through its native file-selection path to check trusted changes, bounded encoding/natural dimensions, the narrow VM facade, filename/path isolation, synthetic-event rejection, errors and switching/unmount cancellation. Reports go to `.local/card-photo-browser/`. Playwright in-memory file payloads dispatch synthetic events: verify their rejection instead of treating them as native user selection. Continue with real buttons/pixels and bounded storage in an isolated Host; do not use user photos as fixtures.
For card source lifecycle, run `TAVERN_BROWSER_TOOLS_ROOT= node scripts/verify-card-source-recreate-browser.mjs`. Two authored variants differ only in scripts and have identical sanitized static HTML. Desktop/mobile viewports cover direct VM and Worker paths: source changes recreate only the owned iframe/runtime, release the old Worker, start the new script with fresh state, and do not revive prior state when returning to an earlier source. Ordinary renders with identical source preserve nodes/input values; the top page, CSP/sandbox and unmount disposal remain unchanged. Reports go to `.local/card-source-after/`. On an affected older revision, explicitly set `TAVERN_EXPECT_SOURCE_STALE=1` to record the disposed-but-not-recreated counterexample in `.local/card-source-before/`; that is not the passing criterion for the fix. This check never opens the native photo chooser and cannot explain a disabled macOS Open button.
For script-panel display lifecycle, run `node --test test/card-first-visible.test.mjs test/card-worker-lifecycle.test.mjs` and `node scripts/verify-card-display-lifecycle-browser.mjs`; set `TAVERN_CHROME_PATH` for a Chromium executable. An isolated temporary browser at desktop and 390px widths covers six visible panels, initial offscreen admission, scrolling state retention, Worker/timer/variable-subscription release when hidden or leaving RP, the cached-return authoritative-read gate, playthrough/swipe scope replacement and content-sized surfaces. It uses neutral authored panels and a read-only synthetic Host, with no model sends or user sessions. Reports/pixels default to `.local/card-display-lifecycle-browser/`. This fixture does not replace actual target-Host switching and desktop-application acceptance.
For native disclosure sizing after script failure, run `node --test test/card-execution-diagnostic.test.mjs test/card-diagnostics.test.mjs` and `node scripts/verify-card-collapse-browser.mjs`. The neutral status details panel covers normal desktop/390px expand-collapse, fixed diagnostics after deliberately dropping one fixture layout reply, passive height convergence after Worker termination, a healthy sibling, source replacement with pending sizing and unmount cleanup. Reports and pixels default to `.local/card-collapse-browser/`. Deliberate reply loss proves the failure path, not why a real page lost its reply; continue actual Host diagnosis using the owning card’s fixed diagnostic rather than inferring CPU timeout from approximately 1000ms wall time.
To determine whether a view replaces the input during photo selection, first run `node --test test/card-photo-diagnostic.test.mjs` and `TAVERN_BROWSER_TOOLS_ROOT= node scripts/verify-card-photo-diagnostic-browser.mjs`. Normal `npm run build` disables diagnostics; use `node build.mjs --photo-diagnostic` only for a separately reviewed isolated build, never the default production package. A hidden `[data-dtv-photo-diagnostic]` node in the trusted parent exposes opaque object tokens for this instance's file inputs, connectivity, view reuse/replacement counts, length/equality summaries and trusted change/cancel counts. It retains at most 64 events and 16 inputs per event. It collects no HTML/CSS, URLs, file contents/metadata, writes no storage/network, and adds no guest entry point. Tokens cannot be compared across instances; disposal removes the output, which has no layout box. Reports go to `.local/card-photo-diagnostic-browser/`. CDP file chooser interception verifies host callbacks and deliberately changed snapshots, but cannot validate the macOS Open panel or its Open button. Same-instance observation and native chooser acceptance require separate work in an authorized isolated Host.
## Environment rendering cache
`node --test test/rendering-host-cache.test.mjs test/rendering-shared-cache.test.mjs test/rendering-dependencies.test.mjs test/identity-opening-bridge.test.mjs` verifies temporary-directory copies, source deduplication and version retention, global Host budgets, interrupted-write recovery, generation CAS, browser import retry/tombstones, HTTP guards and fixed-opening integrity. Set `DSH_TAVERN_COMPAT_ROOT` to the target runtime to additionally check the production route on real Cordis, remount recovery and route disposal. These checks are included in `verify:2.0`.
Browser acceptance should seed authored sources in real legacy IndexedDB, restore them through the Host client without external downloads, then copy the temporary Tavern data directory and open it at a different origin. Verify source reuse by another owner without inheriting its installed record. Finish legacy migration at the original browser/origin before copying a real environment. Images retain their existing temporary browser cache. Browser fixtures and request-token checks do not establish acceptance in the official desktop shell.