# Packed profile and client-module acceptance This page records the narrower packed/SDK fixtures and their historical limits. The later [actual Web-host acceptance](full-host-acceptance.md) separately passed the bounded synthetic HTTP/WebSocket, dual-session and process-restart scenario. Do not treat either layer as live-model or full-catalog certification. Run after `npm ci --ignore-scripts`: ```sh npm run build:plugin npm run test:packed ``` The command packs the actual npm artifact, extracts it under a unique temporary repository directory so locked peers resolve, and runs service, profile and scoped UI checks. It removes its own temporary output in `finally`. It requires Node 24.19.0, `npm` and `tar`, as provided by the Linux CI job. It neither installs a user profile nor modifies the real Harness home. No credentials, model, network calls or production data are used. A synthetic `.invalid` URL is an in-memory Request key, not an outgoing request. ## Regression fixed in alpha.2 Alpha.1’s built `lib/client.js` was ESM with a relative shared chunk. The DSH 0.2.0-rc.2 browser host consumes classic scripts that register lazy CJS factories. The official host-served/loader chain rejected alpha.1 with `Cannot use import statement outside a module`; standalone Vite tests did not exercise this boundary. Alpha.2 builds the server as ESM and the client as one self-contained CJS factory registered under `dsh-a2ui`. React remains a host singleton. Side effects stay inside the lazy factory. ## Regression fixed in alpha.3 The rc.2 `conversation.chat.node` keyed slot passes a `node` whose payload is `node.data`. The previous client expected top-level `data`, so the real slot renderer crashed reading `messages`. The client now accepts the SDK's `ChatNodeViewProps<'a2ui-document'>` rather than an invented props shape. The new fixture fails against the previous artifact and passes with this fix. ## What the checks actually establish - Packed server entry mounts through real Cordis 4.0.5 / DSH ToolRuntime rc.2; canonical output metadata is frozen, invalid and pre-dispatch cancelled calls have no successful metadata, unload removes the tool and remount works. - A synthetic profile places the extracted package with a local symlink, then uses real `reconcileProfilePlugins`, `loadProfileDirectory` and `boot`. Bundle auto-activation and the actual plugin’s ACTIVE state are asserted, without compatibility exemptions or a substitute registry. - The actual `ClientModuleRegistry` discovers the installed package and serves its artifact. Official `bootInjections` builds the queue; the real rc.2 browser module system runs in jsdom’s outside-only VM. Prefetch must remain lazy; import must expose the client plugin; `/client` reimport must reuse exports; recorded require edges must be only React baseline modules. - The extracted client runs in the actual rc.2 SlotRegistry/React renderer, UiSession adapter, ClientSessions, UiConversation event assembler and ConversationController. Synthetic tool-call/result events produce the slot node. Two retained sessions render the same independent example; a click in B reaches B's `Session.prompt`, while a rejected A send shows A's error only and is not retried. The transport records the untrusted-data action envelope. - This UI fixture uses a minimal synthetic root and chat target projection, captured official browser factories and a synthetic remote transport. Unused composer primitives are a fail-closed sentinel, not simulated UI services. The separate profile fixture tests the official module loader. Neither fixture claims the full chat/composer app, CSS layout or an actual server/model. Observed 2026-10-23: old alpha.1 artifact fails this real loader path; corrected artifact passes. The same checks are now part of the existing CI acceptance job. The server-only proof originally landed at `f5d01c6`; this expands its boundary. ## Durable tool-result acceptance `test:packed` also executes the packed server against the official rc.2 JSONL backend with `compression: none` and synthetic data. Each of two sessions uses a complete v4 turn/step/assistant-tool-call lifecycle, real ToolRuntime success and failure, and `SessionStore.flush`. After closing writers and disposing the first Context, a fresh backend reads the disk files; official `Session.fromRestore` retains the canonical A2UI metadata and assistant/tool history. Failed calls have no successful metadata and A/B surface IDs remain distinct. The assistant tool-call messages are synthetic, not model responses. This checks plaintext durable tool-result metadata, not persistence of edited browser fields, full chat replay, process crash recovery, cross-process restart or default Zstd. ## Still unverified The automated profile fixture uses synthetic package placement. Separately, the official DSH 0.2.0-rc.2 CLI and pnpm 11.25.0 installed the alpha.3 tarball into an empty isolated profile on 2026-10-23. Dependency and bundle registration, `plugin list`, package bytes and lock integrity were checked independently. Scripts remained disabled, and no compatibility exemption was added. All eight host peers were absent in that empty profile, so successful installation is not full host activation. jsdom is not a browser-rendered DSH shell. Complete DSH shell/composer activation, live-model/real-transport streaming and click-to-model turns, persisted browser edits and full UI replay, full host cancellation and production deployment remain separate acceptance requirements. Do not infer user adoption, full protocol coverage or revenue. ## Regression fixed in alpha.4 A rejected action previously replaced the entire host form with an error, leaving the user unable to inspect or resubmit their edited values. The packed, official two-session UI fixture reproduces that failure on alpha.3. Alpha.4 displays the delivery status inside the existing surface instead: edited values remain available, no automatic retry occurs, and a deliberate second click routes the retained value only to the owning session. A confirmed subsequent send clears the error; the other session is unchanged. This is in-memory recovery after a rejected send, not durable draft storage. Unconfirmed delivery can be ambiguous: users should check the conversation before sending again. The fixture uses a synthetic remote rejection and acceptance, not a live model or network-failure guarantee. ## Model ownership fixed in alpha.5 The official renderer stores data-model values by reference. Passing host message objects directly to it allowed form edits to rewrite the canonical host projection, and two surfaces given the same input could share mutable state. Later model updates within one batch could also rewrite an earlier history entry before it was recorded. Alpha.5 takes independent copies for authored history and renderer state before processing the batch. The packed official-slot test now asserts that editing a field leaves the host node messages unchanged. Renderer tests cover shared-input session isolation, caller mutation after append, ordered authored updates versus final snapshots, and unchanged imported recordings after editing the restored surface. No localStorage, IndexedDB, network draft write, or automatic action replay is introduced. This fixes ownership, not draft survival across node reconstruction or browser reload. ## Same-node resync boundary in alpha.6 DSH may rebuild a canonical conversation node from the same event window during resync. Fresh array identity alone is not a new document. Alpha.6 keys the mounted surface session by the serialized canonical message content, node identity, and preview/error state, rather than the message-array reference. This retains its edited fields, action budget, and delivery status for identical documents without replaying an action. The official injected transport remains scoped to the session binding. Changed canonical content, a different node, lifecycle/error changes, or component teardown invalidate this in-memory ownership. No localStorage, IndexedDB, global cache, or backend draft write exists. A page reload or a new session generation does not restore unsent edits. Object-key reordering that changes the serialized document is conservatively treated as a changed document. This does not claim full-shell/model or durable submitted-state replay. The reactive packed fixture subscribes to the official conversation target and drives `eventSource.replace`, rather than manually rerendering a test root. Five cases cover retained unsent text, retained rejected-delivery status, an exhausted action budget, replacement by a genuinely changed document (including the next explicit action payload), and actual renderer unmount/remount. Equal replay keeps the same slot DOM and binding while receiving fresh canonical node objects. No resync sends an action, and the other session stays isolated. Cross-generation remote transport and a complete DSH browser shell remain outside this fixture. ## Scripted model loop with actual tool and UI events The [no-key walkthrough](synthetic-loop.md) now runs against the extracted packed artifact as part of `test:packed`. Unlike the earlier hand-authored lifecycle fixtures, the official AgentLoop creates these tool calls and results. The actual form action reaches a second agent turn with the edited topic, and that turn produces another validated A2UI surface. Assertions require two completed turns, four provider calls, two real tool results and exactly one explicit UI action. Only the model provider and transport bridge are scripted; the root/target and jsdom remain minimal fixtures. This adds an executable model-loop contract, not live-model access, transient streaming preview, full shell/composer, server SessionController/HTTP, persistence, cancellation or production certification. ## Streamed cancellation fixed in alpha.7 The earlier model-loop example forwards only durable events. It therefore misses an important user flow: cancelling while a partial form is already visible, before any `render_a2ui` tool result exists. Alpha.6 returned `null` after the official client retired that attempt's transient start. The actual conversation assembler rejected the withdrawal of an already-materialized node, and its stale preview remained visible. Alpha.7 follows the SDK's same-key hidden-node contract and clears the retired A2UI messages and running state while preserving node identity and position. No action is sent and no cancelled payload is retained in that node. `test:packed` now runs `scripts/verify-packed-stream.mjs` in success and cancellation modes against the extracted tarball. `npm run test:stream` runs the same checks against a built checkout. Real `SessionQueryEngine` live observations feed the pinned `SessionHistoryController.follow` implementation, then official `RemoteStream`, `SessionEventStream`, `ClientAssistantStream`, conversation assembly and the renderer. Neither durable events nor assistant frames are hand-authored. The history implementation class is loaded from its installed SDK file because it is not a public package export; the fixture asserts the exact rc.2 version. The success flow pauses the scripted provider before tool completion, observes a visible inert form, attempts a blocked preview click, allows the real tool to settle, edits the form, performs an actual `Session.resync`, then submits exactly one action into the next real agent turn. The cancelled flow confirms hidden same-key state with an empty payload, zero tool results/actions, an actual history resync, full client-binding teardown/reopen, and a second cancellation without a ghost form or swallowed projection error. Detached controls cannot act; the old preview projection is unchanged; a later valid form and explicit action still complete normally after both cancellations. A `BYPASS_STREAM=1` negative control must fail before a transient preview appears; durable-only forwarding cannot pass. The model, physical carrier and prompt/cancel admission remain synthetic/in-process. The root/chat target is minimal and the DOM is jsdom. The full server SessionController, HTTP/WebSocket, full browser shell, model credentials, network failure/retry behavior, network connection generation changes, cancellation during/after tool execution and full-host cancellation are not certified. This check adds no browser storage, backend drafts or automatic action replay.